summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cerbero/build/recipe.py2
-rwxr-xr-xcerbero/tools/osxrelocator.py75
-rwxr-xr-xcerbero/tools/osxuniversalgenerator.py3
3 files changed, 54 insertions, 26 deletions
diff --git a/cerbero/build/recipe.py b/cerbero/build/recipe.py
index 9f01bf5a..704e7d20 100644
--- a/cerbero/build/recipe.py
+++ b/cerbero/build/recipe.py
@@ -576,7 +576,7 @@ SOFTWARE LICENSE COMPLIANCE.\n\n'''
return fp.split('/')[0] in ['lib', 'bin', 'libexec'] and \
os.path.splitext(fp)[1] not in ['.a', '.pc', '.la']
- relocator = OSXRelocator(self.config.prefix, self.config.prefix, True,
+ relocator = OSXRelocator(self.config.prefix, self.config.libdir, True,
logfile=self.logfile)
# Only relocate files are that are potentially relocatable and
# remove duplicates by symbolic links so we relocate libs only
diff --git a/cerbero/tools/osxrelocator.py b/cerbero/tools/osxrelocator.py
index 40483d70..737d72d5 100755
--- a/cerbero/tools/osxrelocator.py
+++ b/cerbero/tools/osxrelocator.py
@@ -53,6 +53,11 @@ class OSXRelocator(object):
self.change_libs_path(object_file, original_file)
def change_id(self, object_file, id=None):
+ """
+ Changes the `LC_ID_DYLIB` of the given object file.
+ @object_file: Path to the object file
+ @id: New ID; if None, it'll be `@rpath/<basename>`
+ """
id = id or object_file.replace(self.lib_prefix, '@rpath')
if not self._is_mach_o_file(object_file):
return
@@ -60,42 +65,68 @@ class OSXRelocator(object):
shell.new_call(cmd, fail=False, logfile=self.logfile)
def change_libs_path(self, object_file, original_file=None):
- # @object_file: the actual file location
- # @original_file: where the file will end up in the output directory
- # structure and the basis of how to calculate rpath entries. This may
- # be different from where the file is currently located e.g. when
- # creating a fat binary from copy of the original file in a temporary
- # location.
+ """
+ Sanitizes the `LC_LOAD_DYLIB` and `LC_RPATH` load commands,
+ setting the former to be of the form `@rpath/libyadda.dylib`,
+ and the latter to point to the /lib folder within the GStreamer prefix.
+ @object_file: the actual file location
+ @original_file: where the file will end up in the output directory
+ structure and the basis of how to calculate rpath entries. This may
+ be different from where the file is currently located e.g. when
+ creating a fat binary from copy of the original file in a temporary
+ location.
+ """
+ if not self._is_mach_o_file(object_file):
+ return
if original_file is None:
original_file = object_file
+ # First things first: ensure the load command of future consumers
+ # points to the real ID of this library
+ # This used to be done only at Universal lipo time, but by then
+ # it's too late -- unless one wants to run through all load commands
+ self.change_id(object_file, id='@rpath/{}'.format(os.path.basename(original_file)))
+ # With that out of the way, we need to sort out how many parents
+ # need to be navigated to reach the root of the GStreamer prefix
depth = len(original_file.split('/')) - len(self.lib_prefix.split('/')) - 1
p_depth = '/..' * depth
- rpaths = ['.']
- rpaths += ['@loader_path' + p_depth, '@executable_path' + p_depth]
- rpaths += ['@loader_path' + '/../lib', '@executable_path' + '/../lib']
- if not self._is_mach_o_file(object_file):
- return
+ rpaths = [
+ # From a deeply nested library
+ f'@loader_path{p_depth}',
+ # From a deeply nested framework or binary
+ f'@executable_path{p_depth}',
+ # From a library within the prefix
+ '@loader_path/../lib',
+ # From a binary within the prefix
+ '@executable_path/../lib',
+ ]
if depth > 1:
- rpaths += ['@loader_path/..', '@executable_path/..']
- existing_rpaths = self.list_rpaths(object_file)
+ rpaths += [
+ # Allow loading from the parent (e.g. GIO plugin)
+ '@loader_path/..',
+ '@executable_path/..',
+ ]
+ # Make them unique
+ rpaths = list(set(rpaths))
# Remove absolute RPATHs, we don't want or need these
- for p in existing_rpaths:
- if not p.startswith('/'):
- continue
+ existing_rpaths = list(set(self.list_rpaths(object_file)))
+ for p in filter(lambda p: p.startswith('/'), self.list_rpaths(object_file)):
cmd = [INT_CMD, '-delete_rpath', p, object_file]
shell.new_call(cmd, fail=False)
# Add relative RPATHs
- for p in rpaths:
- if p in existing_rpaths:
- continue
+ for p in filter(lambda p: p not in existing_rpaths, rpaths):
cmd = [INT_CMD, '-add_rpath', p, object_file]
shell.new_call(cmd, fail=False)
- # Change dependent library names from absolute to @rpath/
+ # Change dependencies' paths from absolute to @rpath/
for lib in self.list_shared_libraries(object_file):
if self.lib_prefix in lib:
new_lib = lib.replace(self.lib_prefix, '@rpath')
- cmd = [INT_CMD, '-change', lib, new_lib, object_file]
- shell.new_call(cmd, fail=False, logfile=self.logfile)
+ elif '@rpath/lib/' in lib:
+ # These are leftovers from meson thinking RPATH == prefix
+ new_lib = lib.replace('@rpath/lib/', '@rpath/')
+ else:
+ continue
+ cmd = [INT_CMD, '-change', lib, new_lib, object_file]
+ shell.new_call(cmd, fail=False, logfile=self.logfile)
def change_lib_path(self, object_file, old_path, new_path):
for lib in self.list_shared_libraries(object_file):
diff --git a/cerbero/tools/osxuniversalgenerator.py b/cerbero/tools/osxuniversalgenerator.py
index 2ad6f627..b12bc22c 100755
--- a/cerbero/tools/osxuniversalgenerator.py
+++ b/cerbero/tools/osxuniversalgenerator.py
@@ -127,10 +127,7 @@ class OSXUniversalGenerator(object):
shutil.copy(f, tmp.name)
prefix_to_replace = [d for d in dirs if d in f][0]
relocator = OSXRelocator(self.output_root, prefix_to_replace, False, logfile=self.logfile)
- # since we are using a temporary file, we must force the library id
- # name to real one and not based on the filename
relocator.relocate_file(tmp.name, f)
- relocator.change_id(tmp.name, id='@rpath/{}'.format(os.path.basename(f)))
cmd = [self.LIPO_CMD, '-create'] + [f.name for f in tmp_inputs] + ['-output', output]
shell.new_call(cmd)
for tmp in tmp_inputs: