diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2020-02-17 00:08:37 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek@centricular.com> | 2020-02-22 06:49:34 +0530 |
commit | 3320e13d91d68f0a4898901c168b3981b76dec41 (patch) | |
tree | 46770e75260d290a4ae9114a5e9509b742b01016 | |
parent | b0061257c93da955397da05fb0783801f67cd54d (diff) | |
download | meson-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.py | 46 | ||||
-rwxr-xr-x | run_unittests.py | 34 |
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): ''' |