From edccb11f015d51a1a45a936751a504f01641e928 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sun, 28 Oct 2018 11:51:13 -0400 Subject: Rollback if an optional subproject fails If a subproject is not required and fails during its configuration, the parent project continues, but should not include any target or state set by the failed subproject. This fix ninja still trying to build targets generated by subprojects before they fail in their configuration. The 'build' object is now per-interpreter instead of being global. Once a subproject interpreter succeed, values from its 'build' object are merged back into its parent 'build' object. --- mesonbuild/build.py | 13 +++++++++++++ mesonbuild/interpreter.py | 4 +++- test cases/common/205 broken subproject/meson.build | 2 ++ .../205 broken subproject/subprojects/broken/broken.c | 1 + .../205 broken subproject/subprojects/broken/meson.build | 4 ++++ 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test cases/common/205 broken subproject/meson.build create mode 100644 test cases/common/205 broken subproject/subprojects/broken/broken.c create mode 100644 test cases/common/205 broken subproject/subprojects/broken/meson.build diff --git a/mesonbuild/build.py b/mesonbuild/build.py index f2a6d9c..df67c8e 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -138,6 +138,19 @@ class Build: self.find_overrides = {} self.searched_programs = set() # The list of all programs that have been searched for. + def copy(self): + other = Build(self.environment) + for k, v in self.__dict__.items(): + if isinstance(v, (list, dict, set, OrderedDict)): + other.__dict__[k] = v.copy() + else: + other.__dict__[k] = v + return other + + def merge(self, other): + for k, v in other.__dict__.items(): + self.__dict__[k] = v + def add_compiler(self, compiler): if self.static_linker is None and compiler.needs_static_linker(): self.static_linker = self.environment.detect_static_linker(compiler) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 66f7f02..8717a83 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2286,7 +2286,8 @@ external dependencies (including libraries) must go to "dependencies".''') with mlog.nested(): try: mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n') - subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir, + new_build = self.build.copy() + subi = Interpreter(new_build, self.backend, dirname, subdir, self.subproject_dir, self.modules, default_options) subi.subprojects = self.subprojects @@ -2312,6 +2313,7 @@ external dependencies (including libraries) must go to "dependencies".''') self.subprojects.update(subi.subprojects) self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname) self.build_def_files += subi.build_def_files + self.build.merge(subi.build) return self.subprojects[dirname] def get_option_internal(self, optname): diff --git a/test cases/common/205 broken subproject/meson.build b/test cases/common/205 broken subproject/meson.build new file mode 100644 index 0000000..e3a6cae --- /dev/null +++ b/test cases/common/205 broken subproject/meson.build @@ -0,0 +1,2 @@ +project('test broken subproject') +subproject('broken', required : false) diff --git a/test cases/common/205 broken subproject/subprojects/broken/broken.c b/test cases/common/205 broken subproject/subprojects/broken/broken.c new file mode 100644 index 0000000..a9fc4b1 --- /dev/null +++ b/test cases/common/205 broken subproject/subprojects/broken/broken.c @@ -0,0 +1 @@ +#error This must not compile diff --git a/test cases/common/205 broken subproject/subprojects/broken/meson.build b/test cases/common/205 broken subproject/subprojects/broken/meson.build new file mode 100644 index 0000000..2d64fde --- /dev/null +++ b/test cases/common/205 broken subproject/subprojects/broken/meson.build @@ -0,0 +1,4 @@ +project('broken', 'c') + +executable('app', 'broken.c') +assert(false, 'This subproject must fail') -- cgit v1.1