aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2020-02-17 00:08:37 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2020-02-22 06:49:34 +0530
commit3320e13d91d68f0a4898901c168b3981b76dec41 (patch)
tree46770e75260d290a4ae9114a5e9509b742b01016
parentb0061257c93da955397da05fb0783801f67cd54d (diff)
downloadmeson-3320e13d91d68f0a4898901c168b3981b76dec41.zip
meson-3320e13d91d68f0a4898901c168b3981b76dec41.tar.gz
meson-3320e13d91d68f0a4898901c168b3981b76dec41.tar.bz2
unit tests: Add a test for the symbolchecker script
When a source file for a library is changed without adding new extern symbols, only that library should be rebuilt. Nothing that uses it should be relinked. Along the way, also remove trailing `.` in all Ninja rule descriptions. It's very confusing to see messages like: ``` Linking target mylib.dll. ``` It's confusing that the period at the end of that is not part of the filename. Instead of removing that period manually in the tests (which feels wrong!) just don't print it at all.
-rw-r--r--mesonbuild/backend/ninjabackend.py46
-rwxr-xr-xrun_unittests.py34
2 files changed, 55 insertions, 25 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index d6387d5..5f5de0a 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -668,7 +668,7 @@ int dummy;
(srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
deps = self.unwrap_dep_list(target)
deps += self.get_custom_target_depend_files(target)
- desc = 'Generating {0} with a {1} command.'
+ desc = 'Generating {0} with a {1} command'
if target.build_always_stale:
deps.append('PHONY')
if target.depfile is None:
@@ -764,7 +764,7 @@ int dummy;
target_name = 'meson-{}'.format(self.build_run_target_name(target))
elem = NinjaBuildElement(self.all_outputs, target_name, 'CUSTOM_COMMAND', [])
elem.add_item('COMMAND', cmd)
- elem.add_item('description', 'Running external command %s.' % target.name)
+ elem.add_item('description', 'Running external command %s' % target.name)
elem.add_item('pool', 'console')
# Alias that runs the target defined above with the name the user specified
self.create_target_alias(target_name)
@@ -789,7 +789,7 @@ int dummy;
def generate_coverage_rules(self):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, [])
- e.add_item('description', 'Generates coverage reports.')
+ e.add_item('description', 'Generates coverage reports')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage')
@@ -798,21 +798,21 @@ int dummy;
def generate_coverage_legacy_rules(self):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--xml'])
- e.add_item('description', 'Generates XML coverage report.')
+ 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')
self.generate_coverage_command(e, ['--text'])
- e.add_item('description', 'Generates text coverage report.')
+ 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')
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--html'])
- e.add_item('description', 'Generates HTML coverage report.')
+ 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')
@@ -979,7 +979,7 @@ int dummy;
ofilename = os.path.join(self.get_target_private_dir(target), ofilebase)
elem = NinjaBuildElement(self.all_outputs, ofilename, "CUSTOM_COMMAND", rel_sourcefile)
elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename])
- elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile)
+ elem.add_item('DESC', 'Compiling resource %s' % rel_sourcefile)
self.add_build(elem)
deps.append(ofilename)
a = '-resource:' + ofilename
@@ -1073,7 +1073,7 @@ int dummy;
def generate_java_link(self):
rule = 'java_LINKER'
command = ['jar', '$ARGS']
- description = 'Creating JAR $out.'
+ description = 'Creating JAR $out'
self.add_rule(NinjaRule(rule, command, [], description))
def determine_dep_vapis(self, target):
@@ -1554,7 +1554,7 @@ int dummy;
cmdlist += static_linker.get_exelist()
cmdlist += ['$LINK_ARGS']
cmdlist += static_linker.get_output_args('$out')
- description = 'Linking static target $out.'
+ description = 'Linking static target $out'
if num_pools > 0:
pool = 'pool = link_pool'
else:
@@ -1576,7 +1576,7 @@ int dummy;
rule = '%s_LINKER%s' % (langname, self.get_rule_suffix(for_machine))
command = compiler.get_linker_exelist()
args = ['$ARGS'] + compiler.get_linker_output_args('$out') + ['$in', '$LINK_ARGS']
- description = 'Linking target $out.'
+ description = 'Linking target $out'
if num_pools > 0:
pool = 'pool = link_pool'
else:
@@ -1594,7 +1594,7 @@ int dummy;
'$out']
symrule = 'SHSYM'
symcmd = args + ['$CROSS']
- syndesc = 'Generating symbol file $out.'
+ syndesc = 'Generating symbol file $out'
synstat = 'restat = 1'
self.add_rule(NinjaRule(symrule, symcmd, [], syndesc, extra=synstat))
@@ -1602,7 +1602,7 @@ int dummy;
rule = self.compiler_to_rule_name(compiler)
invoc = [ninja_quote(i) for i in compiler.get_exelist()]
command = invoc + ['$ARGS', '$in']
- description = 'Compiling Java object $in.'
+ description = 'Compiling Java object $in'
self.add_rule(NinjaRule(rule, command, [], description))
def generate_cs_compile_rule(self, compiler):
@@ -1610,7 +1610,7 @@ int dummy;
invoc = [ninja_quote(i) for i in compiler.get_exelist()]
command = invoc
args = ['$ARGS', '$in']
- description = 'Compiling C Sharp target $out.'
+ description = 'Compiling C Sharp target $out'
self.add_rule(NinjaRule(rule, command, args, description,
rspable=mesonlib.is_windows()))
@@ -1618,14 +1618,14 @@ int dummy;
rule = self.compiler_to_rule_name(compiler)
invoc = [ninja_quote(i) for i in compiler.get_exelist()]
command = invoc + ['$ARGS', '$in']
- description = 'Compiling Vala source $in.'
+ description = 'Compiling Vala source $in'
self.add_rule(NinjaRule(rule, command, [], description, extra='restat = 1'))
def generate_rust_compile_rules(self, compiler):
rule = self.compiler_to_rule_name(compiler)
invoc = [ninja_quote(i) for i in compiler.get_exelist()]
command = invoc + ['$ARGS', '$in']
- description = 'Compiling Rust source $in.'
+ description = 'Compiling Rust source $in'
depfile = '$targetdep'
depstyle = 'gcc'
self.add_rule(NinjaRule(rule, command, [], description, deps=depstyle,
@@ -1640,7 +1640,7 @@ int dummy;
]
invoc = full_exe + [ninja_quote(i) for i in compiler.get_exelist()]
command = invoc + ['$ARGS', '$in']
- description = 'Compiling Swift source $in.'
+ description = 'Compiling Swift source $in'
self.add_rule(NinjaRule(rule, command, [], description))
def generate_fortran_dep_hack(self, crstr):
@@ -1660,7 +1660,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
rule = self.get_compiler_rule_name('llvm_ir', compiler.for_machine)
command = [ninja_quote(i) for i in compiler.get_exelist()]
args = ['$ARGS'] + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in']
- description = 'Compiling LLVM IR object $in.'
+ description = 'Compiling LLVM IR object $in'
self.add_rule(NinjaRule(rule, command, args, description,
rspable=compiler.can_linker_accept_rsp()))
self.created_llvm_ir_rule[compiler.for_machine] = True
@@ -1697,7 +1697,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
command = [ninja_quote(i) for i in compiler.get_exelist()]
args = ['$ARGS'] + quoted_depargs + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in']
- description = 'Compiling %s object $out.' % compiler.get_display_language()
+ description = 'Compiling %s object $out' % compiler.get_display_language()
if isinstance(compiler, VisualStudioLikeCompiler):
deps = 'msvc'
depfile = None
@@ -1724,7 +1724,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
else:
output = compiler.get_output_args('$out')
command = compiler.get_exelist() + ['$ARGS'] + quoted_depargs + output + compiler.get_compile_only_args() + ['$in']
- description = 'Precompiling header $in.'
+ description = 'Precompiling header $in'
if isinstance(compiler, VisualStudioLikeCompiler):
deps = 'msvc'
depfile = None
@@ -2628,7 +2628,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
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.')
+ 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')
@@ -2642,7 +2642,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
script_root = self.environment.get_script_dir()
clean_script = os.path.join(script_root, 'delwithsuffix.py')
gcno_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcno'])
- gcno_elem.add_item('description', 'Deleting gcno files.')
+ 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')
@@ -2651,7 +2651,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
script_root = self.environment.get_script_dir()
clean_script = os.path.join(script_root, 'delwithsuffix.py')
gcda_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcda'])
- gcda_elem.add_item('description', 'Deleting gcda files.')
+ 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')
@@ -2762,7 +2762,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY')
elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean'])
- elem.add_item('description', 'Cleaning.')
+ elem.add_item('description', 'Cleaning')
# Alias that runs the above-defined meson-clean target
self.create_target_alias('meson-clean')
diff --git a/run_unittests.py b/run_unittests.py
index 500b5eb..80c7cd0 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1756,6 +1756,33 @@ class BasePlatformTests(unittest.TestCase):
else:
raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name))
+ @staticmethod
+ def get_target_from_filename(filename):
+ base = os.path.splitext(filename)[0]
+ if base.startswith('lib'):
+ return base[3:]
+ return base
+
+ def assertBuildRelinkedOnlyTarget(self, target):
+ ret = self.build()
+ if self.backend is Backend.ninja:
+ linked_targets = []
+ for line in ret.split('\n'):
+ if 'Linking target' in line:
+ fname = line.rsplit('target ')[-1]
+ linked_targets.append(self.get_target_from_filename(fname))
+ self.assertEqual(linked_targets, [target])
+ elif self.backend is Backend.vs:
+ # Ensure that this target was rebuilt
+ linkre = re.compile(r'Link:\n [^\n]*link.exe[^\n]*/OUT:".\\([^"]*)"', flags=re.IGNORECASE)
+ matches = linkre.findall(ret)
+ self.assertEqual(len(matches), 1, msg=matches)
+ self.assertEqual(self.get_target_from_filename(matches[0]), target)
+ elif self.backend is Backend.xcode:
+ raise unittest.SkipTest('Please help us fix this test on the xcode backend')
+ else:
+ raise RuntimeError('Invalid backend: {!r}'.format(self.backend.name))
+
def assertPathExists(self, path):
m = 'Path {!r} should exist'.format(path)
self.assertTrue(os.path.exists(path), msg=m)
@@ -2572,6 +2599,9 @@ class AllPlatformTests(BasePlatformTests):
# Changing mtime of meson.build should not rebuild anything
self.utime(os.path.join(testdir, 'meson.build'))
self.assertReconfiguredBuildIsNoop()
+ # Changing mtime of libefile.c should rebuild the library, but not relink the executable
+ self.utime(os.path.join(testdir, 'libfile.c'))
+ self.assertBuildRelinkedOnlyTarget('mylib')
def test_source_changes_cause_rebuild(self):
'''
@@ -2586,7 +2616,7 @@ class AllPlatformTests(BasePlatformTests):
self.assertBuildIsNoop()
# Changing mtime of header.h should rebuild everything
self.utime(os.path.join(testdir, 'header.h'))
- self.assertRebuiltTarget('prog')
+ self.assertBuildRelinkedOnlyTarget('prog')
def test_custom_target_changes_cause_rebuild(self):
'''
@@ -2602,7 +2632,7 @@ class AllPlatformTests(BasePlatformTests):
# Changing mtime of these should rebuild everything
for f in ('input.def', 'makeheader.py', 'somefile.txt'):
self.utime(os.path.join(testdir, f))
- self.assertRebuiltTarget('prog')
+ self.assertBuildRelinkedOnlyTarget('prog')
def test_source_generator_program_cause_rebuild(self):
'''