The Meson Build System
http://mesonbuild.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
7.1 KiB
202 lines
7.1 KiB
--- |
|
short-description: Generation of source files before compilation |
|
... |
|
|
|
# Generating sources |
|
|
|
Sometimes source files need to be preprocessed before they are passed |
|
to the actual compiler. As an example you might want build an IDL |
|
compiler and then run some files through that to generate actual |
|
source files. In Meson this is done with |
|
[`generator()`](Reference-manual.md#generator) or |
|
[`custom_target()`](Reference-manual.md#custom_target). |
|
|
|
## Using custom_target() |
|
|
|
Let's say you have a build target that must be built using sources |
|
generated by a compiler. The compiler can either be a built target: |
|
|
|
```meson |
|
mycomp = executable('mycompiler', 'compiler.c') |
|
``` |
|
|
|
Or an external program provided by the system, or script inside the |
|
source tree: |
|
|
|
```meson |
|
mycomp = find_program('mycompiler') |
|
``` |
|
|
|
Custom targets can take zero or more input files and use them to |
|
generate one or more output files. Using a custom target, you can run |
|
this compiler at build time to generate the sources: |
|
|
|
```meson |
|
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@']) |
|
``` |
|
|
|
The `@INPUT@` there will be transformed to `'somefile1.c' |
|
'file2.c'`. Just like the output, you can also refer to each input |
|
file individually by index. |
|
|
|
Then you just put that in your program and you're done. |
|
|
|
### Generating headers |
|
|
|
Adding a generated header to a source list will ensure that the header is |
|
generated and that the proper include paths are created for the target: |
|
|
|
```meson |
|
prog_python = import('python').find_installation('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) |
|
``` |
|
|
|
Each target that depends on a generated header should add that header to it's sources, |
|
as seen above with `libfoo` and `myexe`. This is because there is no way for |
|
meson or the backend to know that `myexe` depends on `foo.h` just because |
|
`libfoo` does, it could be a private header. |
|
|
|
### Generating multiple files at a time |
|
|
|
Sometimes it makes sense for a single generator to create two or more files at |
|
a time, (perhaps a header and source file), meson has this case covered as |
|
well. `custom_target`s can be indexed like a list to get each output file |
|
separately. The order is the same as the order of the output argument to |
|
`custom_target` |
|
|
|
```meson |
|
prog_python = import('python').find_installation('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 this case `libfoo` depends on both `foo.c` and `foo.h` but `myexe` only |
|
depends on `foo.h`, the second output. |
|
|
|
### Using dependencies to manage generated resources |
|
|
|
In some cases it might be easier to use `declare_dependency` to "bundle" the header |
|
and library dependency, especially if there are many generated headers: |
|
|
|
```meson |
|
idep_foo = declare_dependency( |
|
sources : [foo_h, bar_h], |
|
link_with : [libfoo], |
|
) |
|
``` |
|
|
|
See [dependencies](Dependencies.md#declaring-your-own), and |
|
[reference](Reference-manual.md#decalre_dependency) for more information. |
|
|
|
## Using generator() |
|
|
|
Generators are similar to custom targets, except that we define a |
|
*generator*, which defines how to transform an input file into one or |
|
more output files, and then use that on as many input files as we |
|
want. |
|
|
|
Note that generators should only be used for outputs that will only be |
|
used as inputs for a build target or a custom target. When you use the |
|
processed output of a generator in multiple targets, the generator |
|
will be run multiple times to create outputs for each target. Each |
|
output will be created in a target-private directory `@BUILD_DIR@`. |
|
|
|
If you want to generate files for general purposes such as for |
|
generating headers to be used by several sources, or data that will be |
|
installed, and so on, use a |
|
[`custom_target()`](Reference-manual.md#custom_target) instead. |
|
|
|
|
|
```meson |
|
gen = generator(mycomp, |
|
output : '@BASENAME@.c', |
|
arguments : ['@INPUT@', '@OUTPUT@']) |
|
``` |
|
|
|
The first argument is the executable file to run. The next file |
|
specifies a name generation rule. It specifies how to build the output |
|
file name for a given input name. `@BASENAME@` is a placeholder for |
|
the input file name without preceding path or suffix (if any). So if |
|
the input file name were `some/path/filename.idl`, then the output |
|
name would be `filename.c`. You can also use `@PLAINNAME@`, which |
|
preserves the suffix which would result in a file called |
|
`filename.idl.c`. The last line specifies the command line arguments |
|
to pass to the executable. `@INPUT@` and `@OUTPUT@` are placeholders |
|
for the input and output files, respectively, and will be |
|
automatically filled in by Meson. If your rule produces multiple |
|
output files and you need to pass them to the command line, append the |
|
location to the output holder like this: `@OUTPUT0@`, `@OUTPUT1@` and |
|
so on. |
|
|
|
With this rule specified we can generate source files and add them to |
|
a target. |
|
|
|
```meson |
|
gen_src = gen.process('input1.idl', 'input2.idl') |
|
executable('program', 'main.c', gen_src) |
|
``` |
|
|
|
Generators can also generate multiple output files with unknown names: |
|
|
|
```meson |
|
gen2 = generator(someprog, |
|
output : ['@BASENAME@.c', '@BASENAME@.h'], |
|
arguments : ['--out_dir=@BUILD_DIR@', '@INPUT@']) |
|
``` |
|
|
|
In this case you can not use the plain `@OUTPUT@` variable, as it |
|
would be ambiguous. This program only needs to know the output |
|
directory, it will generate the file names by itself. |
|
|
|
To make passing different additional arguments to the generator |
|
program at each use possible, you can use the `@EXTRA_ARGS@` string in |
|
the `arguments` list. Note that this placeholder can only be present |
|
as a whole string, and not as a substring. The main reason is that it |
|
represents a list of strings, which may be empty, or contain multiple |
|
elements; and in either case, interpolating it into the middle of a |
|
single string would be troublesome. If there are no extra arguments |
|
passed in from a `process()` invocation, the placeholder is entirely |
|
omitted from the actual list of arguments, so an empty string won't be |
|
passed to the generator program because of this. If there are multiple |
|
elements in `extra_args`, they are inserted into to the actual |
|
argument list as separate elements. |
|
|
|
```meson |
|
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']) |
|
```
|
|
|