diff --git a/.travis.yml b/.travis.yml index 100c6e449..08db1b4c1 100755 --- a/.travis.yml +++ b/.travis.yml @@ -144,7 +144,7 @@ before_install: fi export CMAKE_ARGS="${CMAKE_OPTS} -DFREECAD_USE_EXTERNAL_KDL=ON -DFREECAD_USE_EXTERNAL_PIVY=ON -DFREECAD_CREATE_MAC_APP=ON" - export INSTALLED_APP_PATH="/usr/local/FreeCAD.app/Contents/bin/FreeCAD" + export INSTALLED_APP_PATH="/usr/local/FreeCAD.app/Contents/MacOS/FreeCAD" ;; *) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d0d6d64..033ea4d54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,7 +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) + set(CMAKE_MACOSX_RPATH TRUE) endif(APPLE) OPTION(BUILD_FEM "Build the FreeCAD FEM module" ON) diff --git a/src/MacAppBundle/FreeCAD.app/Contents/MacOS/FreeCAD b/src/MacAppBundle/FreeCAD.app/Contents/MacOS/FreeCAD deleted file mode 120000 index 98ca77ada..000000000 --- a/src/MacAppBundle/FreeCAD.app/Contents/MacOS/FreeCAD +++ /dev/null @@ -1 +0,0 @@ -../bin/FreeCAD \ No newline at end of file diff --git a/src/MacAppBundle/FreeCAD.app/Contents/bin/FreeCAD b/src/MacAppBundle/FreeCAD.app/Contents/bin/FreeCAD new file mode 120000 index 000000000..41942cc6e --- /dev/null +++ b/src/MacAppBundle/FreeCAD.app/Contents/bin/FreeCAD @@ -0,0 +1 @@ +../MacOS/FreeCAD \ No newline at end of file diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt index 3432ff54e..b783d164d 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -49,11 +49,16 @@ if(BUILD_GUI) RUNTIME DESTINATION bin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - else(WIN32) + elseif(APPLE) + INSTALL(TARGETS FreeCADMain + RUNTIME DESTINATION MacOS + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + else() INSTALL(TARGETS FreeCADMain RUNTIME DESTINATION bin ) - endif(WIN32) + endif() endif(BUILD_GUI) ######################## FreeCADMainCmd ######################## diff --git a/src/Tools/MakeMacBundleRelocatable.py b/src/Tools/MakeMacBundleRelocatable.py index 6bcfd1417..3950c3e9c 100755 --- a/src/Tools/MakeMacBundleRelocatable.py +++ b/src/Tools/MakeMacBundleRelocatable.py @@ -160,7 +160,8 @@ def create_dep_nodes(install_names, search_paths): path = install_path if not path: - raise LibraryNotFound(lib_name + "not found in given paths") + logging.error("Unable to find LC_DYLD_LOAD entry: " + lib) + raise LibraryNotFound(lib_name + " not found in given search paths") nodes.append(Node(lib_name, path)) @@ -190,9 +191,9 @@ def should_visit(prefix, path_filters, path): s_filter = pf.strip('/').split('/') length = len(s_filter) matched = 0 - for i in range(len(s_path)): - if s_path[i] == s_filter[i]: - matched += 1 + for i in range(len(s_path)): + if s_path[i] == s_filter[i]: + matched += 1 if matched == length or matched == len(s_path): return True @@ -234,7 +235,12 @@ def build_deps_graph(graph, bundle_path, dirs_filter=None, search_paths=[]): if not graph.in_graph(node): graph.add_node(node) - deps = create_dep_nodes(list_install_names(k2), s_paths) + try: + deps = create_dep_nodes(list_install_names(k2), s_paths) + except: + logging.error("Failed to resolve dependency in " + k2) + raise + for d in deps: if d.name not in node.children: node.children.append(d.name) @@ -256,15 +262,12 @@ def copy_into_bundle(graph, node, bundle_path): target = os.path.join(bundle_path, "lib", node.name) logging.info("Bundling {}".format(source)) - check_output([ "cp", "-L", source, target ]) + check_call([ "cp", "-L", source, target ]) node.path = os.path.dirname(target) #fix permissions - 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 ]) + check_call([ "chmod", "a+w", target ]) def get_rpaths(library): "Returns a list of rpaths specified within library" @@ -290,47 +293,53 @@ def get_rpaths(library): return rpaths def add_rpaths(graph, node, bundle_path): - if node.children: - lib = os.path.join(node.path, node.name) - if in_bundle(lib, bundle_path): - install_names = list_install_names(lib) - rpaths = [] + lib = os.path.join(node.path, node.name) - 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 ]) + if in_bundle(lib, bundle_path): + logging.debug(lib) - dep_node = node.children[node.children.index(name)] - rel_path = os.path.relpath(graph.get_node(dep_node).path, + # Remove existing rpaths that could take precedence + for rpath in get_rpaths(lib): + logging.debug(" - rpath: " + rpath) + check_call(["install_name_tool", "-delete_rpath", rpath, lib]) + + if node.children: + install_names = list_install_names(lib) + rpaths = [] + + + for install_name in install_names: + name = os.path.basename(install_name) + #change install names to use rpaths + logging.debug(" ~ rpath: " + name + " => @rpath/" + name) + check_call([ "install_name_tool", "-change", + install_name, "@rpath/" + name, lib ]) + + dep_node = node.children[node.children.index(name)] + rel_path = os.path.relpath(graph.get_node(dep_node).path, node.path) - rpath = "" - if rel_path == ".": - rpath = "@loader_path/" - else: - rpath = "@loader_path/" + rel_path + "/" - if rpath not in rpaths: - rpaths.append(rpath) + rpath = "" + if rel_path == ".": + rpath = "@loader_path/" + else: + rpath = "@loader_path/" + rel_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) + check_call([ "install_name_tool", "-add_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 ]) +def change_libid(graph, node, bundle_path): + lib = os.path.join(node.path, node.name) - #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 ]) + logging.debug(lib) + + if in_bundle(lib, bundle_path): + logging.debug(" ~ id: " + node.name) + check_call([ "install_name_tool", "-id", node.name, lib ]) def print_child(graph, node, path): logging.debug(" >" + str(node)) @@ -354,7 +363,7 @@ def main(): #change to level to logging.DEBUG for diagnostic messages logging.basicConfig(stream=sys.stdout, level=logging.INFO, - format="%(asctime)s %(levelname)s: %(message)s" ) + format="-- %(message)s" ) logging.info("Analyzing bundle dependencies...") build_deps_graph(graph, bundle_path, dir_filter, search_paths) @@ -368,6 +377,9 @@ def main(): logging.info("Updating dynamic loader paths...") graph.visit(add_rpaths, [bundle_path]) + logging.info("Setting bundled library IDs...") + graph.visit(change_libid, [bundle_path]) + logging.info("Done.") if __name__ == "__main__":