diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 35c14ee35..c6f82e3e1 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -434,18 +434,23 @@ class NinjaBackend(backends.Backend): self.introspection_data = {} self.created_llvm_ir_rule = PerMachine(False, False) - def create_target_alias(self, to_target): - # We need to use aliases for targets that might be used as directory - # names to workaround a Ninja bug that breaks `ninja -t clean`. - # This is used for 'reserved' targets such as 'test', 'install', - # 'benchmark', etc, and also for RunTargets. - # https://github.com/mesonbuild/meson/issues/1644 - if not to_target.startswith('meson-'): - raise AssertionError(f'Invalid usage of create_target_alias with {to_target!r}') - from_target = to_target[len('meson-'):] - elem = NinjaBuildElement(self.all_outputs, from_target, 'phony', to_target) + def create_phony_target(self, all_outputs, dummy_outfile, rulename, phony_infilename, implicit_outs=None): + ''' + We need to use aliases for targets that might be used as directory + names to workaround a Ninja bug that breaks `ninja -t clean`. + This is used for 'reserved' targets such as 'test', 'install', + 'benchmark', etc, and also for RunTargets. + https://github.com/mesonbuild/meson/issues/1644 + ''' + if dummy_outfile.startswith('meson-'): + raise AssertionError(f'Invalid usage of create_phony_target with {dummy_outfile!r}') + + to_name = f'meson-{dummy_outfile}' + elem = NinjaBuildElement(all_outputs, dummy_outfile, 'phony', to_name) self.add_build(elem) + return NinjaBuildElement(all_outputs, to_name, rulename, phony_infilename, implicit_outs) + def detect_vs_dep_prefix(self, tempfilename): '''VS writes its dependency in a locale dependent format. Detect the search prefix to use.''' @@ -1050,13 +1055,10 @@ class NinjaBackend(backends.Backend): env=target_env, verbose=True) cmd_type = f' (wrapped by meson {reason})' if reason else '' - internal_target_name = f'meson-{target_name}' - elem = NinjaBuildElement(self.all_outputs, internal_target_name, 'CUSTOM_COMMAND', []) + elem = self.create_phony_target(self.all_outputs, target_name, 'CUSTOM_COMMAND', []) elem.add_item('COMMAND', meson_exe_cmd) elem.add_item('description', f'Running external command {target.name}{cmd_type}') elem.add_item('pool', 'console') - # Alias that runs the target defined above with the name the user specified - self.create_target_alias(internal_target_name) deps = self.unwrap_dep_list(target) deps += self.get_custom_target_depend_files(target) elem.add_dep(deps) @@ -1084,55 +1086,43 @@ class NinjaBackend(backends.Backend): (['--use_llvm_cov'] if use_llvm_cov else [])) def generate_coverage_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]): - e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY') + e = self.create_phony_target(self.all_outputs, 'coverage', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, []) e.add_item('description', 'Generates coverage reports') self.add_build(e) - # Alias that runs the target defined above - self.create_target_alias('meson-coverage') self.generate_coverage_legacy_rules(gcovr_exe, gcovr_version) def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]): - e = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'CUSTOM_COMMAND', 'PHONY') + e = self.create_phony_target(self.all_outputs, 'coverage-html', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--html']) e.add_item('description', 'Generates HTML coverage report') self.add_build(e) - # Alias that runs the target defined above - self.create_target_alias('meson-coverage-html') if gcovr_exe: - e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY') + e = self.create_phony_target(self.all_outputs, 'coverage-xml', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--xml']) e.add_item('description', 'Generates XML coverage report') self.add_build(e) - # Alias that runs the target defined above - self.create_target_alias('meson-coverage-xml') - e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY') + e = self.create_phony_target(self.all_outputs, 'coverage-text', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--text']) e.add_item('description', 'Generates text coverage report') self.add_build(e) - # Alias that runs the target defined above - self.create_target_alias('meson-coverage-text') if mesonlib.version_compare(gcovr_version, '>=4.2'): - e = NinjaBuildElement(self.all_outputs, 'meson-coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY') + e = self.create_phony_target(self.all_outputs, 'coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY') self.generate_coverage_command(e, ['--sonarqube']) e.add_item('description', 'Generates Sonarqube XML coverage report') self.add_build(e) - # Alias that runs the target defined above - self.create_target_alias('meson-coverage-sonarqube') def generate_install(self): self.create_install_data_files() - elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, 'install', 'CUSTOM_COMMAND', 'PHONY') elem.add_dep('all') elem.add_item('DESC', 'Installing files.') elem.add_item('COMMAND', self.environment.get_build_command() + ['install', '--no-rebuild']) elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the target defined above - self.create_target_alias('meson-install') def generate_tests(self): self.serialize_tests() @@ -1141,25 +1131,21 @@ class NinjaBackend(backends.Backend): cmd += ['--no-stdsplit'] if self.environment.coredata.get_option(OptionKey('errorlogs')): cmd += ['--print-errorlogs'] - elem = NinjaBuildElement(self.all_outputs, 'meson-test', 'CUSTOM_COMMAND', ['all', 'PHONY']) + elem = self.create_phony_target(self.all_outputs, 'test', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running all tests.') elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the above-defined meson-test target - self.create_target_alias('meson-test') # And then benchmarks. cmd = self.environment.get_build_command(True) + [ 'test', '--benchmark', '--logbase', 'benchmarklog', '--num-processes=1', '--no-rebuild'] - elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) + elem = self.create_phony_target(self.all_outputs, 'benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running benchmark suite.') elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the above-defined meson-benchmark target - self.create_target_alias('meson-benchmark') def generate_rules(self): self.rules = [] @@ -3170,33 +3156,27 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) mlog.debug("Library versioning disabled because we do not have symlink creation privileges.") def generate_custom_target_clean(self, trees: T.List[str]) -> str: - e = NinjaBuildElement(self.all_outputs, 'meson-clean-ctlist', 'CUSTOM_COMMAND', 'PHONY') + e = self.create_phony_target(self.all_outputs, 'clean-ctlist', 'CUSTOM_COMMAND', 'PHONY') d = CleanTrees(self.environment.get_build_dir(), trees) d_file = os.path.join(self.environment.get_scratch_dir(), 'cleantrees.dat') e.add_item('COMMAND', self.environment.get_build_command() + ['--internal', 'cleantrees', d_file]) e.add_item('description', 'Cleaning custom target directories') self.add_build(e) - # Alias that runs the target defined above - self.create_target_alias('meson-clean-ctlist') # Write out the data file passed to the script with open(d_file, 'wb') as ofile: pickle.dump(d, ofile) return 'clean-ctlist' def generate_gcov_clean(self): - gcno_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcno', 'CUSTOM_COMMAND', 'PHONY') + gcno_elem = self.create_phony_target(self.all_outputs, 'clean-gcno', 'CUSTOM_COMMAND', 'PHONY') gcno_elem.add_item('COMMAND', mesonlib.get_meson_command() + ['--internal', 'delwithsuffix', '.', 'gcno']) gcno_elem.add_item('description', 'Deleting gcno files') self.add_build(gcno_elem) - # Alias that runs the target defined above - self.create_target_alias('meson-clean-gcno') - gcda_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcda', 'CUSTOM_COMMAND', 'PHONY') + gcda_elem = self.create_phony_target(self.all_outputs, 'clean-gcda', 'CUSTOM_COMMAND', 'PHONY') gcda_elem.add_item('COMMAND', mesonlib.get_meson_command() + ['--internal', 'delwithsuffix', '.', 'gcda']) gcda_elem.add_item('description', 'Deleting gcda files') self.add_build(gcda_elem) - # Alias that runs the target defined above - self.create_target_alias('meson-clean-gcda') def get_user_option_args(self): cmds = [] @@ -3209,13 +3189,11 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) return sorted(cmds) def generate_dist(self): - elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, 'dist', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('DESC', 'Creating source packages') elem.add_item('COMMAND', self.environment.get_build_command() + ['dist']) elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the target defined above - self.create_target_alias('meson-dist') def generate_scanbuild(self): if not environment.detect_scanbuild(): @@ -3225,12 +3203,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) cmd = self.environment.get_build_command() + \ ['--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir] + \ self.environment.get_build_command() + self.get_user_option_args() - elem = NinjaBuildElement(self.all_outputs, 'meson-scan-build', 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, 'scan-build', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the target defined above - self.create_target_alias('meson-scan-build') def generate_clangtool(self, name, extra_arg=None): target_name = 'clang-' + name @@ -3248,11 +3224,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) cmd = self.environment.get_build_command() + \ ['--internal', 'clang' + name, self.environment.source_dir, self.environment.build_dir] + \ extra_args - elem = NinjaBuildElement(self.all_outputs, 'meson-' + target_name, 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) - self.create_target_alias('meson-' + target_name) def generate_clangformat(self): if not environment.detect_clangformat(): @@ -3276,12 +3251,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) return cmd = self.environment.get_build_command() + \ ['--internal', 'tags', tool, self.environment.source_dir] - elem = NinjaBuildElement(self.all_outputs, 'meson-' + target_name, 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, target_name, 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the target defined above - self.create_target_alias('meson-' + target_name) # For things like scan-build and other helper tools we might have. def generate_utils(self): @@ -3292,12 +3265,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.generate_tags('ctags', 'ctags') self.generate_tags('cscope', 'cscope') cmd = self.environment.get_build_command() + ['--internal', 'uninstall'] - elem = NinjaBuildElement(self.all_outputs, 'meson-uninstall', 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, 'uninstall', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') self.add_build(elem) - # Alias that runs the target defined above - self.create_target_alias('meson-uninstall') def generate_ending(self): targetlist = [] @@ -3309,11 +3280,9 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist) self.add_build(elem) - elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY') + elem = self.create_phony_target(self.all_outputs, 'clean', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', self.ninja_command + ['-t', 'clean']) elem.add_item('description', 'Cleaning') - # Alias that runs the above-defined meson-clean target - self.create_target_alias('meson-clean') # If we have custom targets in this project, add all their outputs to # the list that is passed to the `cleantrees.py` script. The script