diff options
author | David Seifert <16636962+SoapGentoo@users.noreply.github.com> | 2019-09-09 01:48:57 +0200 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2019-09-08 19:48:57 -0400 |
commit | e19a49b8957cd06d6f121812b7b00ef60a57fc7c (patch) | |
tree | 22a6842d0f0c36ade922cc9d3574ef541c8eecf9 | |
parent | c9042fc3eeb0f4e76f5cc1716677aec39e1821b7 (diff) | |
download | meson-e19a49b8957cd06d6f121812b7b00ef60a57fc7c.zip meson-e19a49b8957cd06d6f121812b7b00ef60a57fc7c.tar.gz meson-e19a49b8957cd06d6f121812b7b00ef60a57fc7c.tar.bz2 |
Fix static archives stripping (#5905)
* Do not strip static archives
Stripping static archives without more fine-grained options (e.g. `-g`)
leads to failures such as
ld: libfoo.a: error adding symbols: archive has no index; run ranlib to add one
because GNU strip removes *every* symbol in a static archive by default.
Given that static archives are not final build artifacts (unlike
executables and shared libraries), stripping them gains little and only
causes more edge case failures.
* Gentoo's portage only strips debug information:
https://github.com/gentoo/portage/blob/86f211e3a552753eb945670a39c1a3b14c3c3bd1/bin/estrip#L322
* Fedora also only strips debug information:
https://github.com/rpm-software-management/rpm/blob/e9c13c6565cf4782d1f73255ee9144dd9bd2aca7/scripts/brp-strip-static-archive#L18
* Debian also only does some very light stripping:
https://github.com/Debian/debhelper/blob/72ed1d3261730d56da6afde0ec7f52f32976e04d/dh_strip#L374
Fixes #4138
* Add test case for static archive stripping
-rw-r--r-- | mesonbuild/backend/backends.py | 15 | ||||
-rwxr-xr-x | run_unittests.py | 27 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/app/appA.c | 4 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/app/appB.c | 4 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/app/meson.build | 7 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/lib/libA.c | 5 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/lib/libA.h | 1 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/lib/libB.c | 5 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/lib/libB.h | 1 | ||||
-rw-r--r-- | test cases/unit/68 static archive stripping/lib/meson.build | 23 |
10 files changed, 91 insertions, 1 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c0b2666..773c75e 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1089,7 +1089,20 @@ class Backend: install_mode = t.get_custom_install_mode() # Install the target output(s) if isinstance(t, build.BuildTarget): - should_strip = self.get_option_for_target('strip', t) + # In general, stripping static archives is tricky and full of pitfalls. + # Wholesale stripping of static archives with a command such as + # + # strip libfoo.a + # + # is broken, as GNU's strip will remove *every* symbol in a static + # archive. One solution to this nonintuitive behaviour would be + # to only strip local/debug symbols. Unfortunately, strip arguments + # are not specified by POSIX and therefore not portable. GNU's `-g` + # option (i.e. remove debug symbols) is equivalent to Apple's `-S`. + # + # TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more + # fine-grained stripping of static archives. + should_strip = not isinstance(t, build.StaticLibrary) and self.get_option_for_target('strip', t) # Install primary build output (library/executable/jar, etc) # Done separately because of strip/aliases/rpath if outdirs[0] is not False: diff --git a/run_unittests.py b/run_unittests.py index 04d67a8..07f0b93 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -5331,6 +5331,33 @@ endian = 'little' self.build() @skipIfNoPkgconfig + def test_static_archive_stripping(self): + ''' + Check that Meson produces valid static archives with --strip enabled + ''' + with tempfile.TemporaryDirectory() as tempdirname: + testdirbase = os.path.join(self.unit_test_dir, '68 static archive stripping') + + # build lib + self.new_builddir() + testdirlib = os.path.join(testdirbase, 'lib') + testlibprefix = os.path.join(tempdirname, 'libprefix') + self.init(testdirlib, extra_args=['--prefix=' + testlibprefix, + '--libdir=lib', + '--default-library=static', + '--buildtype=debug', + '--strip'], default_args=False) + self.build() + self.install(use_destdir=False) + + # build executable (uses lib, fails if static archive has been stripped incorrectly) + pkg_dir = os.path.join(testlibprefix, 'lib/pkgconfig') + self.new_builddir() + self.init(os.path.join(testdirbase, 'app'), + override_envvars={'PKG_CONFIG_PATH': pkg_dir}) + self.build() + + @skipIfNoPkgconfig def test_pkgconfig_formatting(self): testdir = os.path.join(self.unit_test_dir, '38 pkgconfig format') self.init(testdir) diff --git a/test cases/unit/68 static archive stripping/app/appA.c b/test cases/unit/68 static archive stripping/app/appA.c new file mode 100644 index 0000000..9c14a02 --- /dev/null +++ b/test cases/unit/68 static archive stripping/app/appA.c @@ -0,0 +1,4 @@ +#include <stdio.h> +#include <libA.h> + +int main() { printf("The answer is: %d\n", libA_func()); } diff --git a/test cases/unit/68 static archive stripping/app/appB.c b/test cases/unit/68 static archive stripping/app/appB.c new file mode 100644 index 0000000..05b4a2a --- /dev/null +++ b/test cases/unit/68 static archive stripping/app/appB.c @@ -0,0 +1,4 @@ +#include <stdio.h> +#include <libB.h> + +int main() { printf("The answer is: %d\n", libB_func()); } diff --git a/test cases/unit/68 static archive stripping/app/meson.build b/test cases/unit/68 static archive stripping/app/meson.build new file mode 100644 index 0000000..118719d --- /dev/null +++ b/test cases/unit/68 static archive stripping/app/meson.build @@ -0,0 +1,7 @@ +project('app', ['c']) + +a = dependency('test-a') +b = dependency('test-b') + +executable('appA', files('appA.c'), dependencies : a) +executable('appB', files('appB.c'), dependencies : b) diff --git a/test cases/unit/68 static archive stripping/lib/libA.c b/test cases/unit/68 static archive stripping/lib/libA.c new file mode 100644 index 0000000..a97185e --- /dev/null +++ b/test cases/unit/68 static archive stripping/lib/libA.c @@ -0,0 +1,5 @@ +#include <libA.h> + +static int libA_func_impl(void) { return 0; } + +int libA_func(void) { return libA_func_impl(); } diff --git a/test cases/unit/68 static archive stripping/lib/libA.h b/test cases/unit/68 static archive stripping/lib/libA.h new file mode 100644 index 0000000..e6450cd --- /dev/null +++ b/test cases/unit/68 static archive stripping/lib/libA.h @@ -0,0 +1 @@ +int libA_func(void); diff --git a/test cases/unit/68 static archive stripping/lib/libB.c b/test cases/unit/68 static archive stripping/lib/libB.c new file mode 100644 index 0000000..0200b1f --- /dev/null +++ b/test cases/unit/68 static archive stripping/lib/libB.c @@ -0,0 +1,5 @@ +#include <libB.h> + +static int libB_func_impl(void) { return 0; } + +int libB_func(void) { return libB_func_impl(); } diff --git a/test cases/unit/68 static archive stripping/lib/libB.h b/test cases/unit/68 static archive stripping/lib/libB.h new file mode 100644 index 0000000..065a4a4 --- /dev/null +++ b/test cases/unit/68 static archive stripping/lib/libB.h @@ -0,0 +1 @@ +int libB_func(void); diff --git a/test cases/unit/68 static archive stripping/lib/meson.build b/test cases/unit/68 static archive stripping/lib/meson.build new file mode 100644 index 0000000..ae50fa7 --- /dev/null +++ b/test cases/unit/68 static archive stripping/lib/meson.build @@ -0,0 +1,23 @@ +project('lib', ['c']) + +pkg = import('pkgconfig') + +a = library('test-a', files('libA.c'), install: true) +install_headers(files('libA.h'), subdir: 'libA') +pkg.generate( + a, + version: '0.0', + description: 'test library libA', + filebase: 'test-a', + name: 'test library libA', + subdirs: 'libA') + +b = static_library('test-b', files('libB.c'), install: true) +install_headers(files('libB.h'), subdir: 'libB') +pkg.generate( + b, + version: '0.0', + description: 'test library libB', + filebase: 'test-b', + name: 'test library libB', + subdirs: 'libB') |