From dc1b4be6be321e39d21604ab4287c9ce972be4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Brzezi=C5=84ski?= Date: Fri, 28 Jun 2024 14:06:25 +0200 Subject: [PATCH] linkers: Fix AppleDynamicLinker not returning any rpaths to remove Fixes regression from commit 78e9009ff9d36925e04f329f9082841002ddd848. The above commit relied on rpath_dirs_to_remove being present and correctly filled, which was never the case for the AppleDynamicLinker. The result was that all the build-dir-only RPATHs were being carried over to the installed files. This commit implements returning the list of RPATHs to remove in AppleDynamicLinker, doing pretty much the same thing as what's in the GnuLikeDynamicLinkerMixin. Thanks to that, depfixer now correctly removes build-time Meson-created RPATHs, as it used to before 1.4.1. --- mesonbuild/linkers/linkers.py | 6 ++++-- .../darwin/1 rpath removal on install/bar.c | 5 +++++ .../1 rpath removal on install/foo/foo.c | 3 +++ .../1 rpath removal on install/foo/foo.h | 1 + .../1 rpath removal on install/foo/meson.build | 3 +++ .../1 rpath removal on install/meson.build | 8 ++++++++ unittests/baseplatformtests.py | 1 + unittests/darwintests.py | 18 ++++++++++++++++++ 8 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 test cases/darwin/1 rpath removal on install/bar.c create mode 100644 test cases/darwin/1 rpath removal on install/foo/foo.c create mode 100644 test cases/darwin/1 rpath removal on install/foo/foo.h create mode 100644 test cases/darwin/1 rpath removal on install/foo/meson.build create mode 100644 test cases/darwin/1 rpath removal on install/meson.build diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index f5e808082..c3750ccc3 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -819,17 +819,19 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): if not rpath_paths and not install_rpath and not build_rpath: return ([], set()) args: T.List[str] = [] + rpath_dirs_to_remove: T.Set[bytes] = set() # @loader_path is the equivalent of $ORIGIN on macOS # https://stackoverflow.com/q/26280738 origin_placeholder = '@loader_path' processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) if build_rpath != '': - all_paths.add(build_rpath) + all_paths.update(build_rpath.split(':')) for rp in all_paths: + rpath_dirs_to_remove.add(rp.encode('utf8')) args.extend(self._apply_prefix('-rpath,' + rp)) - return (args, set()) + return (args, rpath_dirs_to_remove) def get_thinlto_cache_args(self, path: str) -> T.List[str]: return ["-Wl,-cache_path_lto," + path] diff --git a/test cases/darwin/1 rpath removal on install/bar.c b/test cases/darwin/1 rpath removal on install/bar.c new file mode 100644 index 000000000..b2fd0a664 --- /dev/null +++ b/test cases/darwin/1 rpath removal on install/bar.c @@ -0,0 +1,5 @@ +#include "foo/foo.h" + +void bar() { + foo(); +} \ No newline at end of file diff --git a/test cases/darwin/1 rpath removal on install/foo/foo.c b/test cases/darwin/1 rpath removal on install/foo/foo.c new file mode 100644 index 000000000..e355ed459 --- /dev/null +++ b/test cases/darwin/1 rpath removal on install/foo/foo.c @@ -0,0 +1,3 @@ +int foo() { + return 1 + 2; +} \ No newline at end of file diff --git a/test cases/darwin/1 rpath removal on install/foo/foo.h b/test cases/darwin/1 rpath removal on install/foo/foo.h new file mode 100644 index 000000000..176e7a3be --- /dev/null +++ b/test cases/darwin/1 rpath removal on install/foo/foo.h @@ -0,0 +1 @@ +int foo(); \ No newline at end of file diff --git a/test cases/darwin/1 rpath removal on install/foo/meson.build b/test cases/darwin/1 rpath removal on install/foo/meson.build new file mode 100644 index 000000000..cc6fbe4e3 --- /dev/null +++ b/test cases/darwin/1 rpath removal on install/foo/meson.build @@ -0,0 +1,3 @@ +foo = library('foo', 'foo.c', + install: true, +) \ No newline at end of file diff --git a/test cases/darwin/1 rpath removal on install/meson.build b/test cases/darwin/1 rpath removal on install/meson.build new file mode 100644 index 000000000..093d7deba --- /dev/null +++ b/test cases/darwin/1 rpath removal on install/meson.build @@ -0,0 +1,8 @@ +project('proj', 'c') + +subdir('foo') + +bar = library('bar', 'bar.c', + link_with: foo, + install: true, +) \ No newline at end of file diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py index e94a2baac..6e6a01d40 100644 --- a/unittests/baseplatformtests.py +++ b/unittests/baseplatformtests.py @@ -78,6 +78,7 @@ class BasePlatformTests(TestCase): self.linuxlike_test_dir = os.path.join(src_root, 'test cases/linuxlike') self.objc_test_dir = os.path.join(src_root, 'test cases/objc') self.objcpp_test_dir = os.path.join(src_root, 'test cases/objcpp') + self.darwin_test_dir = os.path.join(src_root, 'test cases/darwin') # Misc stuff self.orig_env = os.environ.copy() diff --git a/unittests/darwintests.py b/unittests/darwintests.py index 740310477..afc663a57 100644 --- a/unittests/darwintests.py +++ b/unittests/darwintests.py @@ -100,6 +100,12 @@ class DarwinTests(BasePlatformTests): self.assertIsNotNone(m, msg=out) return m.groups() + def _get_darwin_rpaths(self, fname: str) -> T.List[str]: + out = subprocess.check_output(['otool', '-l', fname], universal_newlines=True) + pattern = re.compile(r'path (.*) \(offset \d+\)') + rpaths = pattern.findall(out) + return rpaths + @skipIfNoPkgconfig def test_library_versioning(self): ''' @@ -154,3 +160,15 @@ class DarwinTests(BasePlatformTests): from mesonbuild.mesonlib import darwin_get_object_archs archs = darwin_get_object_archs('/bin/cat') self.assertEqual(archs, ['x86_64', 'aarch64']) + + def test_darwin_meson_rpaths_removed_on_install(self): + testdir = os.path.join(self.darwin_test_dir, '1 rpath removal on install') + self.init(testdir) + self.build() + # Meson-created RPATHs are usually only valid in the build directory + rpaths = self._get_darwin_rpaths(os.path.join(self.builddir, 'libbar.dylib')) + self.assertListEqual(rpaths, ['@loader_path/foo']) + self.install() + # Those RPATHs are no longer valid and should not be present after installation + rpaths = self._get_darwin_rpaths(os.path.join(self.installdir, 'usr/lib/libbar.dylib')) + self.assertListEqual(rpaths, [])