| --- |
| 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#declare_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']) |
| ``` |