ソース生成

ソースファイルは、実際のコンパイラに渡す前に前処理が必要な場合があります。例として、IDLコンパイラを構築し、それを使用していくつかのファイルを処理して実際のソースファイルを生成したい場合があります。Mesonでは、これはgenerator()またはcustom_target()を使用して行われます。

custom_target()の使用

コンパイラによって生成されたソースを使用して構築する必要があるビルドターゲットがあるとします。コンパイラは、ビルドされたターゲットでも構いません

mycomp = executable('mycompiler', 'compiler.c')

または、システムによって提供される外部プログラム、またはソースツリー内のスクリプトでも構いません

mycomp = find_program('mycompiler')

カスタムターゲットは、ゼロ個以上の入力ファイルを受け取り、それらを使用して1つ以上の出力ファイルを生成できます。カスタムターゲットを使用すると、このコンパイラをビルド時に実行してソースを生成できます

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で示されているように、そのヘッダーをソースに追加する必要があります。これは、libfooが依存しているからといって、myexefoo.hに依存していることをMesonやバックエンドが知る方法がないためです。プライベートヘッダーである可能性もあります。

一度に複数のファイルを生成する

単一のジェネレーターが一度に2つ以上のファイル(おそらくヘッダーファイルとソースファイル)を作成するのが理にかなっている場合があります。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)

この場合、libfoofoo.cfoo.hの両方に依存しますが、myexeは2番目の出力であるfoo.hのみに依存します。

依存関係を使用して生成されたリソースを管理する

特に生成されたヘッダーが多い場合は、declare_dependencyを使用してヘッダーとライブラリの依存関係を「バンドル」する方が簡単な場合があります

idep_foo = declare_dependency(
    sources : [foo_h, bar_h],
    link_with : [libfoo],
)

詳細については、依存関係declare_dependency()を参照してください。

generator()の使用

ジェネレーターはカスタムターゲットに似ていますが、入力ファイルを1つ以上の出力ファイルに変換する方法を定義するジェネレーターを定義し、それを必要な数の入力ファイルで使用するという点が異なります。

ジェネレーターは、ビルドターゲットまたはカスタムターゲットの入力としてのみ使用される出力にのみ使用する必要があることに注意してください。ジェネレーターの処理済み出力を複数のターゲットで使用する場合、ジェネレーターは各ターゲットの出力を生成するために複数回実行されます。各出力は、ターゲットプライベートディレクトリ@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'])

検索結果は次のとおりです