產生來源檔案
有時候,來源檔案在傳遞給實際編譯器之前需要先進行預處理。舉例來說,您可能想要建置一個 IDL 編譯器,然後執行一些檔案來產生實際的來源檔案。在 Meson 中,這是透過 generator()
或 custom_target()
來完成的。
使用 custom_target()
假設您有一個建置目標必須使用編譯器產生的來源檔案來建置。編譯器可以是已建置的目標
mycomp = executable('mycompiler', 'compiler.c')
或是由系統提供的外部程式,或來源樹內的腳本
mycomp = find_program('mycompiler')
自訂目標可以接受零個或多個輸入檔案,並使用它們產生一個或多個輸出檔案。透過使用自訂目標,您可以在建置時執行此編譯器來產生來源檔案
gen_src = custom_target('gen-output',
input : ['somefile1.c', 'file2.c'],
output : ['out.c', 'out.h'],
command : [mycomp, '@INPUT@',
'--c-out', '@OUTPUT0@',
'--h-out', '@OUTPUT1@'])
那裡的 @INPUT@
會被轉換為 'somefile1.c' 'file2.c'
。就像輸出一樣,您也可以透過索引個別參照每個輸入檔案。
然後您只需將其放入您的程式中,就完成了。
產生標頭檔
將產生的標頭檔新增到來源清單中,將確保產生標頭檔,並為目標建立正確的包含路徑
prog_python = find_program('python3')
foo_c = custom_target(
'foo.c',
output : 'foo.c',
input : 'my_gen.py',
command : [prog_python, '@INPUT@', '--code', '@OUTPUT@'],
)
foo_h = custom_target(
'foo.h',
output : 'foo.h',
input : 'my_gen.py',
command : [prog_python, '@INPUT@', '--header', '@OUTPUT@'],
)
libfoo = static_library('foo', [foo_c, foo_h])
executable('myexe', ['main.c', foo_h], link_with : libfoo)
每個依賴產生標頭檔的目標都應該將該標頭檔新增到其來源中,如上面 libfoo
和 myexe
所見。這是因為 Meson 或後端無法知道 myexe
依賴 foo.h
,僅僅因為 libfoo
依賴它,它可能是一個私有的標頭檔。
一次產生多個檔案
有時,單一產生器一次建立兩個或多個檔案(也許是一個標頭檔和來源檔)是有意義的,Meson 也涵蓋了這種情況。可以像列表一樣索引 custom_target
,以分別取得每個輸出檔案。順序與 custom_target
的輸出引數順序相同
prog_python = find_program('python3')
foo_ch = custom_target(
'foo.[ch]',
output : ['foo.c', 'foo.h'],
input : 'my_gen.py',
command : [prog_python, '@INPUT@', '@OUTPUT@'],
)
libfoo = static_library('foo', [foo_ch])
executable('myexe', ['main.c', foo_ch[1]], link_with : libfoo)
在這種情況下,libfoo
依賴 foo.c
和 foo.h
,但 myexe
僅依賴 foo.h
,即第二個輸出。
使用相依性來管理產生的資源
在某些情況下,使用 declare_dependency
來「捆綁」標頭檔和函式庫相依性可能會更容易,特別是當有很多產生的標頭檔時
idep_foo = declare_dependency(
sources : [foo_h, bar_h],
link_with : [libfoo],
)
如需更多資訊,請參閱相依性和declare_dependency()
。
使用 generator()
產生器類似於自訂目標,只是我們定義一個產生器,它定義如何將輸入檔案轉換為一個或多個輸出檔案,然後在我們想要的任意多個輸入檔案上使用它。
請注意,產生器僅應在將僅用作建置目標或自訂目標輸入的輸出上使用。當您在多個目標中使用產生器的處理輸出時,產生器將執行多次,以為每個目標建立輸出。每個輸出都將在目標私有的 @BUILD_DIR@
目錄中建立。
如果您想要產生用於一般用途的檔案,例如產生多個來源使用的標頭檔,或將要安裝的資料等等,請改用 custom_target()
。
gen = generator(mycomp,
output : '@BASENAME@.c',
arguments : ['@INPUT@', '@OUTPUT@'])
第一個引數是要執行的執行檔。下一個檔案指定名稱產生規則。它指定如何為給定的輸入名稱建置輸出檔案名稱。@BASENAME@
是輸入檔案名稱的佔位符,不帶前導路徑或後綴(如果有的話)。因此,如果輸入檔案名稱為 some/path/filename.idl
,則輸出名稱將為 filename.c
。您也可以使用 @PLAINNAME@
,它會保留後綴,這將產生一個名為 filename.idl.c
的檔案。最後一行指定要傳遞給執行檔的命令列引數。@INPUT@
和 @OUTPUT@
分別是輸入和輸出檔案的佔位符,Meson 會自動填入。如果您的規則產生多個輸出檔案,並且您需要將它們傳遞給命令列,請將位置附加到輸出持有者,例如:@OUTPUT0@
、@OUTPUT1@
等。
指定此規則後,我們可以產生來源檔案並將其新增到目標中。
gen_src = gen.process('input1.idl', 'input2.idl')
executable('program', 'main.c', gen_src)
產生器還可以產生具有未知名稱的多個輸出檔案
gen2 = generator(someprog,
output : ['@BASENAME@.c', '@BASENAME@.h'],
arguments : ['--out_dir=@BUILD_DIR@', '@INPUT@'])
在這種情況下,您不能使用普通的 @OUTPUT@
變數,因為它會造成歧義。此程式只需要知道輸出目錄,它會自行產生檔案名稱。
為了使每次使用時都可以將不同的額外引數傳遞給產生器程式,您可以在 arguments
清單中使用 @EXTRA_ARGS@
字串。請注意,此佔位符只能作為一個完整的字串存在,而不能作為子字串。主要原因是它代表一個字串列表,該列表可能為空,或包含多個元素;並且在任何一種情況下,將其插入到單個字串的中間都是有問題的。如果沒有從 process()
呼叫中傳遞任何額外引數,則會從實際引數清單中完全省略該佔位符,因此不會因此將空字串傳遞給產生器程式。如果 extra_args
中有多個元素,則它們會作為單獨的元素插入到實際引數清單中。
gen3 = generator(genprog,
output : '@BASENAME@.cc',
arguments : ['@INPUT@', '@EXTRA_ARGS@', '@OUTPUT@'])
gen3_src1 = gen3.process('input1.y')
gen3_src2 = gen3.process('input2.y', extra_args: '--foo')
gen3_src3 = gen3.process('input3.y', extra_args: ['--foo', '--bar'])
搜尋結果是