aboutsummaryrefslogtreecommitdiffstats
path: root/meson/docs/markdown/Generating-sources.md
diff options
context:
space:
mode:
Diffstat (limited to 'meson/docs/markdown/Generating-sources.md')
-rw-r--r--meson/docs/markdown/Generating-sources.md206
1 files changed, 206 insertions, 0 deletions
diff --git a/meson/docs/markdown/Generating-sources.md b/meson/docs/markdown/Generating-sources.md
new file mode 100644
index 000000000..c09819f60
--- /dev/null
+++ b/meson/docs/markdown/Generating-sources.md
@@ -0,0 +1,206 @@
+---
+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'])
+```