ninja: Fix cleaning in various edge cases
We need to use target aliases for reserved target names and run targets to workaround a ninja bug: https://github.com/ninja-build/ninja/issues/828 Closes https://github.com/mesonbuild/meson/issues/1644
This commit is contained in:
parent
0c518a8077
commit
be4428005d
|
@ -138,6 +138,19 @@ class NinjaBackend(backends.Backend):
|
|||
self.fortran_deps = {}
|
||||
self.all_outputs = {}
|
||||
|
||||
def create_target_alias(self, to_target, outfile):
|
||||
# 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-'):
|
||||
m = 'Invalid usage of create_target_alias with {!r}'
|
||||
raise AssertionError(m.format(to_target))
|
||||
from_target = to_target[len('meson-'):]
|
||||
elem = NinjaBuildElement(self.all_outputs, from_target, 'phony', to_target)
|
||||
elem.write(outfile)
|
||||
|
||||
def detect_vs_dep_prefix(self, tempfilename):
|
||||
'''VS writes its dependency in a locale dependent format.
|
||||
Detect the search prefix to use.'''
|
||||
|
@ -537,7 +550,7 @@ int dummy;
|
|||
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
|
||||
else:
|
||||
raise AssertionError('Unreachable code in generate_run_target: ' + str(i))
|
||||
elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', [])
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-' + target.name, 'CUSTOM_COMMAND', [])
|
||||
cmd += [self.environment.get_source_dir(),
|
||||
self.environment.get_build_dir(),
|
||||
target.subdir,
|
||||
|
@ -573,10 +586,12 @@ int dummy;
|
|||
elem.add_item('description', 'Running external command %s.' % target.name)
|
||||
elem.add_item('pool', 'console')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above with the name the user specified
|
||||
self.create_target_alias('meson-' + target.name, outfile)
|
||||
self.processed_targets[target.name + target.type_suffix()] = True
|
||||
|
||||
def generate_coverage_rules(self, outfile):
|
||||
e = NinjaBuildElement(self.all_outputs, 'coverage', 'CUSTOM_COMMAND', 'PHONY')
|
||||
e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY')
|
||||
e.add_item('COMMAND', [sys.executable,
|
||||
self.environment.get_build_command(),
|
||||
'--internal', 'coverage',
|
||||
|
@ -585,6 +600,8 @@ int dummy;
|
|||
self.environment.get_log_dir()])
|
||||
e.add_item('description', 'Generates coverage reports.')
|
||||
e.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-coverage', outfile)
|
||||
self.generate_coverage_legacy_rules(outfile)
|
||||
|
||||
def generate_coverage_legacy_rules(self, outfile):
|
||||
|
@ -592,22 +609,28 @@ int dummy;
|
|||
added_rule = False
|
||||
if gcovr_exe:
|
||||
added_rule = True
|
||||
elem = NinjaBuildElement(self.all_outputs, 'coverage-xml', 'CUSTOM_COMMAND', '')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', '')
|
||||
elem.add_item('COMMAND', [gcovr_exe, '-x', '-r', self.environment.get_source_dir(),
|
||||
'-o', os.path.join(self.environment.get_log_dir(), 'coverage.xml')])
|
||||
elem.add_item('DESC', 'Generating XML coverage report.')
|
||||
elem.write(outfile)
|
||||
elem = NinjaBuildElement(self.all_outputs, 'coverage-text', 'CUSTOM_COMMAND', '')
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-coverage-xml', outfile)
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', '')
|
||||
elem.add_item('COMMAND', [gcovr_exe, '-r', self.environment.get_source_dir(),
|
||||
'-o', os.path.join(self.environment.get_log_dir(), 'coverage.txt')])
|
||||
elem.add_item('DESC', 'Generating text coverage report.')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-coverage-text', outfile)
|
||||
if lcov_exe and genhtml_exe:
|
||||
added_rule = True
|
||||
htmloutdir = os.path.join(self.environment.get_log_dir(), 'coveragereport')
|
||||
covinfo = os.path.join(self.environment.get_log_dir(), 'coverage.info')
|
||||
phony_elem = NinjaBuildElement(self.all_outputs, 'coverage-html', 'phony', os.path.join(htmloutdir, 'index.html'))
|
||||
phony_elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-coverage-html', outfile)
|
||||
elem = NinjaBuildElement(self.all_outputs, os.path.join(htmloutdir, 'index.html'), 'CUSTOM_COMMAND', '')
|
||||
command = [lcov_exe, '--directory', self.environment.get_build_dir(),
|
||||
'--capture', '--output-file', covinfo, '--no-checksum',
|
||||
|
@ -636,7 +659,7 @@ int dummy;
|
|||
self.environment.get_prefix(),
|
||||
strip_bin,
|
||||
get_meson_script(self.environment, 'mesonintrospect'))
|
||||
elem = NinjaBuildElement(self.all_outputs, 'install', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem.add_dep('all')
|
||||
elem.add_item('DESC', 'Installing files.')
|
||||
elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file])
|
||||
|
@ -649,6 +672,8 @@ int dummy;
|
|||
self.generate_custom_install_script(d)
|
||||
self.generate_subdir_install(d)
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-install', outfile)
|
||||
|
||||
with open(install_data_file, 'wb') as ofile:
|
||||
pickle.dump(d, ofile)
|
||||
|
@ -822,20 +847,24 @@ int dummy;
|
|||
cmd += ['--no-stdsplit']
|
||||
if self.environment.coredata.get_builtin_option('errorlogs'):
|
||||
cmd += ['--print-errorlogs']
|
||||
elem = NinjaBuildElement(self.all_outputs, 'test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||||
elem.add_item('COMMAND', cmd)
|
||||
elem.add_item('DESC', 'Running all tests.')
|
||||
elem.add_item('pool', 'console')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the above-defined meson-test target
|
||||
self.create_target_alias('meson-test', outfile)
|
||||
|
||||
# And then benchmarks.
|
||||
cmd = [sys.executable, '-u', self.environment.get_build_command(), 'test', '--benchmark', '--logbase',
|
||||
'benchmarklog', '--num-processes=1', '--no-rebuild']
|
||||
elem = NinjaBuildElement(self.all_outputs, 'benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||||
elem.add_item('COMMAND', cmd)
|
||||
elem.add_item('DESC', 'Running benchmark suite.')
|
||||
elem.add_item('pool', 'console')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the above-defined meson-benchmark target
|
||||
self.create_target_alias('meson-benchmark', outfile)
|
||||
|
||||
def generate_rules(self, outfile):
|
||||
outfile.write('# Rules for compiling.\n\n')
|
||||
|
@ -2453,7 +2482,7 @@ rule FORTRAN_DEP_HACK
|
|||
mlog.debug("Library versioning disabled because we do not have symlink creation privileges.")
|
||||
|
||||
def generate_custom_target_clean(self, outfile, trees):
|
||||
e = NinjaBuildElement(self.all_outputs, 'clean-ctlist', 'CUSTOM_COMMAND', 'PHONY')
|
||||
e = NinjaBuildElement(self.all_outputs, 'meson-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', [sys.executable,
|
||||
|
@ -2461,25 +2490,31 @@ rule FORTRAN_DEP_HACK
|
|||
'--internal', 'cleantrees', d_file])
|
||||
e.add_item('description', 'Cleaning custom target directories.')
|
||||
e.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-clean-ctlist', outfile)
|
||||
# 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, outfile):
|
||||
gcno_elem = NinjaBuildElement(self.all_outputs, 'clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
|
||||
script_root = self.environment.get_script_dir()
|
||||
clean_script = os.path.join(script_root, 'delwithsuffix.py')
|
||||
gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno'])
|
||||
gcno_elem.add_item('description', 'Deleting gcno files.')
|
||||
gcno_elem.write(outfile)
|
||||
gcno_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
|
||||
script_root = self.environment.get_script_dir()
|
||||
clean_script = os.path.join(script_root, 'delwithsuffix.py')
|
||||
gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno'])
|
||||
gcno_elem.add_item('description', 'Deleting gcno files.')
|
||||
gcno_elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-clean-gcno', outfile)
|
||||
|
||||
gcda_elem = NinjaBuildElement(self.all_outputs, 'clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
|
||||
script_root = self.environment.get_script_dir()
|
||||
clean_script = os.path.join(script_root, 'delwithsuffix.py')
|
||||
gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda'])
|
||||
gcda_elem.add_item('description', 'Deleting gcda files.')
|
||||
gcda_elem.write(outfile)
|
||||
gcda_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
|
||||
script_root = self.environment.get_script_dir()
|
||||
clean_script = os.path.join(script_root, 'delwithsuffix.py')
|
||||
gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda'])
|
||||
gcda_elem.add_item('description', 'Deleting gcda files.')
|
||||
gcda_elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-clean-gcda', outfile)
|
||||
|
||||
def get_user_option_args(self):
|
||||
cmds = []
|
||||
|
@ -2491,7 +2526,7 @@ rule FORTRAN_DEP_HACK
|
|||
return sorted(cmds)
|
||||
|
||||
def generate_dist(self, outfile):
|
||||
elem = NinjaBuildElement(self.all_outputs, 'dist', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem.add_item('DESC', 'Creating source packages')
|
||||
elem.add_item('COMMAND', [sys.executable,
|
||||
self.environment.get_build_command(),
|
||||
|
@ -2502,22 +2537,28 @@ rule FORTRAN_DEP_HACK
|
|||
self.environment.get_build_command()])
|
||||
elem.add_item('pool', 'console')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-dist', outfile)
|
||||
|
||||
# For things like scan-build and other helper tools we might have.
|
||||
def generate_utils(self, outfile):
|
||||
cmd = [sys.executable, self.environment.get_build_command(),
|
||||
'--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir,
|
||||
sys.executable, self.environment.get_build_command()] + self.get_user_option_args()
|
||||
elem = NinjaBuildElement(self.all_outputs, 'scan-build', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-scan-build', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem.add_item('COMMAND', cmd)
|
||||
elem.add_item('pool', 'console')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-scan-build', outfile)
|
||||
cmd = [sys.executable, self.environment.get_build_command(),
|
||||
'--internal', 'uninstall']
|
||||
elem = NinjaBuildElement(self.all_outputs, 'uninstall', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-uninstall', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem.add_item('COMMAND', cmd)
|
||||
elem.add_item('pool', 'console')
|
||||
elem.write(outfile)
|
||||
# Alias that runs the target defined above
|
||||
self.create_target_alias('meson-uninstall', outfile)
|
||||
|
||||
def generate_ending(self, outfile):
|
||||
targetlist = []
|
||||
|
@ -2535,9 +2576,11 @@ rule FORTRAN_DEP_HACK
|
|||
ninja_command = environment.detect_ninja()
|
||||
if ninja_command is None:
|
||||
raise MesonException('Could not detect Ninja v1.6 or newer')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'clean', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY')
|
||||
elem.add_item('COMMAND', [ninja_command, '-t', 'clean'])
|
||||
elem.add_item('description', 'Cleaning.')
|
||||
# Alias that runs the above-defined meson-clean target
|
||||
self.create_target_alias('meson-clean', outfile)
|
||||
|
||||
# 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
|
||||
|
|
|
@ -2742,9 +2742,12 @@ different subdirectory.
|
|||
def add_target(self, name, tobj):
|
||||
if name == '':
|
||||
raise InterpreterException('Target name must not be empty.')
|
||||
if name.startswith('meson-'):
|
||||
raise InvalidArguments("Target names starting with 'meson-' are reserved "
|
||||
"for Meson's internal use. Please rename.")
|
||||
if name in coredata.forbidden_target_names:
|
||||
raise InvalidArguments('Target name "%s" is reserved for Meson\'s internal use. Please rename.'
|
||||
% name)
|
||||
raise InvalidArguments("Target name '%s' is reserved for Meson's "
|
||||
"internal use. Please rename." % name)
|
||||
# To permit an executable and a shared library to have the
|
||||
# same name, such as "foo.exe" and "libfoo.a".
|
||||
idname = tobj.get_id()
|
||||
|
|
Loading…
Reference in New Issue