diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2017-02-03 17:21:08 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek@centricular.com> | 2017-02-18 02:38:54 +0530 |
commit | a14eba27a9d68fa128dbcb9d4f4fd4d4a4e70f09 (patch) | |
tree | 487aa9bfcd4a96d41d819452ccd68d2d4af4d41c | |
parent | 217eae4011fa7693f6538d4240009fca7722d756 (diff) | |
download | meson-a14eba27a9d68fa128dbcb9d4f4fd4d4a4e70f09.zip meson-a14eba27a9d68fa128dbcb9d4f4fd4d4a4e70f09.tar.gz meson-a14eba27a9d68fa128dbcb9d4f4fd4d4a4e70f09.tar.bz2 |
ninja: Delete output static lib before calling `ar`
Otherwise if the list of sources changes on reconfigure after building,
the static library will contain both the old and new objects.
Closes https://github.com/mesonbuild/meson/issues/1355
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 14 | ||||
-rwxr-xr-x | run_unittests.py | 41 | ||||
-rw-r--r-- | test cases/common/3 static/libfile2.c | 3 | ||||
-rw-r--r-- | test cases/common/3 static/meson.build | 3 | ||||
-rw-r--r-- | test cases/common/3 static/meson_options.txt | 1 |
5 files changed, 58 insertions, 4 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index a22e0ab..27e1e9a 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -30,9 +30,11 @@ from collections import OrderedDict if mesonlib.is_windows(): quote_char = '"' execute_wrapper = 'cmd /c' + rmfile_prefix = 'del /f /s /q {} &&' else: quote_char = "'" execute_wrapper = '' + rmfile_prefix = 'rm -f {} &&' def ninja_quote(text): return text.replace(' ', '$ ').replace(':', '$:') @@ -1238,10 +1240,16 @@ int dummy; ''' else: command_template = ' command = {executable} $LINK_ARGS {output_args} $in\n' + cmdlist = [] + if isinstance(static_linker, compilers.ArLinker): + # `ar` has no options to overwrite archives. It always appends, + # which is never what we want. Delete an existing library first if + # it exists. https://github.com/mesonbuild/meson/issues/1355 + cmdlist = [execute_wrapper, rmfile_prefix.format('$out')] + cmdlist += static_linker.get_exelist() command = command_template.format( - executable=' '.join(static_linker.get_exelist()), - output_args=' '.join(static_linker.get_output_args('$out')) - ) + executable=' '.join(cmdlist), + output_args=' '.join(static_linker.get_output_args('$out'))) description = ' description = Static linking library $out\n\n' outfile.write(rule) outfile.write(command) diff --git a/run_unittests.py b/run_unittests.py index 115a8a7..0a53733 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -328,6 +328,47 @@ class AllPlatformTests(BasePlatformTests): self.init(testdir) self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False) + def test_static_library_overwrite(self): + ''' + Tests that static libraries are never appended to, always overwritten. + Has to be a unit test because this involves building a project, + reconfiguring, and building it again so that `ar` is run twice on the + same static library. + https://github.com/mesonbuild/meson/issues/1355 + ''' + testdir = os.path.join(self.common_test_dir, '3 static') + env = Environment(testdir, self.builddir, self.meson_command, + get_fake_options(self.prefix), []) + cc = env.detect_c_compiler(False) + static_linker = env.detect_static_linker(cc) + if not isinstance(static_linker, mesonbuild.compilers.ArLinker): + raise unittest.SkipTest('static linker is not `ar`') + # Configure + self.init(testdir) + # Get name of static library + targets = self.introspect('--targets') + self.assertEqual(len(targets), 1) + libname = targets[0]['filename'] + # Build and get contents of static library + self.build() + before = self._run(['ar', 't', os.path.join(self.builddir, libname)], + return_output=True).split() + # Filter out non-object-file contents + before = [f for f in before if f.endswith((b'.o', b'.obj'))] + # Static library should contain only one object + self.assertEqual(len(before), 1, msg=before) + # Change the source to be built into the static library + self.setconf('-Dsource=libfile2.c') + self.build() + after = self._run(['ar', 't', os.path.join(self.builddir, libname)], + return_output=True).split() + # Filter out non-object-file contents + after = [f for f in after if f.endswith((b'.o', b'.obj'))] + # Static library should contain only one object + self.assertEqual(len(after), 1, msg=after) + # and the object must have changed + self.assertNotEqual(before, after) + class LinuxlikeTests(BasePlatformTests): ''' diff --git a/test cases/common/3 static/libfile2.c b/test cases/common/3 static/libfile2.c new file mode 100644 index 0000000..86bbb2c --- /dev/null +++ b/test cases/common/3 static/libfile2.c @@ -0,0 +1,3 @@ +int libfunc2() { + return 4; +} diff --git a/test cases/common/3 static/meson.build b/test cases/common/3 static/meson.build index 3dee93b..e539956 100644 --- a/test cases/common/3 static/meson.build +++ b/test cases/common/3 static/meson.build @@ -1,3 +1,4 @@ project('static library test', 'c') -lib = static_library('mylib', 'libfile.c', + +lib = static_library('mylib', get_option('source'), link_args : '-THISMUSTNOBEUSED') # Static linker needs to ignore all link args. diff --git a/test cases/common/3 static/meson_options.txt b/test cases/common/3 static/meson_options.txt new file mode 100644 index 0000000..7261a19 --- /dev/null +++ b/test cases/common/3 static/meson_options.txt @@ -0,0 +1 @@ +option('source', type : 'combo', choices : ['libfile.c', 'libfile2.c'], value : 'libfile.c') |