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
pull/1356/head
Nirbheek Chauhan 8 years ago
parent 217eae4011
commit a14eba27a9
  1. 14
      mesonbuild/backend/ninjabackend.py
  2. 41
      run_unittests.py
  3. 3
      test cases/common/3 static/libfile2.c
  4. 3
      test cases/common/3 static/meson.build
  5. 1
      test cases/common/3 static/meson_options.txt

@ -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)

@ -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):
'''

@ -0,0 +1,3 @@
int libfunc2() {
return 4;
}

@ -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.

@ -0,0 +1 @@
option('source', type : 'combo', choices : ['libfile.c', 'libfile2.c'], value : 'libfile.c')
Loading…
Cancel
Save