Compare commits

...

6 Commits

Author SHA1 Message Date
Jussi Pakkanen 8e403e08ac Use library() instead of rolling your own. [skip ci] 5 years ago
Jussi Pakkanen 77a933faca
Merge pull request #5028 from bonzini/sourceset 5 years ago
Michael Hirsch, Ph.D 44b6ccbe56 join_paths => / [skip ci] 5 years ago
Luís Ferreira 144e7dcf3b dub: add other library target types 5 years ago
Paolo Bonzini 06b1f457d5 sourceset: add a realistic example as a testcase 5 years ago
Paolo Bonzini d894c48660 new module "sourceset" to match source file lists against configuration data 5 years ago
  1. 3
      docs/markdown/Installing.md
  2. 6
      docs/markdown/Porting-from-autotools.md
  3. 5
      docs/markdown/Reference-manual.md
  4. 10
      docs/markdown/Release-notes-for-0.49.0.md
  5. 196
      docs/markdown/SourceSet-module.md
  6. 6
      docs/markdown/Syntax.md
  7. 8
      docs/markdown/Vala.md
  8. 15
      docs/markdown/Wrap-best-practices-and-tips.md
  9. 8
      docs/markdown/snippets/sourceset.md
  10. 1
      docs/sitemap.txt
  11. 2
      mesonbuild/dependencies/base.py
  12. 190
      mesonbuild/modules/sourceset.py
  13. 8
      test cases/common/220 source set configuration_data/a.c
  14. 7
      test cases/common/220 source set configuration_data/all.h
  15. 5
      test cases/common/220 source set configuration_data/f.c
  16. 6
      test cases/common/220 source set configuration_data/g.c
  17. 54
      test cases/common/220 source set configuration_data/meson.build
  18. 3
      test cases/common/220 source set configuration_data/nope.c
  19. 13
      test cases/common/220 source set configuration_data/subdir/b.c
  20. 1
      test cases/common/220 source set configuration_data/subdir/meson.build
  21. 8
      test cases/common/221 source set dictionary/a.c
  22. 7
      test cases/common/221 source set dictionary/all.h
  23. 5
      test cases/common/221 source set dictionary/f.c
  24. 6
      test cases/common/221 source set dictionary/g.c
  25. 56
      test cases/common/221 source set dictionary/meson.build
  26. 3
      test cases/common/221 source set dictionary/nope.c
  27. 13
      test cases/common/221 source set dictionary/subdir/b.c
  28. 1
      test cases/common/221 source set dictionary/subdir/meson.build
  29. 7
      test cases/common/222 source set custom target/a.c
  30. 2
      test cases/common/222 source set custom target/all.h
  31. 5
      test cases/common/222 source set custom target/cp.py
  32. 5
      test cases/common/222 source set custom target/f.c
  33. 5
      test cases/common/222 source set custom target/g.c
  34. 28
      test cases/common/222 source set custom target/meson.build
  35. 8
      test cases/common/223 source set realistic example/boards/arm/aarch64.cc
  36. 10
      test cases/common/223 source set realistic example/boards/arm/arm.cc
  37. 12
      test cases/common/223 source set realistic example/boards/arm/arm.h
  38. 8
      test cases/common/223 source set realistic example/boards/arm/arm32.cc
  39. 16
      test cases/common/223 source set realistic example/boards/arm/versatilepb.cc
  40. 16
      test cases/common/223 source set realistic example/boards/arm/virt.cc
  41. 16
      test cases/common/223 source set realistic example/boards/arm/xlnx_zcu102.cc
  42. 7
      test cases/common/223 source set realistic example/boards/meson.build
  43. 26
      test cases/common/223 source set realistic example/boards/x86/pc.cc
  44. 41
      test cases/common/223 source set realistic example/common.h
  45. 5
      test cases/common/223 source set realistic example/config/aarch64
  46. 3
      test cases/common/223 source set realistic example/config/arm
  47. 4
      test cases/common/223 source set realistic example/config/x86
  48. 3
      test cases/common/223 source set realistic example/devices/meson.build
  49. 16
      test cases/common/223 source set realistic example/devices/virtio-mmio.cc
  50. 16
      test cases/common/223 source set realistic example/devices/virtio-pci.cc
  51. 6
      test cases/common/223 source set realistic example/devices/virtio.cc
  52. 10
      test cases/common/223 source set realistic example/devices/virtio.h
  53. 32
      test cases/common/223 source set realistic example/main.cc
  54. 44
      test cases/common/223 source set realistic example/meson.build
  55. 8
      test cases/common/223 source set realistic example/not-found.cc
  56. 7
      test cases/common/223 source set realistic example/was-found.cc
  57. 13
      test cases/common/223 source set realistic example/zlib.cc

@ -27,7 +27,8 @@ Other install commands are the following.
```meson
install_headers('header.h', subdir : 'projname') # -> include/projname/header.h
install_man('foo.1') # -> share/man/man1/foo.1
install_data('datafile.dat', install_dir : join_paths(get_option('datadir'), 'progname')) # -> share/progname/datafile.dat
install_data('datafile.dat', install_dir : get_option('datadir') / 'progname')
# -> share/progname/datafile.dat
```
`install_data()` supports rename of the file *since 0.46.0*.

@ -608,7 +608,7 @@ gsettings_SCHEMAS = foo.gschema.xml
`meson.build`:
```meson
install_data('foo.gschema.xml', install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas'))
install_data('foo.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0' / 'schemas')
meson.add_install_script('meson_post_install.py')
```
@ -668,7 +668,7 @@ i18n.merge_file(
type: 'desktop',
po_dir: 'po',
install: true,
install_dir: join_paths(get_option('datadir'), 'applications')
install_dir: get_option('datadir') / 'applications'
)
i18n.merge_file(
@ -676,7 +676,7 @@ i18n.merge_file(
output: 'foo.appdata.xml',
po_dir: 'po',
install: true,
install_dir: join_paths(get_option('datadir'), 'appdata')
install_dir: get_option('datadir') / 'appdata'
)
```

@ -568,7 +568,7 @@ be passed to [shared and static libraries](#library).
- `install_dir` override install directory for this file. The value is
relative to the `prefix` specified. F.ex, if you want to install
plugins into a subdir, you'd use something like this: `install_dir :
join_paths(get_option('libdir'), 'projectname-1.0'`).
get_option('libdir') / 'projectname-1.0'`.
- `install_mode` *(added 0.47.0)* specify the file mode in symbolic format
and optionally the owner/uid and group/gid for the installed files.
- `install_rpath` a string to set the target's rpath to after install
@ -780,8 +780,7 @@ The only exceptions are: `sysconfdir`, `localstatedir`, and
configuration as-is, which may be absolute, or relative to `prefix`.
[`install_dir` arguments](Installing.md) handles that as expected, but
if you need the absolute path to one of these e.g. to use in a define
etc., you should use `join_paths(get_option('prefix'),
get_option('localstatedir'))`
etc., you should use `get_option('prefix') / get_option('localstatedir')`
For options of type `feature` a special object is returned instead of
a string. See [`feature` options](Build-options.md#features)

@ -234,16 +234,18 @@ endif
## Joining paths with /
Joining two paths has traditionally been done with the `join_paths` function.
For clarity and conciseness, we recommend using the `/` operator to separate
path elements:
```meson
joined = join_paths('foo', 'bar')
joined = 'foo' / 'bar'
```
Now you can use the simpler notation using the `/` operator.
Before Meson 0.49, joining path elements was done with the legacy `join_paths`
function, but the `/` syntax above is now recommended.
```meson
joined = 'foo' / 'bar'
joined = join_paths('foo', 'bar')
```
This only works for strings.

@ -0,0 +1,196 @@
---
short-description: Source set module
authors:
- name: Paolo Bonzini
email: pbonzini@redhat.com
years: [2019]
...
# Source set module
This module provides support for building many targets against a single set
of files; the choice of which files to include in each target depends on the
contents of a dictionary or a `configuration_data` object. The module can
be loaded with:
``` meson
ssmod = import('sourceset')
```
A simple example of using the module looks like this:
``` meson
ss = ssmod.source_set()
# Include main.c unconditionally
ss.add(files('main.c'))
# Include a.c if configuration key FEATURE1 is true
ss.add(when: 'FEATURE1', if_true: files('a.c'))
# Include zlib.c if the zlib dependency was found, and link zlib
# in the executable
ss.add(when: zlib, if_true: files('zlib.c'))
# many more rules here...
ssconfig = ss.apply(config)
executable('exe', sources: ssconfig.sources(),
dependencies: ssconfig.dependencies())
```
and it would be equivalent to
``` meson
sources = files('main.c')
dependencies = []
if config['FEATURE1'] then
sources += [files('a.c')]
endif
if zlib.found() then
sources += [files('zlib.c')]
dependencies += [zlib]
endif
# many more "if"s here...
executable('exe', sources: sources, dependencies: dependencies())
```
Sourcesets can be used with a single invocation of the `apply` method,
similar to the example above, but the module is especially useful
when multiple executables are generated by applying the same rules to
many different configurations.
*Added 0.51.0*
## Functions
### `source_set()`
``` meson
ssmod.source_set()
```
Create and return a new source set object.
**Returns**: a [source set][`source_set` object]
## `source_set` object
The `source_set` object provides methods to add files to a source set and
to query it. The source set becomes immutable after any method but `add`
is called.
### Methods
#### `add()`
``` meson
source_set.add([when: varnames_and_deps],
[if_true: sources_and_deps],
[if_false: list_of_alt_sources])
source_set.add(sources_and_deps)
```
Add a *rule* to a source set. A rule determines the conditions under which
some source files or dependency objects are included in a build configuration.
All source files must be present in the source tree or they can be created
in the build tree via `configure_file`, `custom_target` or `generator`.
`varnames_and_deps` is a list of conditions for the rule, which can be
either strings or dependency objects (a dependency object is anything that
has a `found()` method). If *all* the strings evaluate to true and all
dependencies are found, the rule will evaluate to true; `apply()`
will then include the contents of the `if_true` keyword argument in its
result. Otherwise, that is if any of the strings in the positional
arguments evaluate to false or any dependency is not found, `apply()`
will instead use the contents of the `if_false` keyword argument.
Dependencies can also appear in `sources_and_deps`. In this case, a
missing dependency will simply be ignored and will *not* disable the rule,
similar to how the `dependencies` keyword argument works in build targets.
**Note**: It is generally better to avoid mixing source sets and disablers.
This is because disablers will cause the rule to be dropped altogether,
and the `list_of_alt_sources` would not be taken into account anymore.
#### `add_all()`
``` meson
source_set.add_all(when: varnames_and_deps,
if_true: [source_set1, source_set2, ...])
source_set.add_all(source_set1, source_set2, ...)
```
Add one or more source sets to another.
For each source set listed in the arguments, `apply()` will
consider their rules only if the conditions in `varnames_and_deps` are
evaluated positively. For example, the following:
``` meson
sources_b = ssmod.source_set()
sources_b.add(when: 'HAVE_A', if_true: 'file.c')
sources = ssmod.source_set()
sources.add_all(when: 'HAVE_B', if_true: sources_b)
```
is equivalent to:
``` meson
sources = ssmod.source_set()
sources.add(when: ['HAVE_A', 'HAVE_B'], if_true: 'file.c')
```
#### `all_sources()`
``` meson
list source_set.all_sources(...)
```
Returns a list of all sources that were placed in the source set using
`add` (including nested source sets) and that do not have a not-found
dependency. If a rule has a not-found dependency, only the `if_false`
sources are included (if any).
**Returns**: a list of file objects
#### `apply()`
``` meson
source_files source_set.apply(conf_data[, strict: false])
```
Match the source set against a dictionary or a `configuration_data` object
and return a *source configuration* object. A source configuration object
allows you to retrieve the sources and dependencies for a specific configuration.
By default, all the variables that were specified in the rules have to
be present in `conf_data`. However, in some cases the convention is
that `false` configuration symbols are absent in `conf_data`; this is
the case for example when the configuration was loaded from a Kconfig file.
In that case you can specify the `strict: false` keyword argument, which
will treat absent variables as false.
**Returns**: a [source configuration][`source_configuration` object]
## `source_configuration` object
The `source_configuration` object provides methods to query the result of an
`apply` operation on a source set.
### Methods
#### `sources()`
``` meson
source_config.sources()
```
Return the source files corresponding to the applied configuration.
**Returns**: a list of file objects
#### `dependencies()`
``` meson
source_config.dependencies()
```
Return the dependencies corresponding to the applied configuration.
**Returns**: a list of dependency objects

@ -214,12 +214,12 @@ pathsep = ':'
path = pathsep.join(['/usr/bin', '/bin', '/usr/local/bin'])
# path now has the value '/usr/bin:/bin:/usr/local/bin'
# For joining paths, you should use join_paths()
# For joining path elements, you should use path1 / path2
# This has the advantage of being cross-platform
path = join_paths(['/usr', 'local', 'bin'])
path = '/usr' / 'local' / 'bin'
# path now has the value '/usr/local/bin'
# Don't use join_paths for sources files, use files for that:
# For sources files, use files():
my_sources = files('foo.c')
...
my_sources += files('bar.c')

@ -148,7 +148,7 @@ function:
```meson
project('vala app', 'vala', 'c')
vapi_dir = join_paths(meson.current_source_dir(), 'vapi')
vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
@ -229,7 +229,7 @@ file and the VAPI is in the `vapi` directory of your project source files:
```meson
project('vala app', 'vala', 'c')
vapi_dir = join_paths(meson.current_source_dir(), 'vapi')
vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
@ -309,9 +309,9 @@ program and a dependency on the library:
```meson
g_ir_compiler = find_program('g-ir-compiler')
custom_target('foo typelib', command: [g_ir_compiler, '--output', '@OUTPUT@', '@INPUT@'],
input: join_paths(meson.current_build_dir(), 'Foo-1.0.gir'),
input: meson.current_build_dir() / 'Foo-1.0.gir',
output: 'Foo-1.0.typelib',
depends: foo_lib,
install: true,
install_dir: join_paths(get_option('libdir'), 'girepository-1.0'))
install_dir: get_option('libdir') / 'girepository-1.0')
```

@ -47,19 +47,12 @@ also faster during development due to Meson's relinking
optimization. However building both library types on all builds is
slow and wasteful.
Your project should provide a toggle specifying which type of library
it should build. As an example if you have a Meson option called
`shared_lib` then you could do this:
Your project should use the `library` method that can be toggled
between shared and static with the `defaul_library` builtin option.
```meson
if get_option('shared_lib')
libtype = 'shared_library'
else
libtype = 'static_library'
endif
mylib = build_target('foo', 'foo.c',
target_type : libtype)
mylib = library('foo', 'foo.c')
```
## Declare generated headers explicitly

@ -0,0 +1,8 @@
## New `sourceset` module
A new module, `sourceset`, was added to help building many binaries
from the same source files. Source sets associate source files and
dependencies to keys in a `configuration_data` object or a dictionary;
they then take multiple `configuration_data` objects or dictionaries,
and compute the set of source files and dependencies for each of those
configurations.

@ -43,6 +43,7 @@ index.md
Qt5-module.md
RPM-module.md
Simd-module.md
SourceSet-module.md
Windows-module.md
Cuda-module.md
Kconfig-module.md

@ -1892,7 +1892,7 @@ class DubDependency(ExternalDependency):
not_lib = True
if 'targetType' in package:
if package['targetType'] == 'library':
if package['targetType'] in ['library', 'sourceLibrary', 'staticLibrary', 'dynamicLibrary']:
not_lib = False
if not_lib:

@ -0,0 +1,190 @@
# Copyright 2019 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import namedtuple
from .. import mesonlib
from ..mesonlib import listify
from . import ExtensionModule
from ..interpreterbase import (
noPosargs, noKwargs, permittedKwargs,
InterpreterObject, MutableInterpreterObject, ObjectHolder,
InterpreterException, InvalidArguments, InvalidCode, FeatureNew,
)
from ..interpreter import (
GeneratedListHolder, CustomTargetHolder,
CustomTargetIndexHolder
)
SourceSetRule = namedtuple('SourceSetRule', 'keys sources if_false sourcesets dependencies extra_deps')
SourceFiles = namedtuple('SourceFiles', 'sources dependencies')
class SourceSetHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self, environment, subdir):
MutableInterpreterObject.__init__(self)
ObjectHolder.__init__(self, list())
self.environment = environment
self.subdir = subdir
self.frozen = False
self.methods.update({
'add': self.add_method,
'add_all': self.add_all_method,
'all_sources': self.all_sources_method,
'apply': self.apply_method,
})
def check_source_files(self, arg, allow_deps):
sources = []
deps = []
for x in arg:
if isinstance(x, (str, mesonlib.File,
GeneratedListHolder, CustomTargetHolder,
CustomTargetIndexHolder)):
sources.append(x)
elif hasattr(x, 'found'):
if not allow_deps:
msg = 'Dependencies are not allowed in the if_false argument.'
raise InvalidArguments(msg)
deps.append(x)
else:
msg = 'Sources must be strings or file-like objects.'
raise InvalidArguments(msg)
mesonlib.check_direntry_issues(sources)
return sources, deps
def check_conditions(self, arg):
keys = []
deps = []
for x in listify(arg):
if isinstance(x, str):
keys.append(x)
elif hasattr(x, 'found'):
deps.append(x)
else:
raise InvalidArguments('Conditions must be strings or dependency object')
return keys, deps
@permittedKwargs(['when', 'if_false', 'if_true'])
def add_method(self, args, kwargs):
if self.frozen:
raise InvalidCode('Tried to use \'add\' after querying the source set')
when = listify(kwargs.get('when', []))
if_true = listify(kwargs.get('if_true', []))
if_false = listify(kwargs.get('if_false', []))
if not when and not if_true and not if_false:
if_true = args
elif args:
raise InterpreterException('add called with both positional and keyword arguments')
keys, dependencies = self.check_conditions(when)
sources, extra_deps = self.check_source_files(if_true, True)
if_false, _ = self.check_source_files(if_false, False)
self.held_object.append(SourceSetRule(keys, sources, if_false, [], dependencies, extra_deps))
@permittedKwargs(['when', 'if_true'])
def add_all_method(self, args, kwargs):
if self.frozen:
raise InvalidCode('Tried to use \'add_all\' after querying the source set')
when = listify(kwargs.get('when', []))
if_true = listify(kwargs.get('if_true', []))
if not when and not if_true:
if_true = args
elif args:
raise InterpreterException('add_all called with both positional and keyword arguments')
keys, dependencies = self.check_conditions(when)
for s in if_true:
if not isinstance(s, SourceSetHolder):
raise InvalidCode('Arguments to \'add_all\' after the first must be source sets')
s.frozen = True
self.held_object.append(SourceSetRule(keys, [], [], if_true, dependencies, []))
def collect(self, enabled_fn, all_sources, into=None):
if not into:
into = SourceFiles(set(), set())
for entry in self.held_object:
if all(x.found() for x in entry.dependencies) and \
all(enabled_fn(key) for key in entry.keys):
into.sources.update(entry.sources)
into.dependencies.update(entry.dependencies)
into.dependencies.update(entry.extra_deps)
for ss in entry.sourcesets:
ss.collect(enabled_fn, all_sources, into)
if not all_sources:
continue
into.sources.update(entry.if_false)
return into
@noKwargs
@noPosargs
def all_sources_method(self, args, kwargs):
self.frozen = True
files = self.collect(lambda x: True, True)
return list(files.sources)
@permittedKwargs(['strict'])
def apply_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('Apply takes exactly one argument')
config_data = args[0]
self.frozen = True
strict = kwargs.get('strict', True)
if isinstance(config_data, dict):
def _get_from_config_data(key):
if strict and key not in config_data:
raise InterpreterException('Entry %s not in configuration dictionary.' % key)
return config_data.get(key, False)
else:
config_cache = dict()
def _get_from_config_data(key):
nonlocal config_cache
if key not in config_cache:
args = [key] if strict else [key, False]
config_cache[key] = config_data.get_method(args, {})
return config_cache[key]
files = self.collect(_get_from_config_data, False)
res = SourceFilesHolder(files)
return res
class SourceFilesHolder(InterpreterObject, ObjectHolder):
def __init__(self, files):
InterpreterObject.__init__(self)
ObjectHolder.__init__(self, files)
self.methods.update({
'sources': self.sources_method,
'dependencies': self.dependencies_method,
})
@noPosargs
@noKwargs
def sources_method(self, args, kwargs):
return list(self.held_object.sources)
@noPosargs
@noKwargs
def dependencies_method(self, args, kwargs):
return list(self.held_object.dependencies)
class SourceSetModule(ExtensionModule):
@FeatureNew('SourceSet module', '0.51.0')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.snippets.add('source_set')
@noKwargs
@noPosargs
def source_set(self, interpreter, state, args, kwargs):
return SourceSetHolder(interpreter.environment, interpreter.subdir)
def initialize(*args, **kwargs):
return SourceSetModule(*args, **kwargs)

@ -0,0 +1,8 @@
#include <stdlib.h>
#include "all.h"
int main(void)
{
if (p) abort();
f();
}

@ -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);

@ -0,0 +1,5 @@
#include "all.h"
void f(void)
{
}

@ -0,0 +1,6 @@
#include "all.h"
void g(void)
{
h();
}

@ -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

@ -0,0 +1,3 @@
#include "all.h"
void (*p)(void) = undefined;

@ -0,0 +1,13 @@
#include <stdlib.h>
#include "all.h"
void h(void)
{
}
int main(void)
{
if (p) abort();
f();
g();
}

@ -0,0 +1 @@
sources.add(when: ['YES2', good], if_true: [ files('b.c') ])

@ -0,0 +1,8 @@
#include <stdlib.h>
#include "all.h"
int main(void)
{
if (p) abort();
f();
}

@ -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);

@ -0,0 +1,5 @@
#include "all.h"
void f(void)
{
}

@ -0,0 +1,6 @@
#include "all.h"
void g(void)
{
h();
}

@ -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

@ -0,0 +1,3 @@
#include "all.h"
void (*p)(void) = undefined;

@ -0,0 +1,13 @@
#include <stdlib.h>
#include "all.h"
void h(void)
{
}
int main(void)
{
if (p) abort();
f();
g();
}

@ -0,0 +1 @@
sources.add(when: ['YES2', good], if_true: [ files('b.c') ])

@ -0,0 +1,7 @@
#include "all.h"
int main(void)
{
f();
g();
}

@ -0,0 +1,2 @@
extern void f(void);
extern void g(void);

@ -0,0 +1,5 @@
#! /usr/bin/env python3
import sys
from shutil import copyfile
copyfile(*sys.argv[1:])

@ -0,0 +1,5 @@
#include "all.h"
void f(void)
{
}

@ -0,0 +1,5 @@
#include "all.h"
void g(void)
{
}

@ -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())

@ -0,0 +1,8 @@
#include "common.h"
#include <iostream>
void initialize_target()
{
std::cout << ANSI_START << "some " << THE_TARGET
<< " initialization" << ANSI_END << std::endl;
}

@ -0,0 +1,10 @@
#include "arm.h"
const char *ARMBoard::target()
{
return THE_TARGET;
}
void ARMBoard::some_arm_thing()
{
}

@ -0,0 +1,12 @@
#ifndef ARM_H
#define ARM_H 1
#include "common.h"
struct ARMBoard: Board {
const char *target();
void some_arm_thing();
};
#endif

@ -0,0 +1,8 @@
#include "common.h"
#include <iostream>
void initialize_target()
{
std::cout << ANSI_START << "a different " << THE_TARGET
<< " initialization" << ANSI_END << std::endl;
}

@ -0,0 +1,16 @@
#include <iostream>
#include "common.h"
#include "arm.h"
struct VersatilePBBoard: ARMBoard {
void say_hello();
};
void VersatilePBBoard::say_hello()
{
some_arm_thing();
std::cout << ANSI_START << "I am the versatilepb board"
<< ANSI_END << std::endl;
}
static VersatilePBBoard versatilepb;

@ -0,0 +1,16 @@
#include <iostream>
#include "common.h"
#include "arm.h"
struct VirtBoard: ARMBoard {
void say_hello();
};
void VirtBoard::say_hello()
{
some_arm_thing();
std::cout << ANSI_START << "I am the virt board"
<< ANSI_END << std::endl;
}
static VirtBoard virt;

@ -0,0 +1,16 @@
#include <iostream>
#include "common.h"
#include "arm.h"
struct XlnxZCU102Board: ARMBoard {
void say_hello();
};
void XlnxZCU102Board::say_hello()
{
some_arm_thing();
std::cout << ANSI_START << "I am the xlnx_zcu102 board"
<< ANSI_END << std::endl;
}
static XlnxZCU102Board xlnx_zcu102;

@ -0,0 +1,7 @@
specific.add(when: 'TARGET_ARM', if_true: files('arm/arm.cc', 'arm/arm32.cc'))
specific.add(when: 'TARGET_AARCH64', if_true: files('arm/arm.cc', 'arm/aarch64.cc'))
specific.add(when: 'CONFIG_VIRT', if_true: files('arm/virt.cc'))
specific.add(when: 'CONFIG_XLNX_ZCU102', if_true: files('arm/xlnx_zcu102.cc'))
specific.add(when: 'CONFIG_VERSATILEPB', if_true: files('arm/versatilepb.cc'))
specific.add(when: 'TARGET_X86', if_true: files('x86/pc.cc'))

@ -0,0 +1,26 @@
#include <iostream>
#include "common.h"
struct X86Board: Board {
const char *target();
void say_hello();
};
const char *X86Board::target()
{
return THE_TARGET;
}
void X86Board::say_hello()
{
std::cout << ANSI_START << "I am a 1996 PC"
<< ANSI_END << std::endl;
}
void initialize_target()
{
std::cout << ANSI_START << "ready, set, go"
<< ANSI_END << std::endl;
}
static X86Board pc;

@ -0,0 +1,41 @@
#ifndef COMMON_H
#define COMMON_H 1
/*
* target-specific code will print in yellow, common code will print
* in grey.
*/
#ifdef THE_TARGET
#define ANSI_START "\x1b[33;1m"
#define ANSI_END "\x1b[0m"
#else
#define ANSI_START ""
#define ANSI_END ""
#endif
void some_random_function();
void initialize_target();
struct Board {
Board *next;
Board();
virtual ~Board();
virtual void say_hello() = 0;
virtual const char *target() = 0;
};
struct Device {
Device *next;
Device();
virtual ~Device();
virtual void say_hello() = 0;
};
struct Dependency {
Dependency *next;
Dependency();
virtual ~Dependency();
virtual void initialize() = 0;
};
#endif

@ -0,0 +1,5 @@
TARGET_AARCH64=y
CONFIG_VIRT=y
CONFIG_XLNX_ZCU102=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_MMIO=y

@ -0,0 +1,3 @@
TARGET_ARM=y
CONFIG_VIRT=y
CONFIG_VERSATILEPB=y

@ -0,0 +1,4 @@
TARGET_X86=y
CONFIG_PC=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y

@ -0,0 +1,3 @@
specific.add(when: 'CONFIG_VIRTIO', if_true: files('virtio.cc'))
common.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.cc'))
common.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.cc'))

@ -0,0 +1,16 @@
#include <iostream>
#include "common.h"
#include "virtio.h"
struct VirtioMMIODevice: VirtioDevice {
void say_hello();
};
void VirtioMMIODevice::say_hello()
{
some_virtio_thing();
std::cout << ANSI_START << "virtio-mmio is available"
<< ANSI_END << std::endl;
}
static VirtioMMIODevice virtio_mmio;

@ -0,0 +1,16 @@
#include <iostream>
#include "common.h"
#include "virtio.h"
struct VirtioPCIDevice: VirtioDevice {
void say_hello();
};
void VirtioPCIDevice::say_hello()
{
some_virtio_thing();
std::cout << ANSI_START << "virtio-pci is available"
<< ANSI_END << std::endl;
}
static VirtioPCIDevice virtio_pci;

@ -0,0 +1,6 @@
#include <iostream>
#include "common.h"
#include "virtio.h"
void VirtioDevice::some_virtio_thing() {
}

@ -0,0 +1,10 @@
#ifndef VIRTIO_H
#define VIRTIO_H 1
#include "common.h"
struct VirtioDevice: Device {
void some_virtio_thing();
};
#endif

@ -0,0 +1,32 @@
#include <iostream>
#include <vector>
#include "common.h"
Board* boards;
Device* devices;
Dependency* deps;
Board::Board() { this->next = boards; boards = this; }
Board::~Board() {}
Device::Device() { this->next = devices; devices = this; }
Device::~Device() {}
Dependency::Dependency() { this->next = deps; deps = this; }
Dependency::~Dependency() {}
int main()
{
some_random_function();
for (auto d = deps; d; d = d->next)
d->initialize();
initialize_target();
for (auto b = boards; b; b = b->next) {
std::cout << ANSI_START << b->target() << " - " << ANSI_END;
b->say_hello();
}
for (auto d = devices; d; d = d->next)
d->say_hello();
}

@ -0,0 +1,44 @@
# a sort-of realistic example that combines the sourceset and kconfig
# modules, inspired by QEMU's build system
project('sourceset-example', 'cpp')
ss = import('sourceset')
kconfig = import('unstable-kconfig')
zlib = dependency('zlib', version : '>=1.2.8', required: false)
not_found = dependency('not-found', required: false)
common = ss.source_set()
specific = ss.source_set()
common.add(files('main.cc'))
common.add(when: zlib, if_true: files('zlib.cc'))
common.add(when: not_found,
if_true: files('was-found.cc'),
if_false: files('not-found.cc'))
subdir('boards')
subdir('devices')
if meson.is_unity()
specific.add_all(common)
common = ss.source_set()
endif
common_lib = static_library('common', common.all_sources())
targets = [ 'arm', 'aarch64', 'x86' ]
target_dirs = { 'arm' : 'arm', 'aarch64' : 'arm', 'x86': 'x86' }
foreach x : targets
config = kconfig.load('config' / x)
target_specific = specific.apply(config, strict: false)
target_common = common.apply(config, strict: false)
target_deps = target_specific.dependencies() + target_common.dependencies()
executable(x,
objects: common_lib.extract_objects(target_common.sources()),
sources: target_specific.sources(),
dependencies: target_deps,
include_directories: 'boards' / target_dirs[x],
cpp_args: '-DTHE_TARGET="' + x + '"')
endforeach

@ -0,0 +1,8 @@
#include <iostream>
#include "common.h"
void some_random_function()
{
std::cout << ANSI_START << "everything's alright"
<< ANSI_END << std::endl;
}

@ -0,0 +1,7 @@
#include <iostream>
void some_random_function()
{
std::cout << ANSI_START << "huh?"
<< ANSI_END << std::endl;
}

@ -0,0 +1,13 @@
#include <iostream>
#include "common.h"
struct ZLibDependency : Dependency {
void initialize();
};
void ZLibDependency::initialize() {
std::cout << ANSI_START << "hello from zlib"
<< ANSI_END << std::endl;
}
ZLibDependency zlib;
Loading…
Cancel
Save