Generieren von Quellen

Manchmal müssen Quelldateien vorverarbeitet werden, bevor sie an den eigentlichen Compiler übergeben werden. Als Beispiel könnten Sie einen IDL-Compiler erstellen und dann einige Dateien damit durchlaufen lassen, um tatsächliche Quelldateien zu generieren. In Meson wird dies mit generator() oder custom_target() erledigt.

Verwendung von custom_target()

Nehmen wir an, Sie haben ein Build-Ziel, das mit Quellen erstellt werden muss, die von einem Compiler generiert wurden. Der Compiler kann entweder ein gebautes Ziel sein

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

Oder ein externes Programm, das vom System bereitgestellt wird, oder ein Skript innerhalb des Quellbaums

mycomp = find_program('mycompiler')

Benutzerdefinierte Ziele können null oder mehr Eingabedateien aufnehmen und diese zur Generierung einer oder mehrerer Ausgabedateien verwenden. Mit einem benutzerdefinierten Ziel können Sie diesen Compiler zur Build-Zeit ausführen, um die Quellen zu generieren

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@ wird dort in 'somefile1.c' 'file2.c' umgewandelt. Genau wie die Ausgabe können Sie auch auf jede Eingabedatei einzeln nach Index verweisen.

Dann fügen Sie das einfach in Ihr Programm ein und sind fertig.

Generieren von Headern

Das Hinzufügen eines generierten Headers zu einer Quellliste stellt sicher, dass der Header generiert wird und dass die richtigen Include-Pfade für das Ziel erstellt werden

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)

Jedes Ziel, das von einem generierten Header abhängt, sollte diesen Header zu seinen Quellen hinzufügen, wie oben bei libfoo und myexe gesehen. Dies liegt daran, dass Meson oder das Backend nicht wissen können, dass myexe von foo.h abhängt, nur weil libfoo dies tut, es könnte ein privater Header sein.

Generieren mehrerer Dateien auf einmal

Manchmal ist es sinnvoll, dass ein einzelner Generator zwei oder mehr Dateien gleichzeitig erstellt (vielleicht eine Header- und eine Quelldatei). Meson deckt auch diesen Fall ab. custom_targets können wie eine Liste indiziert werden, um jede Ausgabedatei separat zu erhalten. Die Reihenfolge ist die gleiche wie die Reihenfolge des Ausgabearguments für 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)

In diesem Fall hängt libfoo sowohl von foo.c als auch von foo.h ab, aber myexe hängt nur von foo.h ab, der zweiten Ausgabe.

Verwendung von Abhängigkeiten zur Verwaltung generierter Ressourcen

In einigen Fällen kann es einfacher sein, declare_dependency zu verwenden, um die Header- und Bibliotheksabhängigkeit zu "bündeln", insbesondere wenn es viele generierte Header gibt

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

Weitere Informationen finden Sie unter dependencies und declare_dependency().

Verwendung von generator()

Generatoren ähneln benutzerdefinierten Zielen, mit dem Unterschied, dass wir einen Generator definieren, der festlegt, wie eine Eingabedatei in eine oder mehrere Ausgabedateien transformiert wird, und diesen dann auf so viele Eingabedateien anwenden, wie wir möchten.

Beachten Sie, dass Generatoren nur für Ausgaben verwendet werden sollten, die nur als Eingaben für ein Build-Ziel oder ein benutzerdefiniertes Ziel verwendet werden. Wenn Sie die verarbeitete Ausgabe eines Generators in mehreren Zielen verwenden, wird der Generator mehrmals ausgeführt, um Ausgaben für jedes Ziel zu erstellen. Jede Ausgabe wird in einem zielprivaten Verzeichnis @BUILD_DIR@ erstellt.

Wenn Sie Dateien für allgemeine Zwecke generieren möchten, z. B. zum Generieren von Headern, die von mehreren Quellen verwendet werden sollen, oder von zu installierenden Daten und so weiter, verwenden Sie stattdessen ein custom_target().

gen = generator(mycomp,
                output  : '@BASENAME@.c',
                arguments : ['@INPUT@', '@OUTPUT@'])

Das erste Argument ist die ausführbare Datei, die ausgeführt werden soll. Die nächste Datei gibt eine Namensgenerierungsregel an. Sie gibt an, wie der Ausgabedateinamen für einen gegebenen Eingabenamen erstellt wird. @BASENAME@ ist ein Platzhalter für den Namen der Eingabedatei ohne vorhergehenden Pfad oder Suffix (falls vorhanden). Wenn der Name der Eingabedatei some/path/filename.idl wäre, dann wäre der Name der Ausgabe filename.c. Sie können auch @PLAINNAME@ verwenden, das das Suffix beibehält, was zu einer Datei namens filename.idl.c führen würde. Die letzte Zeile gibt die Befehlszeilenargumente an, die an die ausführbare Datei übergeben werden sollen. @INPUT@ und @OUTPUT@ sind Platzhalter für die Ein- und Ausgabedateien und werden automatisch von Meson ausgefüllt. Wenn Ihre Regel mehrere Ausgabedateien produziert und Sie diese an die Befehlszeile übergeben müssen, fügen Sie den Speicherort zum Ausgabebereich hinzu, wie folgt: @OUTPUT0@, @OUTPUT1@ und so weiter.

Mit dieser angegebenen Regel können wir Quelldateien generieren und sie zu einem Ziel hinzufügen.

gen_src = gen.process('input1.idl', 'input2.idl')
executable('program', 'main.c', gen_src)

Generatoren können auch mehrere Ausgabedateien mit unbekannten Namen generieren

gen2 = generator(someprog,
                 output : ['@BASENAME@.c', '@BASENAME@.h'],
                 arguments : ['--out_dir=@BUILD_DIR@', '@INPUT@'])

In diesem Fall können Sie nicht die einfache @OUTPUT@-Variable verwenden, da dies mehrdeutig wäre. Dieses Programm muss nur das Ausgabeverzeichnis kennen, es wird die Dateinamen selbst generieren.

Um verschiedene zusätzliche Argumente an das Generatorprogramm bei jeder Verwendung übergeben zu können, können Sie den String @EXTRA_ARGS@ in der arguments-Liste verwenden. Beachten Sie, dass dieser Platzhalter nur als ganzer String vorhanden sein kann und nicht als Teilstring. Der Hauptgrund ist, dass er eine Liste von Strings repräsentiert, die leer sein kann oder mehrere Elemente enthalten kann; und in beiden Fällen wäre die Interpolation mitten in einem einzelnen String problematisch. Wenn keine zusätzlichen Argumente aus einer process()-Aufrufung übergeben werden, wird der Platzhalter vollständig aus der tatsächlichen Argumentliste weggelassen, sodass keine leere Zeichenfolge wegen dieser an das Generatorprogramm übergeben wird. Wenn es mehrere Elemente in extra_args gibt, werden diese als separate Elemente in die tatsächliche Argumentliste eingefügt.

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'])

Die Ergebnisse der Suche sind