| --- | |
| 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]] or | |
| [[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 = [[#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) | |
| ``` | |
| Each target that depends on a generated header should add that header | |
| to its 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 = [[#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 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 | |
| [[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]] 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 cannot 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']) | |
| ``` |