Merge pull request #535 from bblacey/mantis-2886
Packaging: Set macOS dynamic loader paths
This commit is contained in:
commit
3fab41f567
|
@ -196,6 +196,7 @@ if(APPLE)
|
|||
${CMAKE_INSTALL_PREFIX}/${PACKAGE_NAME}.app/Contents)
|
||||
set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib)
|
||||
endif(FREECAD_CREATE_MAC_APP)
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
endif(APPLE)
|
||||
|
||||
OPTION(BUILD_FEM "Build the FreeCAD FEM module" ON)
|
||||
|
|
55
src/Tools/MakeMacBundleRelocatable.py
Normal file → Executable file
55
src/Tools/MakeMacBundleRelocatable.py
Normal file → Executable file
|
@ -3,6 +3,7 @@ import sys
|
|||
from subprocess import Popen, PIPE, check_call, check_output
|
||||
import pprint
|
||||
import re
|
||||
import logging
|
||||
|
||||
# This script is intended to help copy dynamic libraries used by FreeCAD into
|
||||
# a Mac application bundle and change dyld commands as appropriate. There are
|
||||
|
@ -44,6 +45,8 @@ class Node:
|
|||
return not self.__eq__(other)
|
||||
def __hash__(self):
|
||||
return hash(self.name)
|
||||
def __str__(self):
|
||||
return self.name + " path: " + self.path + " num children: " + str(len(self.children))
|
||||
|
||||
class DepsGraph:
|
||||
graph = {}
|
||||
|
@ -94,8 +97,8 @@ def is_system_lib(lib):
|
|||
return True
|
||||
for p in warnPaths:
|
||||
if lib.startswith(p):
|
||||
print "WARNING: library %s will not be bundled!" % lib
|
||||
print "See MakeMacRelocatable.py for more information."
|
||||
logging.warning("WARNING: library %s will not be bundled!" % lib)
|
||||
logging.warning("See MakeMacRelocatable.py for more information.")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -249,14 +252,19 @@ def in_bundle(lib, bundle_path):
|
|||
|
||||
def copy_into_bundle(graph, node, bundle_path):
|
||||
if not in_bundle(node.path, bundle_path):
|
||||
check_call([ "cp", "-L", os.path.join(node.path, node.name),
|
||||
os.path.join(bundle_path, "lib", node.name) ])
|
||||
source = os.path.join(node.path, node.name)
|
||||
target = os.path.join(bundle_path, "lib", node.name)
|
||||
logging.info("Bundling {}".format(source))
|
||||
|
||||
node.path = os.path.join(bundle_path, "lib")
|
||||
check_output([ "cp", "-L", source, target ])
|
||||
|
||||
node.path = os.path.dirname(target)
|
||||
|
||||
#fix permissions
|
||||
check_call([ "chmod", "a+w",
|
||||
os.path.join(bundle_path, "lib", node.name) ])
|
||||
check_output([ "chmod", "a+w", target ])
|
||||
|
||||
#Change the loader ID_DYLIB to a bundle-local name (i.e. non-absolute)
|
||||
check_output([ "install_name_tool", "-id", node.name, target ])
|
||||
|
||||
def get_rpaths(library):
|
||||
"Returns a list of rpaths specified within library"
|
||||
|
@ -288,9 +296,11 @@ def add_rpaths(graph, node, bundle_path):
|
|||
install_names = list_install_names(lib)
|
||||
rpaths = []
|
||||
|
||||
logging.debug(lib)
|
||||
for install_name in install_names:
|
||||
name = os.path.basename(install_name)
|
||||
#change install names to use rpaths
|
||||
logging.debug(" ~ " + name + " => @rpath/" + name)
|
||||
check_call([ "install_name_tool", "-change",
|
||||
install_name, "@rpath/" + name, lib ])
|
||||
|
||||
|
@ -305,12 +315,30 @@ def add_rpaths(graph, node, bundle_path):
|
|||
if rpath not in rpaths:
|
||||
rpaths.append(rpath)
|
||||
|
||||
for rpath in get_rpaths(lib):
|
||||
# Remove existing rpaths because the libraries copied into the
|
||||
# bundle will point to a location outside the bundle
|
||||
logging.debug(" - rpath: " + rpath)
|
||||
check_output(["install_name_tool", "-delete_rpath", rpath, lib])
|
||||
|
||||
for rpath in rpaths:
|
||||
# Ensure that lib has rpath set
|
||||
if not rpath in get_rpaths(lib):
|
||||
logging.debug(" + rpath: " + rpath + " to library " + lib)
|
||||
check_output([ "install_name_tool",
|
||||
"-add_rpath", rpath, lib ])
|
||||
|
||||
#Change the loader ID_DYLIB to a bundle-local name (i.e. non-absolute)
|
||||
logging.debug(" ~ id: " + node.name)
|
||||
check_output([ "install_name_tool", "-id", node.name, lib ])
|
||||
|
||||
def print_child(graph, node, path):
|
||||
logging.debug(" >" + str(node))
|
||||
|
||||
def print_node(graph, node, path):
|
||||
logging.debug(node)
|
||||
graph.visit(print_child, [node])
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print "Usage " + sys.argv[0] + " path [additional search paths]"
|
||||
|
@ -324,10 +352,23 @@ def main():
|
|||
"lib/python2.7/lib-dynload"]
|
||||
search_paths = [bundle_path + "/lib"] + sys.argv[2:]
|
||||
|
||||
#change to level to logging.DEBUG for diagnostic messages
|
||||
logging.basicConfig(stream=sys.stdout, level=logging.INFO,
|
||||
format="%(asctime)s %(levelname)s: %(message)s" )
|
||||
|
||||
logging.info("Analyzing bundle dependencies...")
|
||||
build_deps_graph(graph, bundle_path, dir_filter, search_paths)
|
||||
|
||||
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
|
||||
graph.visit(print_node, [bundle_path])
|
||||
|
||||
logging.info("Copying external dependencies to bundle...")
|
||||
graph.visit(copy_into_bundle, [bundle_path])
|
||||
|
||||
logging.info("Updating dynamic loader paths...")
|
||||
graph.visit(add_rpaths, [bundle_path])
|
||||
|
||||
logging.info("Done.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
Loading…
Reference in New Issue
Block a user