From 2d8f326f56a0a4483ee22a9f8f7323adb231be5a Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 11 Mar 2016 17:22:58 +0100 Subject: [PATCH] Added new relocate target and script. --- cmake/setup_custom_targets.cmake | 16 ++++ contrib/utilities/relocate_libraries.py | 108 ++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100755 contrib/utilities/relocate_libraries.py diff --git a/cmake/setup_custom_targets.cmake b/cmake/setup_custom_targets.cmake index 41f8ed38e1..e3782000ca 100644 --- a/cmake/setup_custom_targets.cmake +++ b/cmake/setup_custom_targets.cmake @@ -99,6 +99,19 @@ ADD_CUSTOM_TARGET(indent COMMENT "Indenting all files in the deal.II directories" ) +# +# Provide "relocate" target to run install_name_tool on all external libraries +# under ${DEAL_II_CPACK_EXTERNAL_LIBS_TREE} +# +IF(CMAKE_SYSTEM_NAME MATCHES "Darwin" AND + NOT "${DEAL_II_CPACK_EXTERNAL_LIBS_TREE}" STREQUAL "") + ADD_CUSTOM_TARGET(relocate + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ./contrib/utilities/relocate_libraries.py + COMMENT "Running install_name_tool under ${DEAL_II_CPACK_EXTERNAL_LIBS_TREE}" + ) +ENDIF() + # # Provide an "info" target to print a help message: @@ -140,6 +153,9 @@ FILE(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/print_info.cmake # # indent - indent all headers and source file # +# relocate - (only available on Darwin machines) fix RPATH for external +# libraries, if packaging was requested +# ###\")" ) diff --git a/contrib/utilities/relocate_libraries.py b/contrib/utilities/relocate_libraries.py new file mode 100755 index 0000000000..4f1bab6b29 --- /dev/null +++ b/contrib/utilities/relocate_libraries.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# This script runs install_name_tool on each library under basedir (first argument +# on command line) and makes sure that all libraries are installed with absolute +# id name. This makes Mac OS X happy about not using DYLD_LIBRARY_PATH, which is generally +# a bad thing. + +import os +import sys +from subprocess import check_output as run + +basedir = '/Applications/deal.II.app/Contents/Resources/opt/' +if len(sys.argv) > 1: + basedir = sys.argv[1] + +## Lib object +# +# Stores the name of a library, its install name, its location and all its dependencies, as given by `otool -L` + +class Lib(object): + location = None + install_name = None + name = None + deps = None + def __str__(self): + mystr = "" + mystr += "Name :"+str(self.name) + mystr +="\nInstall name:"+str(self.install_name) + mystr +="\nLocation :"+str(self.location) + mystr +="\nDeps : ... " + return mystr + +# Walk the current tree, and extract all libraries +def get_libs(): + libraries = [] + + for root, dirs, files in os.walk(basedir): + for f in files: + filename = os.path.join(root, f) + if os.path.isfile(filename) and f.endswith("dylib"): + a = Lib() + a.name = f + a.install_name = run(["otool", "-D", filename]).split('\n')[1] + a.location= os.path.join(root, f) + long_deps = run(["otool", "-L", a.location]).split('\n') + a.deps = [dep.partition(' ')[0][1::] for dep in long_deps[2:-1]] + libraries += [a] + return libraries + + +# # Fix all install names first +# +# Some will fail, because they are either stub files, or system files... + +# In[ ]: + +libraries = get_libs() +c = 0 +failed = [] +for c in range(len(libraries)): + i = libraries[c] + if os.path.islink(i.location): + continue + if i.install_name != i.location: + try: + run(["install_name_tool",'-id',i.location, i.location]) + except: + print("Failed: ",i.name) + print( "(",libraries[c].name,")") + failed += [c] +print (failed) +print ('Removing failed libs...') +for fail in reversed(failed): + print ("Removing from list",libraries[fail].name) + del libraries[fail] + + +# # Fix all dependencies with absolute paths + +for c in xrange(len(libraries)): + this_lib = libraries[c] + if this_lib.install_name != this_lib.location: + print('Not valid:', i.name) + else: + lib = this_lib.name + command = ['install_name_tool'] + for dep in this_lib.deps: + for loc in libraries: + if dep.find(loc.name) != -1 and dep != loc.install_name: + command += ['-change', dep, loc.install_name] + break + try: + if len(command) != 1: + command += [this_lib.location] + print('Processing', lib) + print('======================\n\n') + print(" ".join(command)) + print('======================\n\n') + run(command) + except: + print('\n\n*********************************************') + print('Last command failed!') + print(" ".join(command)) + print('*********************************************\n\n') + + + + -- 2.39.5