summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2019-07-19 10:34:11 -0400
committerXavier Claessens <xclaesse@gmail.com>2020-02-06 14:11:24 -0500
commit3ba0073df6014d4b594df052f8e1fa75ce17b20e (patch)
treeaac412650192c2e934c3e58241b00287bb08b6f9
parent0bf3c4ac4d9128154bf27649a39645b7d804582e (diff)
downloadmeson-3ba0073df6014d4b594df052f8e1fa75ce17b20e.tar.gz
Make 'default_library' per-subproject builtin option
Currently it's just like if all builtin/base/compiler options are yielding. This patch makes possible to have non-yielding builtin options. The value in is overriden in this order: - Value from parent project - Value from subproject's default_options if set - Value from subproject() default_options if set - Value from command line if set
-rw-r--r--docs/markdown/Reference-manual.md3
-rw-r--r--docs/markdown/snippets/per_subproject_builtin.md15
-rw-r--r--mesonbuild/coredata.py58
-rw-r--r--mesonbuild/interpreter.py13
-rw-r--r--mesonbuild/mintro.py15
-rw-r--r--test cases/common/229 persubproject options/foo.c5
-rw-r--r--test cases/common/229 persubproject options/meson.build10
-rw-r--r--test cases/common/229 persubproject options/subprojects/sub1/foo.c5
-rw-r--r--test cases/common/229 persubproject options/subprojects/sub1/meson.build7
-rw-r--r--test cases/common/229 persubproject options/subprojects/sub2/foo.c5
-rw-r--r--test cases/common/229 persubproject options/subprojects/sub2/meson.build7
11 files changed, 117 insertions, 26 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index ae6d1c5a8..510d44323 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -1553,7 +1553,8 @@ arguments:
that override those set in the subproject's `meson_options.txt`
(like `default_options` in `project`, they only have effect when
Meson is run for the first time, and command line arguments override
- any default options in build files)
+ any default options in build files). *Since 0.54.0* `default_library`
+ built-in option can also be overridden.
- `version` keyword argument that works just like the one in
`dependency`. It specifies what version the subproject should be,
as an example `>=1.0.1`
diff --git a/docs/markdown/snippets/per_subproject_builtin.md b/docs/markdown/snippets/per_subproject_builtin.md
new file mode 100644
index 000000000..44ed1c866
--- /dev/null
+++ b/docs/markdown/snippets/per_subproject_builtin.md
@@ -0,0 +1,15 @@
+## Per subproject `default_library` option
+
+The `default_library` built-in option can now be defined per subproject. This is
+useful for example when building shared libraries in the main project, but static
+link a subproject.
+
+Most of the time this would be used either by the parent project by setting
+subproject's default_options (e.g. `subproject('foo', default_options: 'default_library=static')`),
+or by the user using the command line `-Dfoo:default_library=static`.
+
+The value is overriden in this order:
+- Value from parent project
+- Value from subproject's default_options if set
+- Value from subproject() default_options if set
+- Value from command line if set
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index cdee20d73..aea2d908e 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -364,11 +364,12 @@ class CoreData:
self.install_guid = str(uuid.uuid4()).upper()
self.target_guids = {}
self.version = version
- self.init_builtins()
- self.backend_options = {} # : T.Dict[str, UserOption]
- self.user_options = {} # : T.Dict[str, UserOption]
+ self.builtins = {} # : OptionDictType
+ self.builtins_per_machine = PerMachine({}, {})
+ self.backend_options = {} # : OptionDictType
+ self.user_options = {} # : OptionDictType
self.compiler_options = PerMachine({}, {})
- self.base_options = {} # : T.Dict[str, UserOption]
+ self.base_options = {} # : OptionDictType
self.cross_files = self.__load_config_files(options, scratch_dir, 'cross')
self.compilers = PerMachine(OrderedDict(), OrderedDict())
@@ -378,6 +379,7 @@ class CoreData:
self.compiler_check_cache = OrderedDict()
# Only to print a warning if it changes between Meson invocations.
self.config_files = self.__load_config_files(options, scratch_dir, 'native')
+ self.init_builtins('')
self.libdir_cross_fixup()
@staticmethod
@@ -497,15 +499,25 @@ class CoreData:
raise MesonException(msg.format(option, value, prefix))
return value.as_posix()
- def init_builtins(self):
+ def init_builtins(self, subproject: str):
# Create builtin options with default values
- self.builtins = {}
for key, opt in builtin_options.items():
- self.builtins[key] = opt.init_option(key, default_prefix())
- self.builtins_per_machine = PerMachine({}, {})
+ self.add_builtin_option(self.builtins, key, opt, subproject)
for for_machine in iter(MachineChoice):
for key, opt in builtin_options_per_machine.items():
- self.builtins_per_machine[for_machine][key] = opt.init_option()
+ self.add_builtin_option(self.builtins_per_machine[for_machine], key, opt, subproject)
+
+ def add_builtin_option(self, opts_map, key, opt, subproject):
+ if subproject:
+ if opt.yielding:
+ # This option is global and not per-subproject
+ return
+ optname = subproject + ':' + key
+ value = opts_map[key].value
+ else:
+ optname = key
+ value = None
+ opts_map[optname] = opt.init_option(key, value, default_prefix())
def init_backend_options(self, backend_name):
if backend_name == 'ninja':
@@ -520,15 +532,20 @@ class CoreData:
'Default project to execute in Visual Studio',
'')
- def get_builtin_option(self, optname):
+ def get_builtin_option(self, optname, subproject=''):
+ raw_optname = optname
+ if subproject:
+ optname = subproject + ':' + optname
for opts in self._get_all_builtin_options():
v = opts.get(optname)
+ if v is None or v.yielding:
+ v = opts.get(raw_optname)
if v is None:
continue
- if optname == 'wrap_mode':
+ if raw_optname == 'wrap_mode':
return WrapMode.from_string(v.value)
return v.value
- raise RuntimeError('Tried to get unknown builtin option %s.' % optname)
+ raise RuntimeError('Tried to get unknown builtin option %s.' % raw_optname)
def _try_set_builtin_option(self, optname, value):
for opts in self._get_all_builtin_options():
@@ -707,11 +724,13 @@ class CoreData:
env.cmd_line_options.setdefault(k, v)
# Set default options as if they were passed to the command line.
- # Subprojects can only define default for user options.
+ # Subprojects can only define default for user options and not yielding
+ # builtin option.
from . import optinterpreter
for k, v in default_options.items():
if subproject:
- if optinterpreter.is_invalid_name(k, log=False):
+ if (k not in builtin_options or builtin_options[k].yielding) \
+ and optinterpreter.is_invalid_name(k, log=False):
continue
k = subproject + ':' + k
env.cmd_line_options.setdefault(k, v)
@@ -951,7 +970,7 @@ class BuiltinOption(T.Generic[_T, _U]):
Currently doesn't support UserIntegerOption, or a few other cases.
"""
- def __init__(self, opt_type: T.Type[_U], description: str, default: T.Any, yielding: T.Optional[bool] = None, *,
+ def __init__(self, opt_type: T.Type[_U], description: str, default: T.Any, yielding: bool = True, *,
choices: T.Any = None):
self.opt_type = opt_type
self.description = description
@@ -959,9 +978,11 @@ class BuiltinOption(T.Generic[_T, _U]):
self.choices = choices
self.yielding = yielding
- def init_option(self, name: str = 'prefix', prefix: str = '') -> _U:
+ def init_option(self, name: str, value: T.Optional[T.Any], prefix: str) -> _U:
"""Create an instance of opt_type and return it."""
- keywords = {'yielding': self.yielding, 'value': self.prefixed_default(name, prefix)}
+ if value is None:
+ value = self.prefixed_default(name, prefix)
+ keywords = {'yielding': self.yielding, 'value': value}
if self.choices:
keywords['choices'] = self.choices
return self.opt_type(self.description, **keywords)
@@ -1036,7 +1057,8 @@ builtin_options = OrderedDict([
('buildtype', BuiltinOption(UserComboOption, 'Build type to use', 'debug',
choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])),
('debug', BuiltinOption(UserBooleanOption, 'Debug', True)),
- ('default_library', BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'])),
+ ('default_library', BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'],
+ yielding=False)),
('errorlogs', BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)),
('install_umask', BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')),
('layout', BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])),
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 74882b223..d824e3c3a 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -2750,19 +2750,21 @@ external dependencies (including libraries) must go to "dependencies".''')
return result
def get_option_internal(self, optname):
+ raw_optname = optname
+ if self.is_subproject():
+ optname = self.subproject + ':' + optname
+
for opts in chain(
[self.coredata.base_options, compilers.base_options, self.coredata.builtins],
self.coredata.get_prefixed_options_per_machine(self.coredata.builtins_per_machine),
self.coredata.get_prefixed_options_per_machine(self.coredata.compiler_options),
):
v = opts.get(optname)
+ if v is None or v.yielding:
+ v = opts.get(raw_optname)
if v is not None:
return v
- raw_optname = optname
- if self.is_subproject():
- optname = self.subproject + ':' + optname
-
try:
opt = self.coredata.user_options[optname]
if opt.yielding and ':' in optname and raw_optname in self.coredata.user_options:
@@ -2869,6 +2871,7 @@ external dependencies (including libraries) must go to "dependencies".''')
if self.environment.first_invocation:
default_options = self.project_default_options
default_options.update(self.default_project_options)
+ self.coredata.init_builtins(self.subproject)
else:
default_options = {}
self.coredata.set_default_options(default_options, self.subproject, self.environment)
@@ -4368,7 +4371,7 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s
return BothLibrariesHolder(shared_holder, static_holder, self)
def build_library(self, node, args, kwargs):
- default_library = self.coredata.get_builtin_option('default_library')
+ default_library = self.coredata.get_builtin_option('default_library', self.subproject)
if default_library == 'shared':
return self.build_target(node, args, kwargs, SharedLibraryHolder)
elif default_library == 'static':
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index dff5ecc36..cfa457436 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -180,9 +180,10 @@ def list_targets(builddata: build.Build, installdata, backend: backends.Backend)
return tlist
def list_buildoptions_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
- return list_buildoptions(intr.coredata)
+ subprojects = [i['name'] for i in intr.project_data['subprojects']]
+ return list_buildoptions(intr.coredata, subprojects)
-def list_buildoptions(coredata: cdata.CoreData) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
+def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[str]] = None) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
optlist = [] # type: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]
dir_option_names = ['bindir',
@@ -206,6 +207,16 @@ def list_buildoptions(coredata: cdata.CoreData) -> T.List[T.Dict[str, T.Union[st
test_options = {k: o for k, o in coredata.builtins.items() if k in test_option_names}
core_options = {k: o for k, o in coredata.builtins.items() if k in core_option_names}
+ if subprojects:
+ # Add per subproject built-in options
+ sub_core_options = {}
+ for sub in subprojects:
+ for k, o in core_options.items():
+ if o.yielding:
+ continue
+ sub_core_options[sub + ':' + k] = o
+ core_options.update(sub_core_options)
+
def add_keys(options: T.Dict[str, cdata.UserOption], section: str, machine: str = 'any') -> None:
for key in sorted(options.keys()):
opt = options[key]
diff --git a/test cases/common/229 persubproject options/foo.c b/test cases/common/229 persubproject options/foo.c
new file mode 100644
index 000000000..63e4de6a3
--- /dev/null
+++ b/test cases/common/229 persubproject options/foo.c
@@ -0,0 +1,5 @@
+int foo(void);
+
+int foo(void) {
+ return 0;
+}
diff --git a/test cases/common/229 persubproject options/meson.build b/test cases/common/229 persubproject options/meson.build
new file mode 100644
index 000000000..6a76697e2
--- /dev/null
+++ b/test cases/common/229 persubproject options/meson.build
@@ -0,0 +1,10 @@
+project('persubproject options', 'c', default_options : ['default_library=both'])
+
+assert(get_option('default_library') == 'both', 'Parent default_library should be "both"')
+
+# Check it build both by calling a method only both_libraries target implement
+lib = library('lib1', 'foo.c')
+lib.get_static_lib()
+
+subproject('sub1')
+subproject('sub2', default_options : ['default_library=static'])
diff --git a/test cases/common/229 persubproject options/subprojects/sub1/foo.c b/test cases/common/229 persubproject options/subprojects/sub1/foo.c
new file mode 100644
index 000000000..63e4de6a3
--- /dev/null
+++ b/test cases/common/229 persubproject options/subprojects/sub1/foo.c
@@ -0,0 +1,5 @@
+int foo(void);
+
+int foo(void) {
+ return 0;
+}
diff --git a/test cases/common/229 persubproject options/subprojects/sub1/meson.build b/test cases/common/229 persubproject options/subprojects/sub1/meson.build
new file mode 100644
index 000000000..7afc934e6
--- /dev/null
+++ b/test cases/common/229 persubproject options/subprojects/sub1/meson.build
@@ -0,0 +1,7 @@
+project('sub1', 'c')
+
+assert(get_option('default_library') == 'both', 'Should inherit parent project default_library')
+
+# Check it build both by calling a method only both_libraries target implement
+lib = library('lib1', 'foo.c')
+lib.get_static_lib()
diff --git a/test cases/common/229 persubproject options/subprojects/sub2/foo.c b/test cases/common/229 persubproject options/subprojects/sub2/foo.c
new file mode 100644
index 000000000..63e4de6a3
--- /dev/null
+++ b/test cases/common/229 persubproject options/subprojects/sub2/foo.c
@@ -0,0 +1,5 @@
+int foo(void);
+
+int foo(void) {
+ return 0;
+}
diff --git a/test cases/common/229 persubproject options/subprojects/sub2/meson.build b/test cases/common/229 persubproject options/subprojects/sub2/meson.build
new file mode 100644
index 000000000..546884de3
--- /dev/null
+++ b/test cases/common/229 persubproject options/subprojects/sub2/meson.build
@@ -0,0 +1,7 @@
+project('sub2', 'c', default_options : ['default_library=shared'])
+
+assert(get_option('default_library') == 'static', 'Parent should override default_library')
+
+# If it doesn't build only a static library, it would make target name clash.
+library('lib1', 'foo.c')
+shared_library('lib1', 'foo.c')