diff options
author | Dylan Baker <dylan@pnwbakers.com> | 2020-02-06 09:10:01 -0800 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2020-07-30 19:34:37 -0700 |
commit | a6164ca5a81224b7ed672401a47260f498f06e44 (patch) | |
tree | c79d79a3e701c8ce995bfbd104468e71dd45ce4a | |
parent | cc201a539674babf46f726859587afb5ed6a6867 (diff) | |
download | meson-a6164ca5a81224b7ed672401a47260f498f06e44.zip meson-a6164ca5a81224b7ed672401a47260f498f06e44.tar.gz meson-a6164ca5a81224b7ed672401a47260f498f06e44.tar.bz2 |
Allow setting project options from cross or native files
This allows adding a `[project options]` section to a cross or native file
that contains the options defined for a project in it's meson_option.txt
file.
-rw-r--r-- | docs/markdown/Machine-files.md | 20 | ||||
-rw-r--r-- | docs/markdown/snippets/project_options_in_machine_files.md | 37 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 10 | ||||
-rw-r--r-- | mesonbuild/environment.py | 19 | ||||
-rwxr-xr-x | run_unittests.py | 83 | ||||
-rw-r--r-- | test cases/unit/75 user options for subproject/.gitignore | 1 | ||||
-rw-r--r-- | test cases/unit/75 user options for subproject/meson.build | 3 |
7 files changed, 171 insertions, 2 deletions
diff --git a/docs/markdown/Machine-files.md b/docs/markdown/Machine-files.md index 9011f79..26af44a 100644 --- a/docs/markdown/Machine-files.md +++ b/docs/markdown/Machine-files.md @@ -12,6 +12,7 @@ The following sections are allowed: - binaries - paths - properties +- project options ### constants @@ -166,6 +167,25 @@ section may contain random key value pairs accessed using the The properties section can contain any variable you like, and is accessed via `meson.get_external_property`, or `meson.get_cross_property`. +### Project specific options + +*New in 0.54.0* + +Being able to set project specific options in a native or cross files can be +done using the `[project options]` section of the specific file (if doing a +cross build the options from the native file will be ignored) + +For setting options in supbprojects use the `<subproject>:project options` +section instead. + +```ini +[project options] +build-tests = true + +[zlib:project options] +build-tests = false +``` + ## Loading multiple machine files Native files allow layering (cross files can be layered since meson 0.52.0). diff --git a/docs/markdown/snippets/project_options_in_machine_files.md b/docs/markdown/snippets/project_options_in_machine_files.md new file mode 100644 index 0000000..78b129a --- /dev/null +++ b/docs/markdown/snippets/project_options_in_machine_files.md @@ -0,0 +1,37 @@ +## Project options can be set in native or cross files + +A new set of sections has been added to the cross and native files, `[project +options]` and `[<subproject_name>:project options]`, where `subproject_name` +is the name of a subproject. Any options that are allowed in the project can +be set from this section. They have the lowest precedent, and will be +overwritten by command line arguments. + + +```meson +option('foo', type : 'string', value : 'foo') +``` + +```ini +[project options] +foo = 'other val' +``` + +```console +meson build --native-file my.ini +``` + +Will result in the option foo having the value `other val`, + +```console +meson build --native-file my.ini -Dfoo='different val' +``` + +Will result in the option foo having the value `different val`, + + +Subproject options are assigned like this: + +```ini +[zlib:project options] +foo = 'some val' +``` diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index e2a6954..49104a7 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -377,6 +377,7 @@ class CoreData: host_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD) self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache] 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.builtin_options_libdir_cross_fixup() @@ -734,7 +735,7 @@ class CoreData: if not self.is_cross_build(): self.copy_build_options_from_regular_ones() - def set_default_options(self, default_options, subproject, env): + def set_default_options(self, default_options: T.Mapping[str, str], subproject: str, env: 'Environment') -> None: # Warn if the user is using two different ways of setting build-type # options that override each other if 'buildtype' in env.cmd_line_options and \ @@ -755,6 +756,13 @@ class CoreData: k = subproject + ':' + k cmd_line_options[k] = v + # load the values for user options out of the appropriate machine file, + # then overload the command line + for k, v in env.user_options.get(subproject, {}).items(): + if subproject: + k = '{}:{}'.format(subproject, k) + cmd_line_options[k] = v + # Override project default_options using conf files (cross or native) for k, v in env.paths.host: if v is not None: diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index a82c8f8..c872aee 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -553,6 +553,9 @@ class Environment: # architecture, just the build and host architectures paths = PerMachineDefaultable() + # We only need one of these as project options are not per machine + user_options = {} + ## Setup build machine defaults # Will be fully initialized later using compilers later. @@ -565,12 +568,26 @@ class Environment: ## Read in native file(s) to override build machine configuration + def load_user_options(): + for section in config.keys(): + if section.endswith('project options'): + if ':' in section: + project = section.split(':')[0] + else: + project = '' + user_options[project] = config.get(section, {}) + if self.coredata.config_files is not None: config = coredata.parse_machine_files(self.coredata.config_files) binaries.build = BinaryTable(config.get('binaries', {})) paths.build = Directories(**config.get('paths', {})) properties.build = Properties(config.get('properties', {})) + # Don't run this if there are any cross files, we don't want to use + # the native values if we're doing a cross build + if not self.coredata.cross_files: + load_user_options() + ## Read in cross file(s) to override host machine configuration if self.coredata.cross_files: @@ -582,6 +599,7 @@ class Environment: if 'target_machine' in config: machines.target = MachineInfo.from_literal(config['target_machine']) paths.host = Directories(**config.get('paths', {})) + load_user_options() ## "freeze" now initialized configuration, and "save" to the class. @@ -589,6 +607,7 @@ class Environment: self.binaries = binaries.default_missing() self.properties = properties.default_missing() self.paths = paths.default_missing() + self.user_options = user_options exe_wrapper = self.lookup_binary_entry(MachineChoice.HOST, 'exe_wrapper') if exe_wrapper is not None: diff --git a/run_unittests.py b/run_unittests.py index 2b0e4e1..9d96ce0 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -7672,7 +7672,10 @@ class NativeFileTests(BasePlatformTests): for section, entries in values.items(): f.write('[{}]\n'.format(section)) for k, v in entries.items(): - f.write("{}='{}'\n".format(k, v)) + if isinstance(v, bool): + f.write("{}={}\n".format(k, v)) + else: + f.write("{}='{}'\n".format(k, v)) return filename def helper_create_binary_wrapper(self, binary, dir_=None, extra_args=None, **kwargs): @@ -7996,6 +7999,54 @@ class NativeFileTests(BasePlatformTests): self.init(testcase, extra_args=['--native-file', config]) self.build() + def test_user_options(self): + testcase = os.path.join(self.common_test_dir, '43 options') + for opt, value in [('testoption', 'some other val'), ('other_one', True), + ('combo_opt', 'one'), ('array_opt', ['two']), + ('integer_opt', 0)]: + config = self.helper_create_native_file({'project options': {opt: value}}) + with self.assertRaises(subprocess.CalledProcessError) as cm: + self.init(testcase, extra_args=['--native-file', config]) + self.assertRegex(cm.exception.stdout, r'Incorrect value to [a-z]+ option') + + def test_user_options_command_line_overrides(self): + testcase = os.path.join(self.common_test_dir, '43 options') + config = self.helper_create_native_file({'project options': {'other_one': True}}) + self.init(testcase, extra_args=['--native-file', config, '-Dother_one=false']) + + def test_user_options_subproject(self): + testcase = os.path.join(self.unit_test_dir, '75 user options for subproject') + + s = os.path.join(testcase, 'subprojects') + if not os.path.exists(s): + os.mkdir(s) + s = os.path.join(s, 'sub') + if not os.path.exists(s): + sub = os.path.join(self.common_test_dir, '43 options') + shutil.copytree(sub, s) + + for opt, value in [('testoption', 'some other val'), ('other_one', True), + ('combo_opt', 'one'), ('array_opt', ['two']), + ('integer_opt', 0)]: + config = self.helper_create_native_file({'project options': {'sub:{}'.format(opt): value}}) + with self.assertRaises(subprocess.CalledProcessError) as cm: + self.init(testcase, extra_args=['--native-file', config]) + self.assertRegex(cm.exception.stdout, r'Incorrect value to [a-z]+ option') + + def test_option_bool(self): + # Bools are allowed to be unquoted + testcase = os.path.join(self.common_test_dir, '1 trivial') + config = self.helper_create_native_file({'built-in options': {'werror': True}}) + self.init(testcase, extra_args=['--native-file', config]) + configuration = self.introspect('--buildoptions') + for each in configuration: + # Test that no-per subproject options are inherited from the parent + if 'werror' in each['name']: + self.assertEqual(each['value'], True) + break + else: + self.fail('Did not find werror in build options?') + class CrossFileTests(BasePlatformTests): @@ -8005,6 +8056,11 @@ class CrossFileTests(BasePlatformTests): This is mainly aimed to testing overrides from cross files. """ + def setUp(self): + super().setUp() + self.current_config = 0 + self.current_wrapper = 0 + def _cross_file_generator(self, *, needs_exe_wrapper: bool = False, exe_wrapper: T.Optional[T.List[str]] = None) -> str: if is_windows(): @@ -8133,6 +8189,21 @@ class CrossFileTests(BasePlatformTests): self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True) self.wipe() + def helper_create_cross_file(self, values): + """Create a config file as a temporary file. + + values should be a nested dictionary structure of {section: {key: + value}} + """ + filename = os.path.join(self.builddir, 'generated{}.config'.format(self.current_config)) + self.current_config += 1 + with open(filename, 'wt') as f: + for section, entries in values.items(): + f.write('[{}]\n'.format(section)) + for k, v in entries.items(): + f.write("{}='{}'\n".format(k, v)) + return filename + def test_cross_file_dirs(self): testcase = os.path.join(self.unit_test_dir, '60 native file override') self.init(testcase, default_args=False, @@ -8189,6 +8260,16 @@ class CrossFileTests(BasePlatformTests): '-Ddef_sharedstatedir=sharedstatebar', '-Ddef_sysconfdir=sysconfbar']) + def test_user_options(self): + # This is just a touch test for cross file, since the implementation + # shares code after loading from the files + testcase = os.path.join(self.common_test_dir, '43 options') + config = self.helper_create_cross_file({'project options': {'testoption': 'some other value'}}) + with self.assertRaises(subprocess.CalledProcessError) as cm: + self.init(testcase, extra_args=['--native-file', config]) + self.assertRegex(cm.exception.stdout, r'Incorrect value to [a-z]+ option') + + class TAPParserTests(unittest.TestCase): def assert_test(self, events, **kwargs): if 'explanation' not in kwargs: diff --git a/test cases/unit/75 user options for subproject/.gitignore b/test cases/unit/75 user options for subproject/.gitignore new file mode 100644 index 0000000..4976afc --- /dev/null +++ b/test cases/unit/75 user options for subproject/.gitignore @@ -0,0 +1 @@ +subprojects/* diff --git a/test cases/unit/75 user options for subproject/meson.build b/test cases/unit/75 user options for subproject/meson.build new file mode 100644 index 0000000..0bc395b --- /dev/null +++ b/test cases/unit/75 user options for subproject/meson.build @@ -0,0 +1,3 @@ +project('user option for subproject') + +p = subproject('sub') |