diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2024-04-09 21:43:33 +0300 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2024-07-17 19:14:45 +0300 |
commit | cb5736304b5dcd2d15d0b422149b6c3926467889 (patch) | |
tree | 90f6d093ed8fa3c49caf905b381dfc5a8d97ad50 | |
parent | b204454731e5edb0c44fc64d8a8ae684fddc1b15 (diff) | |
download | meson-cb5736304b5dcd2d15d0b422149b6c3926467889.zip meson-cb5736304b5dcd2d15d0b422149b6c3926467889.tar.gz meson-cb5736304b5dcd2d15d0b422149b6c3926467889.tar.bz2 |
Can specify per-subproject options from the command line.
-rw-r--r-- | mesonbuild/coredata.py | 53 | ||||
-rw-r--r-- | mesonbuild/mconf.py | 28 | ||||
-rw-r--r-- | test cases/unit/123 persp options/meson.build | 22 | ||||
-rw-r--r-- | test cases/unit/123 persp options/meson.options | 1 | ||||
-rw-r--r-- | test cases/unit/123 persp options/subprojects/sub1/meson.build | 20 | ||||
-rw-r--r-- | test cases/unit/123 persp options/subprojects/sub1/meson.options | 1 | ||||
-rw-r--r-- | test cases/unit/123 persp options/subprojects/sub1/sub1.c | 6 | ||||
-rw-r--r-- | test cases/unit/123 persp options/subprojects/sub2/meson.build | 19 | ||||
-rw-r--r-- | test cases/unit/123 persp options/subprojects/sub2/meson.options | 1 | ||||
-rw-r--r-- | test cases/unit/123 persp options/subprojects/sub2/sub2.c | 6 | ||||
-rw-r--r-- | test cases/unit/123 persp options/toplevel.c | 6 | ||||
-rw-r--r-- | unittests/linuxliketests.py | 42 |
12 files changed, 197 insertions, 8 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index b35081a..458e014 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -260,6 +260,7 @@ class CoreData: self.target_guids = {} self.version = version self.optstore = options.OptionStore() + self.sp_option_overrides: 'MutableKeyedOptionDictType' = {} self.cross_files = self.__load_config_files(cmd_options, scratch_dir, 'cross') self.compilers: PerMachine[T.Dict[str, Compiler]] = PerMachine(OrderedDict(), OrderedDict()) @@ -441,17 +442,20 @@ class CoreData: 'Default project to execute in Visual Studio', '')) + def get_and_clean(self, key, store): + v = store[key].value + if key.name == 'wrap_mode': + return WrapMode[v] + return v + def get_option(self, key: OptionKey) -> T.Union[T.List[str], str, int, bool]: try: - v = self.optstore.get_value(key) - return v + return self.get_and_clean(key, self.sp_option_overrides) except KeyError: pass try: - v = self.optstore.get_value_object(key.as_root()) - if v.yielding: - return v.value + return self.get_and_clean(key.as_root(), self.options) except KeyError: pass @@ -697,6 +701,45 @@ class CoreData: return dirty + def can_set_per_sb(self, keystr): + return True + + def create_sp_options(self, A) -> bool: + if A is None: + return False + import copy + dirty = False + for entry in A: + keystr, valstr = entry.split('=', 1) + if ':' not in keystr: + raise MesonException(f'Option to add override has no subproject: {entry}') + if not self.can_set_per_sb(keystr): + raise MesonException(f'Option {keystr} can not be set per subproject.') + key = OptionKey.from_string(keystr) + if key in self.sp_option_overrides: + raise MesonException(f'Override {keystr} already exists.') + original_key = key.evolve(subproject='') + if original_key not in self.options: + raise MesonException('Tried to override a nonexisting key.') + new_opt = copy.deepcopy(self.options[original_key]) + new_opt.set_value(valstr) + self.sp_option_overrides[key] = new_opt + dirty = True + return dirty + + def remove_sp_options(self, U) -> bool: + dirty = False + if U is None: + return False + for entry in U: + key = OptionKey.from_string(entry) + if key in self.options: + del self.options[key] + dirty = True + else: + pass # Deleting a non-existing key ok, I guess? + return dirty + def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], subproject: str, env: 'Environment') -> None: from .compilers import base_options diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 6cb64e1..62888aa 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -48,6 +48,10 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None: help='Clear cached state (e.g. found dependencies)') parser.add_argument('--no-pager', action='store_false', dest='pager', help='Do not redirect output to a pager') + parser.add_argument('-A', action='append', dest='A', + help='Add a subproject option.') + parser.add_argument('-U', action='append', dest='U', + help='Remove a subproject option.') def stringify(val: T.Any) -> str: if isinstance(val, bool): @@ -335,8 +339,24 @@ class Conf: for m in mismatching: mlog.log(f'{m[0]:21}{m[1]:10}{m[2]:10}') +def has_option_flags(options): + if options.cmd_line_options: + return True + if options.A: + return True + if options.D: + return True + return False + +def is_print_only(options): + if has_option_flags(options): + return False + if options.clearcache: + return False + return True + def run_impl(options: CMDOptions, builddir: str) -> int: - print_only = not options.cmd_line_options and not options.clearcache + print_only = is_print_only(options) c = None try: c = Conf(builddir) @@ -347,8 +367,10 @@ def run_impl(options: CMDOptions, builddir: str) -> int: return 0 save = False - if options.cmd_line_options: - save = c.set_options(options.cmd_line_options) + if has_option_flags(options): + save |= c.set_options(options.cmd_line_options) + save |= c.coredata.create_sp_options(options.A) + save |= c.coredata.remove_sp_options(options.U) coredata.update_cmd_line_file(builddir, options) if options.clearcache: c.clear_cache() diff --git a/test cases/unit/123 persp options/meson.build b/test cases/unit/123 persp options/meson.build new file mode 100644 index 0000000..b751f1f --- /dev/null +++ b/test cases/unit/123 persp options/meson.build @@ -0,0 +1,22 @@ +project('toplevel', 'c') + +round = get_option('round') +opt = get_option('optimization') +if round == 1 + assert(opt == '1') +elif round == 2 + assert(opt == '1') +elif round == 3 + assert(opt == '3') +elif round == 4 + assert(opt == '3') +elif round == 5 + assert(opt == '3') +else + assert(false, 'Invalid round number') +endif + +executable('toplevel', 'toplevel.c') + +subproject('sub1') +subproject('sub2') diff --git a/test cases/unit/123 persp options/meson.options b/test cases/unit/123 persp options/meson.options new file mode 100644 index 0000000..2bfd08d --- /dev/null +++ b/test cases/unit/123 persp options/meson.options @@ -0,0 +1 @@ +option('round', type: 'integer', value: 1, description: 'The test round.') diff --git a/test cases/unit/123 persp options/subprojects/sub1/meson.build b/test cases/unit/123 persp options/subprojects/sub1/meson.build new file mode 100644 index 0000000..47cd5f4 --- /dev/null +++ b/test cases/unit/123 persp options/subprojects/sub1/meson.build @@ -0,0 +1,20 @@ +project('sub1', 'c') + +round = get_option('round') +opt = get_option('optimization') +if round == 1 + assert(opt == '1') +elif round == 2 + assert(opt == '1') +elif round == 3 + assert(opt == '1') +elif round == 4 + assert(opt == '1') +elif round == 5 + assert(opt == '2') +else + assert(false, 'Invalid round number') +endif + + +executable('sub1', 'sub1.c') diff --git a/test cases/unit/123 persp options/subprojects/sub1/meson.options b/test cases/unit/123 persp options/subprojects/sub1/meson.options new file mode 100644 index 0000000..ba5661a --- /dev/null +++ b/test cases/unit/123 persp options/subprojects/sub1/meson.options @@ -0,0 +1 @@ +option('round', type: 'integer', value: 1, description: 'The test round.', yield: true) diff --git a/test cases/unit/123 persp options/subprojects/sub1/sub1.c b/test cases/unit/123 persp options/subprojects/sub1/sub1.c new file mode 100644 index 0000000..4e4b873 --- /dev/null +++ b/test cases/unit/123 persp options/subprojects/sub1/sub1.c @@ -0,0 +1,6 @@ +#include<stdio.h> + +int main(void) { + printf("This is subproject 1.\n"); + return 0; +} diff --git a/test cases/unit/123 persp options/subprojects/sub2/meson.build b/test cases/unit/123 persp options/subprojects/sub2/meson.build new file mode 100644 index 0000000..774408f --- /dev/null +++ b/test cases/unit/123 persp options/subprojects/sub2/meson.build @@ -0,0 +1,19 @@ +project('sub2', 'c') + +round = get_option('round') +opt = get_option('optimization') +if round == 1 + assert(opt == '1') +elif round == 2 + assert(opt == '2') +elif round == 3 + assert(opt == '2') +elif round == 4 + assert(opt == '1') +elif round == 5 + assert(opt == '2') +else + assert(false, 'Invalid round number') +endif + +executable('sub2', 'sub2.c') diff --git a/test cases/unit/123 persp options/subprojects/sub2/meson.options b/test cases/unit/123 persp options/subprojects/sub2/meson.options new file mode 100644 index 0000000..ba5661a --- /dev/null +++ b/test cases/unit/123 persp options/subprojects/sub2/meson.options @@ -0,0 +1 @@ +option('round', type: 'integer', value: 1, description: 'The test round.', yield: true) diff --git a/test cases/unit/123 persp options/subprojects/sub2/sub2.c b/test cases/unit/123 persp options/subprojects/sub2/sub2.c new file mode 100644 index 0000000..4e4b873 --- /dev/null +++ b/test cases/unit/123 persp options/subprojects/sub2/sub2.c @@ -0,0 +1,6 @@ +#include<stdio.h> + +int main(void) { + printf("This is subproject 1.\n"); + return 0; +} diff --git a/test cases/unit/123 persp options/toplevel.c b/test cases/unit/123 persp options/toplevel.c new file mode 100644 index 0000000..5748d6b --- /dev/null +++ b/test cases/unit/123 persp options/toplevel.c @@ -0,0 +1,6 @@ +#include<stdio.h> + +int main(void) { + printf("This is the top level project.\n"); + return 0; +} diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index 16997e3..05799e8 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -1817,3 +1817,45 @@ class LinuxlikeTests(BasePlatformTests): self.assertIn('build t9-e1: c_LINKER t9-e1.p/main.c.o | libt9-s1.a libt9-s2.a libt9-s3.a\n', content) self.assertIn('build t12-e1: c_LINKER t12-e1.p/main.c.o | libt12-s1.a libt12-s2.a libt12-s3.a\n', content) self.assertIn('build t13-e1: c_LINKER t13-e1.p/main.c.o | libt12-s1.a libt13-s3.a\n', content) + + def check_has_flag(self, compdb, src, argument): + for i in compdb: + if src in i['file']: + self.assertIn(argument, i['command']) + return + self.assertTrue(False, f'Source {src} not found in compdb') + + def test_persp_options(self): + testdir = os.path.join(self.unit_test_dir, '123 persp options') + self.init(testdir, extra_args='-Doptimization=1') + compdb = self.get_compdb() + mainsrc = 'toplevel.c' + sub1src = 'sub1.c' + sub2src = 'sub2.c' + self.check_has_flag(compdb, mainsrc, '-O1') + self.check_has_flag(compdb, sub1src, '-O1') + self.check_has_flag(compdb, sub2src, '-O1') + + # Set subproject option to O2 + compdb = self.get_compdb() + self.check_has_flag(compdb, mainsrc, '-O1') + self.check_has_flag(compdb, sub1src, '-O1') + self.check_has_flag(compdb, sub2src, '-O2') + + # Set top level option to O3 + compdb = self.get_compdb() + self.check_has_flag(compdb, mainsrc, '-O3') + self.check_has_flag(compdb, sub1src, '-O1') + self.check_has_flag(compdb, sub2src, '-O2') + + # UnsetSet subproject + compdb = self.get_compdb() + self.check_has_flag(compdb, mainsrc, '-O3') + self.check_has_flag(compdb, sub1src, '-O1') + self.check_has_flag(compdb, sub2src, '-O1') + + # Set global value + compdb = self.get_compdb() + self.check_has_flag(compdb, mainsrc, '-O3') + self.check_has_flag(compdb, sub1src, '-O2') + self.check_has_flag(compdb, sub2src, '-O2') |