From 47d071a34f1e1539b1b354cfda309dac1b905232 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Oct 2020 15:48:32 -0700 Subject: [PATCH] interpreter: store correct files for project regeneration Right now sub-sub projects are not correctly registered, because we don't have a way to pass up past the first level of subproject. This patch changes that by making the build_Def_files as defined in the Interpreter initializer accurate for translated dependencies, ie, cmake dependencies won't define a dependency on a non-existent meson.build. This means that it can always add the subi.build_def_files because they are always accurate. --- mesonbuild/interpreter.py | 24 ++++++++++++++----- run_unittests.py | 14 +++++++++++ .../main.c | 3 +++ .../meson.build | 6 +++++ .../subprojects/sub1/meson.build | 4 ++++ .../subprojects/sub2/CMakeLists.txt | 1 + 6 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 test cases/unit/85 nested subproject regenerate depends/main.c create mode 100644 test cases/unit/85 nested subproject regenerate depends/meson.build create mode 100644 test cases/unit/85 nested subproject regenerate depends/subprojects/sub1/meson.build create mode 100644 test cases/unit/85 nested subproject regenerate depends/subprojects/sub2/CMakeLists.txt diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 6222f97a7..28ac74f31 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2383,6 +2383,7 @@ class Interpreter(InterpreterBase): default_project_options: T.Optional[T.Dict[str, str]] = None, mock: bool = False, ast: T.Optional[mparser.CodeBlockNode] = None, + is_translated: bool = False, ) -> None: super().__init__(build.environment.get_source_dir(), subdir, subproject) self.an_unpicklable_object = mesonlib.an_unpicklable_object @@ -2421,8 +2422,16 @@ class Interpreter(InterpreterBase): self.default_project_options = {} self.project_default_options = {} self.build_func_dict() + # build_def_files needs to be defined before parse_project is called - self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] + # + # For non-meson subprojects, we'll be using the ast. Even if it does + # exist we don't want to add a dependency on it, it's autogenerated + # from the actual build files, and is just for reference. + self.build_def_files = [] + build_filename = os.path.join(self.subdir, environment.build_filename) + if not is_translated: + self.build_def_files.append(build_filename) if not mock: self.parse_project() self._redetect_machines() @@ -2941,11 +2950,14 @@ external dependencies (including libraries) must go to "dependencies".''') return self.disabled_subproject(subp_name, exception=e) raise e - def _do_subproject_meson(self, subp_name, subdir, default_options, kwargs, ast=None, build_def_files=None): + def _do_subproject_meson(self, subp_name: str, subdir: str, default_options, kwargs, + ast: T.Optional[mparser.CodeBlockNode] = None, + build_def_files: T.Optional[T.List[str]] = None, + is_translated: bool = False) -> SubprojectHolder: with mlog.nested(): new_build = self.build.copy() subi = Interpreter(new_build, self.backend, subp_name, subdir, self.subproject_dir, - self.modules, default_options, ast=ast) + self.modules, default_options, ast=ast, is_translated=is_translated) subi.subprojects = self.subprojects subi.subproject_stack = self.subproject_stack + [subp_name] @@ -2971,8 +2983,8 @@ external dependencies (including libraries) must go to "dependencies".''') # Duplicates are possible when subproject uses files from project root if build_def_files: self.build_def_files = list(set(self.build_def_files + build_def_files)) - else: - self.build_def_files = list(set(self.build_def_files + subi.build_def_files)) + # We always need the subi.build_def_files, to propgate sub-sub-projects + self.build_def_files = list(set(self.build_def_files + subi.build_def_files)) self.build.merge(subi.build) self.build.subprojects[subp_name] = subi.project_version self.summary.update(subi.summary) @@ -3016,7 +3028,7 @@ external dependencies (including libraries) must go to "dependencies".''') mlog.cmd_ci_include(meson_filename) mlog.log() - result = self._do_subproject_meson(subp_name, subdir, default_options, kwargs, ast, cm_int.bs_files) + result = self._do_subproject_meson(subp_name, subdir, default_options, kwargs, ast, cm_int.bs_files, is_translated=True) result.cm_interpreter = cm_int mlog.log() diff --git a/run_unittests.py b/run_unittests.py index c7c6ba265..85292d137 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -5247,6 +5247,20 @@ recommended as it is not supported on some platforms''') wrap = PackageDefinition(redirect_wrap) self.assertEqual(wrap.get('url'), 'http://invalid') + @skip_if_no_cmake + def test_nested_cmake_rebuild(self) -> None: + # This checks a bug where if a non-meson project is used as a third + # level (or deeper) subproject it doesn't cause a rebuild if the build + # files for that project are changed + testdir = os.path.join(self.unit_test_dir, '85 nested subproject regenerate depends') + cmakefile = Path(testdir) / 'subprojects' / 'sub2' / 'CMakeLists.txt' + self.init(testdir) + self.build() + with cmakefile.open('a') as f: + os.utime(str(cmakefile)) + self.assertReconfiguredBuildIsNoop() + + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically diff --git a/test cases/unit/85 nested subproject regenerate depends/main.c b/test cases/unit/85 nested subproject regenerate depends/main.c new file mode 100644 index 000000000..9b6bdc2ec --- /dev/null +++ b/test cases/unit/85 nested subproject regenerate depends/main.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/test cases/unit/85 nested subproject regenerate depends/meson.build b/test cases/unit/85 nested subproject regenerate depends/meson.build new file mode 100644 index 000000000..569888164 --- /dev/null +++ b/test cases/unit/85 nested subproject regenerate depends/meson.build @@ -0,0 +1,6 @@ +project('nested subproject regenerate depends', 'c') + +s = subproject('sub1') + +# This is needed to make msbuild noop check work correctly +executable('exe', 'main.c') diff --git a/test cases/unit/85 nested subproject regenerate depends/subprojects/sub1/meson.build b/test cases/unit/85 nested subproject regenerate depends/subprojects/sub1/meson.build new file mode 100644 index 000000000..a31db4ade --- /dev/null +++ b/test cases/unit/85 nested subproject regenerate depends/subprojects/sub1/meson.build @@ -0,0 +1,4 @@ +project('sub1') + +cmake = import('cmake') +cmake.subproject('sub2') diff --git a/test cases/unit/85 nested subproject regenerate depends/subprojects/sub2/CMakeLists.txt b/test cases/unit/85 nested subproject regenerate depends/subprojects/sub2/CMakeLists.txt new file mode 100644 index 000000000..f91473a6a --- /dev/null +++ b/test cases/unit/85 nested subproject regenerate depends/subprojects/sub2/CMakeLists.txt @@ -0,0 +1 @@ +project(sub2)