diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2019-03-06 14:41:00 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2019-05-22 12:09:09 +0200 |
commit | d894c48660a573f257f76fe075e512415fdd0f91 (patch) | |
tree | b077999723cc6724c4ab141334af0cb00577ba91 /test cases | |
parent | e9bd7d49bdc8c630cca3bf4cc02c437841b6aaf6 (diff) | |
download | meson-d894c48660a573f257f76fe075e512415fdd0f91.zip meson-d894c48660a573f257f76fe075e512415fdd0f91.tar.gz meson-d894c48660a573f257f76fe075e512415fdd0f91.tar.bz2 |
new module "sourceset" to match source file lists against configuration data
In QEMU a single set of source files is built against many different
configurations in order to generate many executable. Each executable
includes a different but overlapping subset of the source files; some
of the files are compiled separately for each output, others are
compiled just once.
Using Makefiles, this is achieved with a complicated mechanism involving
a combination of non-recursive and recursive make; Meson can do better,
but because there are hundreds of such conditional rules, it's important
to keep meson.build files brief and easy to follow. Therefore, this
commit adds a new module to satisfy this use case while preserving
Meson's declarative nature.
Configurations are mapped to a configuration_data object, and a new
"source set" object is used to store all the rules, and then retrieve
the desired set of sources together with their dependencies.
The test case shows how extract_objects can be used to satisfy both
cases, i.e. when the object files are shared across targets and when
they have to be separate. In the real-world case, a project would use
two source set objects for the two cases and then do
"executable(..., sources: ... , objects: ...)". The next commit
adds such an example.
Diffstat (limited to 'test cases')
22 files changed, 248 insertions, 0 deletions
diff --git a/test cases/common/220 source set configuration_data/a.c b/test cases/common/220 source set configuration_data/a.c new file mode 100644 index 0000000..0570dff --- /dev/null +++ b/test cases/common/220 source set configuration_data/a.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include "all.h" + +int main(void) +{ + if (p) abort(); + f(); +} diff --git a/test cases/common/220 source set configuration_data/all.h b/test cases/common/220 source set configuration_data/all.h new file mode 100644 index 0000000..728a7f6 --- /dev/null +++ b/test cases/common/220 source set configuration_data/all.h @@ -0,0 +1,7 @@ +extern void f(void); +extern void g(void); +extern void h(void); +extern void undefined(void); + +/* No extern here to get a common symbol */ +void (*p)(void); diff --git a/test cases/common/220 source set configuration_data/f.c b/test cases/common/220 source set configuration_data/f.c new file mode 100644 index 0000000..a50ecda --- /dev/null +++ b/test cases/common/220 source set configuration_data/f.c @@ -0,0 +1,5 @@ +#include "all.h" + +void f(void) +{ +} diff --git a/test cases/common/220 source set configuration_data/g.c b/test cases/common/220 source set configuration_data/g.c new file mode 100644 index 0000000..4a6f253 --- /dev/null +++ b/test cases/common/220 source set configuration_data/g.c @@ -0,0 +1,6 @@ +#include "all.h" + +void g(void) +{ + h(); +} diff --git a/test cases/common/220 source set configuration_data/meson.build b/test cases/common/220 source set configuration_data/meson.build new file mode 100644 index 0000000..104f39d --- /dev/null +++ b/test cases/common/220 source set configuration_data/meson.build @@ -0,0 +1,54 @@ +project('a', 'c') + +good = declare_dependency(link_with: static_library('good', 'g.c')) +bad = declare_dependency(link_args: 'nonexistent.a') +not_found = dependency('invalid', required: false) + +source_set = import('sourceset') + +sources = source_set.source_set() +sources.add(when: 'YES', if_false: ['nope.c']) +sources.add(when: 'YES1', if_true: files('a.c')) +subdir('subdir') +sources.add(when: 'NO', if_true: 'nope.c', if_false: ['f.c']) +sources.add(when: 'NO', if_true: bad, if_false: ['f.c']) + +sources.add(when: 'YES2', if_true: good) + +# dependencies as conditions +sources.add(when: not_found, if_true: 'nope.c') + +# test add_all +sources2 = source_set.source_set() +sources2.add(when: 'YES1', if_true: 'nope.c') +sources.add_all(when: 'NO', if_true: sources2) + +# test duplicate items +sources.add(when: 'YES1', if_true: files('a.c')) + +conf1 = configuration_data() +conf1.set10('YES', true) +conf1.set10('YES1', true) +conf1.set10('YES2', false) +conf1.set10('NO', false) +result1 = sources.apply(conf1) + +conf2 = configuration_data() +conf2.set10('YES', true) +conf2.set10('YES1', false) +conf2.set10('YES2', true) +conf2.set10('NO', false) +result2 = sources.apply(conf2) + +# Each target will recompile the objects +executable('first', sources: result1.sources(), dependencies: result1.dependencies()) +executable('second', sources: result2.sources(), dependencies: result2.dependencies()) + +# All target will use the same object files +if meson.is_unity() + message('Skipping extraction test because this is a Unity build.') +else + all_objs = static_library('all_objs', sources.all_sources()) + executable('first_via_lib', objects: all_objs.extract_objects(result1.sources()), dependencies: result1.dependencies()) + executable('second_via_lib', objects: all_objs.extract_objects(result2.sources()), dependencies: result2.dependencies()) +endif diff --git a/test cases/common/220 source set configuration_data/nope.c b/test cases/common/220 source set configuration_data/nope.c new file mode 100644 index 0000000..0ce1d3b --- /dev/null +++ b/test cases/common/220 source set configuration_data/nope.c @@ -0,0 +1,3 @@ +#include "all.h" + +void (*p)(void) = undefined; diff --git a/test cases/common/220 source set configuration_data/subdir/b.c b/test cases/common/220 source set configuration_data/subdir/b.c new file mode 100644 index 0000000..31c3789 --- /dev/null +++ b/test cases/common/220 source set configuration_data/subdir/b.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include "all.h" + +void h(void) +{ +} + +int main(void) +{ + if (p) abort(); + f(); + g(); +} diff --git a/test cases/common/220 source set configuration_data/subdir/meson.build b/test cases/common/220 source set configuration_data/subdir/meson.build new file mode 100644 index 0000000..b497de5 --- /dev/null +++ b/test cases/common/220 source set configuration_data/subdir/meson.build @@ -0,0 +1 @@ +sources.add(when: ['YES2', good], if_true: [ files('b.c') ]) diff --git a/test cases/common/221 source set dictionary/a.c b/test cases/common/221 source set dictionary/a.c new file mode 100644 index 0000000..0570dff --- /dev/null +++ b/test cases/common/221 source set dictionary/a.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include "all.h" + +int main(void) +{ + if (p) abort(); + f(); +} diff --git a/test cases/common/221 source set dictionary/all.h b/test cases/common/221 source set dictionary/all.h new file mode 100644 index 0000000..728a7f6 --- /dev/null +++ b/test cases/common/221 source set dictionary/all.h @@ -0,0 +1,7 @@ +extern void f(void); +extern void g(void); +extern void h(void); +extern void undefined(void); + +/* No extern here to get a common symbol */ +void (*p)(void); diff --git a/test cases/common/221 source set dictionary/f.c b/test cases/common/221 source set dictionary/f.c new file mode 100644 index 0000000..a50ecda --- /dev/null +++ b/test cases/common/221 source set dictionary/f.c @@ -0,0 +1,5 @@ +#include "all.h" + +void f(void) +{ +} diff --git a/test cases/common/221 source set dictionary/g.c b/test cases/common/221 source set dictionary/g.c new file mode 100644 index 0000000..4a6f253 --- /dev/null +++ b/test cases/common/221 source set dictionary/g.c @@ -0,0 +1,6 @@ +#include "all.h" + +void g(void) +{ + h(); +} diff --git a/test cases/common/221 source set dictionary/meson.build b/test cases/common/221 source set dictionary/meson.build new file mode 100644 index 0000000..9a34507 --- /dev/null +++ b/test cases/common/221 source set dictionary/meson.build @@ -0,0 +1,56 @@ +project('a', 'c') + +good = declare_dependency(link_with: static_library('good', 'g.c')) +bad = declare_dependency(link_args: 'nonexistent.a') +not_found = dependency('invalid', required: false) + +source_set = import('sourceset') + +sources = source_set.source_set() +sources.add(when: 'YES', if_false: ['nope.c']) +sources.add(when: 'YES1', if_true: files('a.c')) +subdir('subdir') +sources.add(when: 'NO', if_true: 'nope.c', if_false: ['f.c']) +sources.add(when: 'NO', if_true: bad, if_false: ['f.c']) + +sources.add(when: 'YES2', if_true: good) + +# dependencies as conditions +sources.add(when: not_found, if_true: 'nope.c') + +# test add_all +sources2 = source_set.source_set() +sources2.add(when: 'YES1', if_true: 'nope.c') +sources.add_all(when: 'NO', if_true: sources2) + +# test duplicate items +sources.add(when: 'YES1', if_true: files('a.c')) + +conf1 = { + 'YES': true, + 'YES1': true, + 'YES2': false, + 'NO': false, +} +result1 = sources.apply(conf1) + +conf2 = { + 'YES': true, + 'YES1': false, + 'YES2': true, + 'NO': false, +} +result2 = sources.apply(conf2) + +# Each target will recompile the objects +executable('first', sources: result1.sources(), dependencies: result1.dependencies()) +executable('second', sources: result2.sources(), dependencies: result2.dependencies()) + +# All target will use the same object files +if meson.is_unity() + message('Skipping extraction test because this is a Unity build.') +else + all_objs = static_library('all_objs', sources.all_sources()) + executable('first_via_lib', objects: all_objs.extract_objects(result1.sources()), dependencies: result1.dependencies()) + executable('second_via_lib', objects: all_objs.extract_objects(result2.sources()), dependencies: result2.dependencies()) +endif diff --git a/test cases/common/221 source set dictionary/nope.c b/test cases/common/221 source set dictionary/nope.c new file mode 100644 index 0000000..0ce1d3b --- /dev/null +++ b/test cases/common/221 source set dictionary/nope.c @@ -0,0 +1,3 @@ +#include "all.h" + +void (*p)(void) = undefined; diff --git a/test cases/common/221 source set dictionary/subdir/b.c b/test cases/common/221 source set dictionary/subdir/b.c new file mode 100644 index 0000000..31c3789 --- /dev/null +++ b/test cases/common/221 source set dictionary/subdir/b.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include "all.h" + +void h(void) +{ +} + +int main(void) +{ + if (p) abort(); + f(); + g(); +} diff --git a/test cases/common/221 source set dictionary/subdir/meson.build b/test cases/common/221 source set dictionary/subdir/meson.build new file mode 100644 index 0000000..b497de5 --- /dev/null +++ b/test cases/common/221 source set dictionary/subdir/meson.build @@ -0,0 +1 @@ +sources.add(when: ['YES2', good], if_true: [ files('b.c') ]) diff --git a/test cases/common/222 source set custom target/a.c b/test cases/common/222 source set custom target/a.c new file mode 100644 index 0000000..39a3b6b --- /dev/null +++ b/test cases/common/222 source set custom target/a.c @@ -0,0 +1,7 @@ +#include "all.h" + +int main(void) +{ + f(); + g(); +} diff --git a/test cases/common/222 source set custom target/all.h b/test cases/common/222 source set custom target/all.h new file mode 100644 index 0000000..5885e32 --- /dev/null +++ b/test cases/common/222 source set custom target/all.h @@ -0,0 +1,2 @@ +extern void f(void); +extern void g(void); diff --git a/test cases/common/222 source set custom target/cp.py b/test cases/common/222 source set custom target/cp.py new file mode 100644 index 0000000..cb09cf3 --- /dev/null +++ b/test cases/common/222 source set custom target/cp.py @@ -0,0 +1,5 @@ +#! /usr/bin/env python3 + +import sys +from shutil import copyfile +copyfile(*sys.argv[1:]) diff --git a/test cases/common/222 source set custom target/f.c b/test cases/common/222 source set custom target/f.c new file mode 100644 index 0000000..a50ecda --- /dev/null +++ b/test cases/common/222 source set custom target/f.c @@ -0,0 +1,5 @@ +#include "all.h" + +void f(void) +{ +} diff --git a/test cases/common/222 source set custom target/g.c b/test cases/common/222 source set custom target/g.c new file mode 100644 index 0000000..7098584 --- /dev/null +++ b/test cases/common/222 source set custom target/g.c @@ -0,0 +1,5 @@ +#include "all.h" + +void g(void) +{ +} diff --git a/test cases/common/222 source set custom target/meson.build b/test cases/common/222 source set custom target/meson.build new file mode 100644 index 0000000..fe6e6e1 --- /dev/null +++ b/test cases/common/222 source set custom target/meson.build @@ -0,0 +1,28 @@ +# Try using sourceset with various kinds of generated sources + +project('a', 'c') + +cp = find_program('cp.py') + +source_set = import('sourceset') +sources = source_set.source_set() + +a_c = custom_target('gen-custom-target', + input: 'a.c', output: 'out_a.c', + command: [cp, '@INPUT@', '@OUTPUT@']) +sources.add(when: 'YES', if_true: a_c) +sources.add(when: 'YES', if_true: a_c[0]) + +f_c = configure_file(input: 'f.c', output: 'out_f.c', copy: true) +sources.add(when: 'YES', if_true: f_c) +sources.add(when: 'YES', if_true: f_c) + +gen = generator(cp, output: 'out_@PLAINNAME@', arguments: ['@INPUT@', '@OUTPUT@']) +g_c = gen.process(files('g.c')) +sources.add(when: 'YES', if_true: g_c) +sources.add(when: 'YES', if_true: g_c) + +conf1 = { 'YES': true, } +result1 = sources.apply(conf1) + +executable('first', sources: result1.sources(), dependencies: result1.dependencies()) |