diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83d2a6c0e..337fd7af8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -126,11 +126,21 @@ if(APPLE)
if(FREECAD_CREATE_MAC_APP)
install(
- DIRECTORY ${CMAKE_SOURCE_DIR}/src/MacAppBundle/FreeCAD.app
- DESTINATION ${CMAKE_INSTALL_PREFIX}
+ DIRECTORY ${CMAKE_SOURCE_DIR}/src/MacAppBundle/FreeCAD.app/
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/${PACKAGE_NAME}.app
)
- set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/FreeCAD.app/Contents)
- SET(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib)
+
+ # It should be safe to assume we've got sed on OSX...
+ install(CODE "
+ execute_process(COMMAND
+ sed -i \"\" -e s/VERSION_STRING_FROM_CMAKE/${PACKAGE_VERSION}/
+ -e s/NAME_STRING_FROM_CMAKE/${PACKAGE_NAME}/
+ ${CMAKE_INSTALL_PREFIX}/${PACKAGE_NAME}.app/Contents/Info.plist)
+ ")
+
+ set(CMAKE_INSTALL_PREFIX
+ ${CMAKE_INSTALL_PREFIX}/${PACKAGE_NAME}.app/Contents)
+ set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib)
endif(FREECAD_CREATE_MAC_APP)
endif(APPLE)
@@ -419,9 +429,122 @@ if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER)
# -------------------------------- Python --------------------------------
+#http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=677598
+# Acceptable versions of Python
+set(Python_ADDITIONAL_VERSIONS "2.3" "2.4" "2.5" "2.6" "2.7" "2.8" "2.9")
+
+# For building on OS X
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+
+ # If the user doesn't tell us which package manager they're using
+ if(NOT DEFINED MACPORTS_PREFIX AND NOT DEFINED HOMEBREW_PREFIX)
+
+ # Try to find MacPorts path
+ find_program(MACPORTS_EXECUTABLE port)
+ if(EXISTS ${MACPORTS_EXECUTABLE})
+ string(REPLACE "/bin/port" ""
+ MACPORTS_PREFIX ${MACPORTS_EXECUTABLE})
+ message(STATUS "Detected MacPorts install at ${MACPORTS_PREFIX}")
+ endif(EXISTS ${MACPORTS_EXECUTABLE})
+
+ # Try to find Homebrew path
+ find_program(HOMEBREW_EXECUTABLE brew)
+ if(EXISTS ${HOMEBREW_EXECUTABLE})
+ set(HOMEBREW_PREFIX "/usr/local")
+ message(STATUS "Detected Homebrew install at ${HOMEBREW_PREFIX}")
+ endif()
+
+ endif(NOT DEFINED MACPORTS_PREFIX AND NOT DEFINED HOMEBREW_PREFIX)
+
+ # In case someone tries to shoot themselves in the foot
+ if(DEFINED MACPORTS_PREFIX AND DEFINED HOMEBREW_PREFIX)
+ message(SEND_ERROR
+ "Multiple package management systems detected - ")
+ message(SEND_ERROR
+ "define either MACPORTS_PREFIX or HOMEBREW_PREFIX")
+
+ # No package manager
+ elseif(NOT DEFINED MACPORTS_PREFIX AND NOT DEFINED HOMEBREW_PREFIX)
+ message(SEND_ERROR
+ "No package manager detected - install MacPorts or Homebrew")
+
+ # The hopefully-normal case - one package manager identified
+ else(DEFINED MACPORTS_PREFIX AND DEFINED HOMEBREW_PREFIX)
+
+ # Construct a list like python;python2.9;python2.8;...
+ set(Python_ADDITIONAL_VERSIONS_REV ${Python_ADDITIONAL_VERSIONS})
+ list(REVERSE Python_ADDITIONAL_VERSIONS_REV)
+ set(_PYTHON_NAMES "python")
+ foreach(_PYTHON_VERSION IN LISTS Python_ADDITIONAL_VERSIONS_REV)
+ list(APPEND _PYTHON_NAMES "python${_PYTHON_VERSION}")
+ endforeach(_PYTHON_VERSION)
+
+ # Find python in the package management systems, using names in that
+ # list in decreasing priority. Note that a manually specified
+ # PYTHON_EXECUTABLE still has prescedence over this.
+ find_program(PYTHON_EXECUTABLE
+ NAMES ${_PYTHON_NAMES}
+ PATHS ${MACPORTS_PREFIX} ${HOMEBREW_PREFIX}
+ PATH_SUFFIXES /bin
+ NO_DEFAULT_PATH)
+
+ endif(DEFINED MACPORTS_PREFIX AND DEFINED HOMEBREW_PREFIX)
+
+ # Warn user if we still only have the system Python
+ string(FIND ${PYTHON_EXECUTABLE} "/usr/bin/python" _FIND_SYS_PYTHON)
+ if(_FIND_SYS_PYTHON EQUAL 0)
+ message(SEND_ERROR
+ "Only found the stock Python, that's probably bad.")
+ endif(_FIND_SYS_PYTHON EQUAL 0)
+
+ # Ask Python to tell us it's include directory, if nobody else has
+ if(NOT DEFINED PYTHON_INCLUDE_DIR)
+ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c
+ "from distutils.sysconfig import get_python_inc;print get_python_inc()"
+ OUTPUT_VARIABLE PYTHON_INCLUDE_DIR
+ RESULT_VARIABLE PYTHON_INCLUDE_DIR_RESULT
+ ERROR_QUIET)
+ if(NOT PYTHON_INCLUDE_DIR_RESULT MATCHES 0)
+ message(SEND_ERROR "Failed to determine PYTHON_INCLUDE_DIR")
+ endif(NOT PYTHON_INCLUDE_DIR_RESULT MATCHES 0)
+ endif(NOT DEFINED PYTHON_INCLUDE_DIR)
+
+ # Similar for the Python library - there must be an easier way...
+ if(NOT DEFINED PYTHON_LIBRARY)
+ # Get the library path
+ execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c
+ "from distutils import sysconfig;print sysconfig.get_config_var('LIBDIR')"
+ OUTPUT_VARIABLE PYTHON_LIBRARY_DIR
+ RESULT_VARIABLE PYTHON_LIBRARY_DIR_RESULT
+ ERROR_QUIET)
+ string(STRIP ${PYTHON_LIBRARY_DIR} PYTHON_LIBRARY_DIR)
+ if(NOT PYTHON_LIBRARY_DIR_RESULT MATCHES 0)
+ message(SEND_ERROR "Failed to determine PYTHON_LIBRARY")
+ endif(NOT PYTHON_LIBRARY_DIR_RESULT MATCHES 0)
+
+ # Get library filename - might not be safe to assume .dylib extension?
+ execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c
+ "import sys;print 'libpython%d.%d.dylib'%sys.version_info[0:2]"
+ OUTPUT_VARIABLE PYTHON_LIBRARY_FILE
+ RESULT_VARIABLE PYTHON_LIBRARY_FILE_RESULT
+ ERROR_QUIET)
+ string(STRIP ${PYTHON_LIBRARY_FILE} PYTHON_LIBRARY_FILE)
+ if(NOT PYTHON_LIBRARY_FILE_RESULT MATCHES 0)
+ message(SEND_ERROR "Failed to determine PYTHON_LIBRARY")
+ endif(NOT PYTHON_LIBRARY_FILE_RESULT MATCHES 0)
+
+ set(PYTHON_LIBRARY "${PYTHON_LIBRARY_DIR}/${PYTHON_LIBRARY_FILE}")
+
+ else(NOT DEFINED PYTHON_LIBRARY)
+ # Used on MacPorts systems for finding Shiboken and PySide
+ # TODO: When we start requiring minimum CMake version above
+ # 2.8.11, change PATH below to DIRECTORY
+ get_filename_component(PYTHON_LIBRARY_DIR ${PYTHON_LIBRARY} PATH)
+ endif(NOT DEFINED PYTHON_LIBRARY)
+
+
+endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- #http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=677598
- set(Python_ADDITIONAL_VERSIONS "2.3" "2.4" "2.5" "2.6" "2.7" "2.8" "2.9")
find_package(PythonInterp REQUIRED)
IF (NOT DEFINED PYTHON_VERSION_STRING)
find_package(PythonLibs REQUIRED)
@@ -429,8 +552,9 @@ if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER)
find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT)
ENDIF(NOT DEFINED PYTHON_VERSION_STRING)
+
IF(NOT PYTHONLIBS_FOUND)
- MESSAGE("Python not found, install python!")
+ MESSAGE(FATAL_ERROR "Python not found, install python!")
ENDIF(NOT PYTHONLIBS_FOUND)
# -------------------------------- pcl ----------------------------------
@@ -599,6 +723,12 @@ if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER)
# set(PYTHON_SUFFIX -python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})
SET(PYTHON_SUFFIX -python2.7) # for shiboken
SET(PYTHON_BASENAME -python2.7) # for PySide
+
+ if(DEFINED MACPORTS_PREFIX)
+ find_package(Shiboken REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake")
+ find_package(PySide REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake")
+ endif(DEFINED MACPORTS_PREFIX)
+
find_package(Shiboken REQUIRED)
find_package(PySide REQUIRED)
find_package(PySideTools REQUIRED) # Pyside utilities (pyside-uic & pyside-rcc)
diff --git a/cMake/FindOpenCasCade.cmake b/cMake/FindOpenCasCade.cmake
index 4590d674d..6319fbf6a 100644
--- a/cMake/FindOpenCasCade.cmake
+++ b/cMake/FindOpenCasCade.cmake
@@ -9,7 +9,14 @@
# First try to find OpenCASCADE Community Edition
if(NOT DEFINED OCE_DIR)
- if(UNIX)
+ # Check for OSX needs to come first because UNIX evaluates to true on OSX
+ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ if(DEFINED MACPORTS_PREFIX)
+ find_package(OCE HINTS ${MACPORTS_PREFIX}/Library/Frameworks)
+ elseif(DEFINED HOMEBREW_PREFIX)
+ find_package(OCE HINTS ${HOMEBREW_PREFIX}/Cellar/oce/*)
+ endif()
+ elseif(UNIX)
set(OCE_DIR "/usr/local/share/cmake/")
elseif(WIN32)
set(OCE_DIR "c:/OCE-0.4.0/share/cmake")
@@ -126,5 +133,5 @@ if(OCC_FOUND)
message(STATUS "-- OCE/OpenCASCADE include directory: ${OCC_INCLUDE_DIR}")
message(STATUS "-- OCE/OpenCASCADE shared libraries directory: ${OCC_LIBRARY_DIR}")
else(OCC_FOUND)
- message("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
+ message(SEND_ERROR "Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
endif(OCC_FOUND)
diff --git a/cMake/FindPySideTools.cmake b/cMake/FindPySideTools.cmake
index 0a2caae5d..053cb93e0 100644
--- a/cMake/FindPySideTools.cmake
+++ b/cMake/FindPySideTools.cmake
@@ -14,17 +14,14 @@ IF(PYSIDEUIC4BINARY AND PYSIDERCC4BINARY)
set(PYSIDE_TOOLS_FOUND_QUIETLY TRUE)
ENDIF(PYSIDEUIC4BINARY AND PYSIDERCC4BINARY)
-if(WIN32 OR APPLE)
+if(WIN32 OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
#pyside tools are often in same location as python interpreter
get_filename_component(PYTHON_BIN_DIR ${PYTHON_EXECUTABLE} PATH)
set(PYSIDE_BIN_DIR ${PYTHON_BIN_DIR})
-endif(WIN32 OR APPLE)
+endif(WIN32 OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-FIND_PROGRAM(PYSIDEUIC4BINARY pyside-uic HINTS ${PYSIDE_BIN_DIR})
-FIND_PROGRAM(PYSIDERCC4BINARY pyside-rcc HINTS ${PYSIDE_BIN_DIR})
-
-#message(STATUS "PYSIDEUIC4BINARY ${PYSIDEUIC4BINARY}" )
-#message(STATUS "PYSIDERCC4BINARY ${PYSIDERCC4BINARY}" )
+FIND_PROGRAM(PYSIDEUIC4BINARY NAMES pyside-uic pyside-uic-${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} HINTS ${PYSIDE_BIN_DIR})
+FIND_PROGRAM(PYSIDERCC4BINARY NAMES pyside-rcc pyside-rcc-${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} HINTS ${PYSIDE_BIN_DIR})
MACRO(PYSIDE_WRAP_UI outfiles)
FOREACH(it ${ARGN})
diff --git a/src/MacAppBundle/CMakeLists.txt b/src/MacAppBundle/CMakeLists.txt
index adaa64774..d451dca5f 100644
--- a/src/MacAppBundle/CMakeLists.txt
+++ b/src/MacAppBundle/CMakeLists.txt
@@ -21,8 +21,11 @@ get_filename_component(APP_PATH ${CMAKE_INSTALL_PREFIX} PATH)
install(CODE
"message(STATUS \"Making bundle relocatable...\")
+ # The top-level CMakeLists.txt should prevent multiple package manager
+ # prefixes from being set, so the lib path will resolve correctly...
execute_process(
- COMMAND ${PYTHON_EXECUTABLE}
- ${CMAKE_SOURCE_DIR}/src/Tools/MakeMacBundleRelocatable.py ${APP_PATH}
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${CMAKE_SOURCE_DIR}/src/Tools/MakeMacBundleRelocatable.py
+ ${APP_PATH} ${HOMEBREW_PREFIX}${MACPORTS_PREFIX}/lib
)"
)
diff --git a/src/MacAppBundle/FreeCAD.app/Contents/Info.plist b/src/MacAppBundle/FreeCAD.app/Contents/Info.plist
index 747d3002c..061b16d6c 100644
--- a/src/MacAppBundle/FreeCAD.app/Contents/Info.plist
+++ b/src/MacAppBundle/FreeCAD.app/Contents/Info.plist
@@ -17,7 +17,7 @@
CFBundleLongVersionString
CFBundleName
- FreeCAD
+ NAME_STRING_FROM_CMAKE
CFBundlePackageType
APPL
CFBundleShortVersionString
@@ -25,7 +25,7 @@
CFBundleSignature
????
CFBundleVersion
- 0.14-dev
+ VERSION_STRING_FROM_CMAKE
CSResourcesFileMapped
NSHumanReadableCopyright
diff --git a/src/Tools/MakeMacBundleRelocatable.py b/src/Tools/MakeMacBundleRelocatable.py
index de863c901..d44a94963 100644
--- a/src/Tools/MakeMacBundleRelocatable.py
+++ b/src/Tools/MakeMacBundleRelocatable.py
@@ -3,7 +3,7 @@ import sys
import subprocess
import pprint
-SYS_PATHS = ["/System/","/usr/lib/"]
+SYS_PATHS = ["/System/", "/usr/lib/"]
class LibraryNotFound(Exception):
pass
@@ -64,7 +64,7 @@ class DepsGraph:
operation(self, self.graph[node_key], *op_args)
def is_macho(path):
- output = subprocess.check_output(["file",path])
+ output = subprocess.check_output(["file", path])
if output.count("Mach-O") != 0:
return True
@@ -134,7 +134,7 @@ def create_dep_nodes(install_names, search_paths):
path = install_path
if not path:
- raise LibraryNotFound("{0} not found in given paths".format(lib_name))
+ raise LibraryNotFound(lib_name + "not found in given paths")
nodes.append(Node(lib_name, path))
@@ -155,10 +155,6 @@ def should_visit(prefix, path_filters, path):
#we only want to use filters if they have the same parent as path
for rel_pf in path_filters:
pf = os.path.join(prefix, rel_pf)
- #print(path)
- #print(pf)
- #print(os.path.split(pf)[0] == os.path.split(path)[0])
- #print('----')
if os.path.split(pf)[0] == os.path.split(path)[0]:
filters.append(pf)
if not filters:
@@ -189,7 +185,7 @@ def build_deps_graph(graph, bundle_path, dirs_filter=None, search_paths=[]):
for root, dirs, files in os.walk(bundle_path):
if dirs_filter != None:
- dirs[:] = [d for d in dirs if should_visit(bundle_path, dirs_filter,
+ dirs[:] = [d for d in dirs if should_visit(bundle_path, dirs_filter,
os.path.join(root, d))]
s_paths.insert(0, root)
@@ -197,7 +193,8 @@ def build_deps_graph(graph, bundle_path, dirs_filter=None, search_paths=[]):
for f in files:
fpath = os.path.join(root, f)
ext = os.path.splitext(f)[1]
- if (ext == "" and is_macho(fpath)) or ext == ".so" or ext == ".dylib":
+ if ( (ext == "" and is_macho(fpath)) or
+ ext == ".so" or ext == ".dylib" ):
visited[fpath] = False
stack = []
@@ -223,8 +220,6 @@ def build_deps_graph(graph, bundle_path, dirs_filter=None, search_paths=[]):
if not visited[dk]:
stack.append(dk)
-
-
def in_bundle(lib, bundle_path):
if lib.startswith(bundle_path):
return True
@@ -232,12 +227,13 @@ def in_bundle(lib, bundle_path):
def copy_into_bundle(graph, node, bundle_path):
if not in_bundle(node.path, bundle_path):
- subprocess.check_call(["cp","-L",os.path.join(node.path,node.name),
- os.path.join(bundle_path,"lib",node.name)])
- node.path = os.path.join(bundle_path,"lib")
-
- #fix permissions
- subprocess.check_call(["chmod", "a+w", os.path.join(bundle_path,"lib",node.name)])
+ subprocess.check_call(["cp", "-L", os.path.join(node.path, node.name),
+ os.path.join(bundle_path, "lib", node.name)])
+ node.path = os.path.join(bundle_path, "lib")
+
+ #fix permissions
+ subprocess.check_call(["chmod", "a+w", os.path.join(bundle_path,
+ "lib", node.name)])
def add_rpaths(graph, node, bundle_path):
if node.children:
@@ -249,11 +245,12 @@ def add_rpaths(graph, node, bundle_path):
for install_name in install_names:
name = os.path.basename(install_name)
#change install names to use rpaths
- subprocess.check_call(["install_name_tool","-change",
+ subprocess.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)
+ rel_path = os.path.relpath(graph.get_node(dep_node).path,
+ node.path)
rpath = ""
if rel_path == ".":
rpath = "@loader_path/"
@@ -264,21 +261,21 @@ def add_rpaths(graph, node, bundle_path):
for path in rpaths:
subprocess.call(["install_name_tool", "-add_rpath", path, lib])
-def print_node(graph, node):
- print(os.path.join(node.path, node.name))
-
def main():
+ if len(sys.argv) < 2:
+ print "Usage " + sys.argv[0] + " path [additional search paths]"
+ quit()
+
path = sys.argv[1]
bundle_path = os.path.abspath(os.path.join(path, "Contents"))
graph = DepsGraph()
- dir_filter = ["bin","lib", "Mod","Mod/PartDesign",
+ dir_filter = ["bin", "lib", "Mod", "Mod/PartDesign",
"lib/python2.7/site-packages",
"lib/python2.7/lib-dynload"]
- search_paths = [bundle_path + "/lib", "/usr/local/lib", "/usr/local/Cellar/freetype/2.5.4/lib"]
-
+ search_paths = [bundle_path + "/lib"] + sys.argv[2:]
+
build_deps_graph(graph, bundle_path, dir_filter, search_paths)
- #graph.visit(print_node)
graph.visit(copy_into_bundle, [bundle_path])
graph.visit(add_rpaths, [bundle_path])