diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2018-01-29 15:23:57 +0100 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2018-02-06 10:47:58 +0000 |
commit | dce67501894f527d37447e70e17fb3bc8834ea30 (patch) | |
tree | d059b4674a2780553b396196dd030b3a6e32bcf0 /utils.py | |
parent | c605d686f8cc4c8d370ec4d6260fca4b423f5526 (diff) |
Embeds $ORIGIN rpath into QtCore and libICU libraries
In case if Qt is configured without "-R ." which adds the $ORIGIN
rpath value, the linker will not try to find the copied over ICU
libraries (because the RPATH of a library higher in the dependency
tree does not get inherited by its children).
We want to make sure that the linker does attempt to find the ICU
libraries in the destination Qt libdir, so we prepend the
additional rpath value to the QtCore library, and also to the
ICU libraries.
Change-Id: Idbbf578d58ee12806b61610e6fd21f7c1ac48e3d
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'utils.py')
-rw-r--r-- | utils.py | 62 |
1 files changed, 62 insertions, 0 deletions
@@ -812,3 +812,65 @@ def copy_icu_libs(destination_lib_dir): basename = os.path.basename(path) destination = os.path.join(destination_lib_dir, basename) copyfile(path, destination, force_copy_symlink=True) + # Patch the ICU libraries to contain the $ORIGIN rpath value, so that only the local + # package libraries are used. + linuxSetRPaths(destination, '$ORIGIN') + + # Patch the QtCore library to find the copied over ICU libraries (if necessary). + log.info('Checking if QtCore library needs a new rpath to make it work with ICU libs.') + rpaths = linuxGetRPaths(qt_core_library_path) + if not rpaths or not rpathsHasOrigin(rpaths): + log.info('Patching QtCore library to contain $ORIGIN rpath.') + rpaths.insert(0, '$ORIGIN') + new_rpaths_string = ":".join(rpaths) + linuxSetRPaths(qt_core_library_path, new_rpaths_string) + +def linuxSetRPaths(executable_path, rpath_string): + """ Patches the `executable_path` with a new rpath string. """ + + if not hasattr(linuxSetRPaths, "patchelf_path"): + script_dir = os.getcwd() + patchelf_path = os.path.join(script_dir, "patchelf") + setattr(linuxSetRPaths, "patchelf_path", patchelf_path) + + cmd = [linuxSetRPaths.patchelf_path, '--set-rpath', rpath_string, executable_path] + + if run_process(cmd) != 0: + raise RuntimeError("Error patching rpath in {}".format(executable_path)) + +def linuxGetRPaths(executable_path): + """ Returns a list of run path values embedded in the executable or just an empty list. """ + + cmd = "readelf -d {}".format(executable_path) + (out, err, code) = back_tick(cmd, True) + if code != 0: + raise RuntimeError('Running `readelf -d {}` failed with ' + 'error output:\n {}. '.format(executable_path, err)) + lines = split_and_strip(out) + pattern = re.compile(r"^.+?\(RUNPATH\).+?\[(.+?)\]$") + + rpath_line = None + for line in lines: + match = pattern.search(line) + if match: + rpath_line = match.group(1) + break + + rpaths = [] + + if rpath_line: + rpaths = rpath_line.split(':') + + return rpaths + +def rpathsHasOrigin(rpaths): + """ Return True if the specified list of rpaths has an "$ORIGIN" value (aka current dir). """ + if not rpaths: + return False + + pattern = re.compile(r"^\$ORIGIN(/)?$") + for rpath in rpaths: + match = pattern.search(rpath) + if match: + return True + return False |