From 1653594aca9c552fa6ae6af208137a4569b1496f Mon Sep 17 00:00:00 2001 From: marco <marco@5a81b35b-ba03-0410-adc8-b2c5c5119f08> Date: Wed, 30 Jun 2010 12:06:23 +0000 Subject: [PATCH] implement deployment mechanism Leopard Leopard's install_name_tool doesn't allow to manipulate the rpaths of mach-o binaries, that's why we have to fall back to the ugly @executable_path on these systems. This doesn't work properly when using the default Python coming with the system, since the library load commands are defined relative to the executable they were loaded in. If the python the binary and gosty binary are not in the same path, BANG! git-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@2479 5a81b35b-ba03-0410-adc8-b2c5c5119f08 --- deployment/macos/deploy.py | 4 +- deployment/macos/deps.py | 106 ++++++++++++++++++++++++++----------- 2 files changed, 78 insertions(+), 32 deletions(-) diff --git a/deployment/macos/deploy.py b/deployment/macos/deploy.py index 396d3c3d8..87e782940 100644 --- a/deployment/macos/deploy.py +++ b/deployment/macos/deploy.py @@ -1,4 +1,6 @@ import bundle import deps +import sys bundle.create_bundle('DNG') -deps.make_standalone('../../stage', 'standalone', True) +deps.make_standalone('../../stage', 'standalone', True, + '--no-rpath' in sys.argv) diff --git a/deployment/macos/deps.py b/deployment/macos/deps.py index 5053762e4..1bcb4ab08 100644 --- a/deployment/macos/deps.py +++ b/deployment/macos/deps.py @@ -2,10 +2,9 @@ import os import subprocess import shutil import sys -def _LibName(component): +def _lib_name(component): return 'libost_%s.dylib' % component - def _deps_for_lib(lib, pool, recursive=True): if lib in pool: return @@ -33,7 +32,7 @@ def collect_deps(stage_dir, components, binaries): pool=set() for component in components: lib_name=os.path.abspath(os.path.join(stage_dir, 'lib', - _LibName(component))) + _lib_name(component))) if not os.path.exists(lib_name): print 'WARNING:', lib_name, 'does not exist' if lib_name not in pool: @@ -53,23 +52,26 @@ BINARIES=['gosty', 'chemdict_tool'] COMPONENTS=['mol', 'geom', 'conop', 'gfx', 'gui', 'seq_alg', 'seq', 'img', 'img_alg', 'qa', 'info', 'io', 'db', 'base'] SCRIPTS=['dng', 'ost'] -CHANGE_ID='install_name_tool -id @rpath/%s %s' -CHANGE_LOAD_CMD='install_name_tool -change %s @rpath/%s %s' +CHANGE_ID_RPATH='install_name_tool -id @rpath/%s %s' +CHANGE_ID='install_name_tool -id @executable_path/%s %s' +CHANGE_LOAD_CMD_RPATH='install_name_tool -change %s @rpath/%s %s' +CHANGE_LOAD_CMD='install_name_tool -change %s @executable_path/%s %s' ADD_RPATH='install_name_tool -add_rpath %s %s 2> /dev/null' SITE_PACKAGES=['sip.so', 'sipconfig.py', 'sipdistutils.py', 'PyQt4'] REMOVE_HEADERS='rm -rf `find %s/lib -type d -name Headers`' REMOVE_CURRENT='rm -rf `find %s/lib -type d -name Current`' # collect libs of non-standard libraries/frameworks we depend on -def copy_binaries(stage_dir, outdir, binary_names, scripts): +def copy_binaries(stage_dir, outdir, binary_names, scripts, use_rpath): + exe_path=os.path.abspath(os.path.join(outdir, 'bin')) for binary_name in binary_names: - bin_name=os.path.abspath(os.path.join(stage_dir, 'bin', binary_name)) + bin_name=os.path.join(stage_dir, 'bin', binary_name) if not os.path.exists(bin_name): print 'WARNING:', binary_name, 'does not exist' continue dst_name=os.path.join(outdir, 'bin', os.path.basename(bin_name)) shutil.copy(bin_name, dst_name) - update_load_commands(dst_name, exe=True) + update_load_commands(dst_name, True, use_rpath, exe_path) os.system(ADD_RPATH % ('../lib', dst_name)) for script in scripts: shutil.copy(os.path.join(stage_dir, 'bin', script), @@ -89,50 +91,74 @@ def split_framework_components(abs_path): trail=os.path.join(*parts[i+1:]) return lead, trail -def change_id(id,lib): +def change_id(id, lib, use_rpath): os.chmod(lib, 0666) - os.system(CHANGE_ID % (id,lib)) + if use_rpath: + os.system(CHANGE_ID_RRPATH % (id,lib)) + else: + os.system(CHANGE_ID % (id,lib)) os.chmod(lib, 0444) -def update_load_commands(lib, exe=False): +def update_load_commands(lib, exe, use_rpath, exe_path): direct_deps=set() _deps_for_lib(lib, direct_deps, recursive=False) os.chmod(lib, 0666) for direct_dep in direct_deps: if direct_dep.endswith('.dylib'): - new_name=os.path.basename(direct_dep) - os.system(CHANGE_LOAD_CMD % (direct_dep, new_name, lib)) + if use_rpath: + new_name=os.path.basename(direct_dep) + os.system(CHANGE_LOAD_CMD_RPATH % (direct_dep, new_name, lib)) + else: + new_name=os.path.join('../lib', os.path.basename(direct_dep)) + os.system(CHANGE_LOAD_CMD % (direct_dep, new_name, lib)) else: assert direct_dep.find('.framework/')>=0 - framework_path, rel_path=split_framework_components(direct_dep) - framework_name=os.path.basename(framework_path) - dst_name=os.path.join(framework_name, rel_path) - new_name=os.path.join(framework_name, rel_path) - os.system(CHANGE_LOAD_CMD % (direct_dep, new_name, lib)) - os.system(ADD_RPATH % ('.', lib)) + if use_rpath: + framework_path, rel_path=split_framework_components(direct_dep) + framework_name=os.path.basename(framework_path) + new_name=os.path.join(framework_name, rel_path) + os.system(CHANGE_LOAD_CMD_RPATH % (direct_dep, new_name, lib)) + else: + framework_path, rel_path=split_framework_components(direct_dep) + framework_name=os.path.basename(framework_path) + new_name=os.path.join('../lib', framework_name, rel_path) + os.system(CHANGE_LOAD_CMD % (direct_dep, new_name, lib)) + if use_rpath: + os.system(ADD_RPATH % ('.', lib)) if exe: os.chmod(lib, 0555) else: os.chmod(lib, 0444) -def copy_deps(dependencies, outdir): +def copy_deps(dependencies, outdir, use_rpath): + exe_path=os.path.join(outdir, 'bin') for dep in dependencies: if dep.endswith('.dylib'): dst_name=os.path.join(outdir, 'lib', os.path.basename(dep)) shutil.copy(dep, dst_name) - change_id(os.path.basename(dep), dst_name) - update_load_commands(dst_name) + if use_rpath: + change_id(os.path.basename(dep), dst_name, use_rpath) + else: + change_id('../lib/%s' % os.path.basename(dep), dst_name, use_rpath) + update_load_commands(dst_name, False, use_rpath, exe_path) else: assert dep.find('.framework/')>=0 framework_path, rel_path=split_framework_components(dep) framework_name=os.path.basename(framework_path) dst_name=os.path.join(outdir, 'lib', framework_name) shutil.copytree(framework_path, dst_name) - change_id(os.path.join(dst_name, rel_path), - os.path.join(dst_name, rel_path)) - update_load_commands(os.path.join(dst_name, rel_path)) + if use_rpath: + change_id(os.path.join(dst_name, rel_path), + os.path.join(dst_name, rel_path), use_rpath) + else: + change_id(os.path.join('../lib', framework_name, rel_path), + os.path.join(dst_name, rel_path), use_rpath) + update_load_commands(os.path.join(dst_name, rel_path), False, + use_rpath, exe_path) -def update_pymod_shared_objects(lib_path, path, files): +def update_pymod_shared_objects(args, path, files): + lib_path, use_rpath=args + exe_path=os.path.abspath(os.path.join(lib_path, '../bin')) for f in files: if not os.path.exists(os.path.join(path, f)): continue @@ -141,7 +167,7 @@ def update_pymod_shared_objects(lib_path, path, files): path_to_lib_path=os.path.relpath(lib_path, path) abs_name=os.path.join(path, f) os.system(ADD_RPATH % (path_to_lib_path, abs_name)) - update_load_commands(abs_name) + update_load_commands(abs_name, False, use_rpath, exe_path) elif ext=='.py': pyc_path=os.path.join(path, '%s.pyc' % base) if os.path.exists(pyc_path): @@ -162,7 +188,25 @@ def get_site_package_dir(): return p[:index+len(pattern)] raise RuntimeError("Couldn't determine site-packages location") -def make_standalone(stage_dir, outdir, no_includes): +def check_install_name_tool_capabilities(): + """ + Find out whether install_name_tool supports the add_rpath option. + """ + inst_name_tool=subprocess.Popen('install_name_tool', shell=True, + stderr=subprocess.PIPE) + output=inst_name_tool.communicate()[1] + return output.find('-add_rpath')!=-1 + +def make_standalone(stage_dir, outdir, no_includes, force_no_rpath=False): + # figure out if install_name_tool supports the -add_rpath option. + use_rpath=True + if not check_install_name_tool_capabilities(): + print "install_name_tool doesn't support the -add_rpath option." + print "I will fallback to the more arcane @executable_path" + use_rpath=False + elif force_no_rpath: + print "I will use the arcane @executable_path" + use_rpath=False if os.path.exists(outdir): shutil.rmtree(outdir) os.system('mkdir -p "%s"' % outdir) @@ -174,9 +218,9 @@ def make_standalone(stage_dir, outdir, no_includes): print 'collecting dependencies' deps=collect_deps(stage_dir, COMPONENTS, BINARIES) print 'copying dependencies' - copy_deps(deps, outdir) + copy_deps(deps, outdir, use_rpath) print 'copying binaries' - copy_binaries(stage_dir, outdir, BINARIES, SCRIPTS) + copy_binaries(stage_dir, outdir, BINARIES, SCRIPTS, use_rpath) print 'copying pymod' shutil.copytree(os.path.join(stage_dir, 'lib/openstructure'), os.path.join(outdir, 'lib/openstructure')) @@ -194,4 +238,4 @@ def make_standalone(stage_dir, outdir, no_includes): print 'updating link commands of python shared objects' os.path.walk(os.path.join(outdir, 'lib', 'openstructure'), update_pymod_shared_objects, - os.path.join(outdir, 'lib')) + (os.path.join(outdir, 'lib'), use_rpath)) -- GitLab