Skip to content
This repository has been archived by the owner on Mar 29, 2024. It is now read-only.

Commit

Permalink
improve Tulip-Python wheels generation on MacOS:
Browse files Browse the repository at this point in the history
  - remove Qt version restriction as universal Qt 4.8.7 from MacPorts is now used
  - now automatically gather and copy dylibs dependencies into wheels native folders
  - fix import of the tulipgui module when using the Anaconda Python distribution (as noticed by B. Renoust)

git-svn-id: https://svn.code.sf.net/p/auber/code/tulip@12589 f5d4c5f9-c943-4916-8a57-bd8605bf961c
  • Loading branch information
anlambert committed Jul 14, 2017
1 parent ded1e84 commit 7c3b81b
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 70 deletions.
6 changes: 0 additions & 6 deletions cmake/FindQtX.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,6 @@ ELSE(${Qt5Widgets_FOUND} AND ${Qt5OpenGL_FOUND} AND ${Qt5Network_FOUND})

SET(QT_VERSION "${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}")

IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR} VERSION_GREATER 4.7)
MESSAGE(SEND_ERROR "When building Tulip python wheels on MacOS, Qt version must be lesser than 4.8."
"Indeed we need universal binaries (i386;x86_64) to build a binary wheel and Qt 4.7 "
"is the last Qt version to provide bundles with universal binaries.")
ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR} VERSION_GREATER 4.7)

# define aliases for Qt macros
MACRO(QTX_WRAP_CPP outfiles)
QT4_WRAP_CPP(${outfiles} ${ARGN})
Expand Down
37 changes: 0 additions & 37 deletions library/tulip-python/bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,4 @@ ADD_SUBDIRECTORY(tulip-core)
IF(NOT TULIP_BUILD_CORE_ONLY)
ADD_SUBDIRECTORY(tulip-ogl)
ADD_SUBDIRECTORY(tulip-gui)

# When building Python wheels on MacOS, copy dependencies dylibs in wheels folders.
# They will be distributed and relinked when generating the wheels.
IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS)

MACRO(COPY_REAL_LIB symlink destination)
GET_FILENAME_COMPONENT(REAL_LIB ${symlink} REALPATH)
GET_FILENAME_COMPONENT(REAL_LIB_NAME ${REAL_LIB} NAME)
EXECUTE_PROCESS(COMMAND otool -DX ${symlink} OUTPUT_VARIABLE LINK_NAME)
STRING(REPLACE "\n" "" LINK_NAME "${LINK_NAME}")
GET_FILENAME_COMPONENT(LINK_NAME ${LINK_NAME} NAME)
FILE(COPY ${REAL_LIB} DESTINATION ${destination})
FILE(RENAME ${destination}/${REAL_LIB_NAME} ${destination}/${LINK_NAME})
ENDMACRO(COPY_REAL_LIB)

COPY_REAL_LIB(${ZLIB_LIBRARY} ${TULIP_PYTHON_NATIVE_FOLDER})
IF(QHULL_FOUND)
COPY_REAL_LIB(${QhullLibrary} ${TULIP_PYTHON_NATIVE_FOLDER})
ENDIF(QHULL_FOUND)
IF(YAJL_FOUND)
COPY_REAL_LIB(${YajlLibrary} ${TULIP_PYTHON_NATIVE_FOLDER})
ENDIF(YAJL_FOUND)
COPY_REAL_LIB(${FREETYPE_LIBRARY} ${TULIPOGL_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${GLEW_LIBRARY} ${TULIPOGL_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${JPEG_LIBRARY} ${TULIPOGL_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${PNG_LIBRARY_RELEASE} ${TULIPOGL_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${FREETYPE_LIBRARY} ${TULIPOGL_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTCORE_LIBRARY}/QtCore ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTGUI_LIBRARY}/QtGui ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTNETWORK_LIBRARY}/QtNetwork ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTXML_LIBRARY}/QtXml ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTOPENGL_LIBRARY}/QtOpenGL ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTWEBKIT_LIBRARY}/QtWebKit ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTXMLPATTERNS_LIBRARY}/QtXmlPatterns ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_PHONON_LIBRARY}/phonon ${TULIPGUI_PYTHON_NATIVE_FOLDER})
COPY_REAL_LIB(${QT_QTDBUS_LIBRARY}/QtDBus ${TULIPGUI_PYTHON_NATIVE_FOLDER})
ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS)
ENDIF(NOT TULIP_BUILD_CORE_ONLY)
42 changes: 29 additions & 13 deletions library/tulip-python/bindings/tulip-core/packaging/setup.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ from os import path
import platform
import subprocess
import sys
import shutil

# On MacOS, we need to relink dylibs and set correct rpaths in
# order for the modules to be imported in a portable way when
Expand All @@ -29,18 +30,10 @@ if platform.system() == 'Darwin' and len(sys.argv) > 1 and sys.argv[1] == 'bdist
def relinkDyLibAndSetRpaths(dylib, rpaths=[]):
libs = getDyLibDependencies(dylib)
for L in libs:
# prefer system libs for libbz
if 'libbz2.1.0.dylib' in L:
subprocess.call(
'install_name_tool -change %s /usr/lib/libbz2.1.0.dylib %s 2>/dev/null' %
(L, dylib),
shell=True)
# change not system libraries path to @rpath/libname
else:
subprocess.call(
'install_name_tool -change %s @rpath/%s %s 2>/dev/null' %
(L, os.path.basename(L), dylib),
shell=True)
subprocess.call(
'install_name_tool -change %s @rpath/%s %s 2>/dev/null' %
(L, os.path.basename(L), dylib),
shell=True)
# add rpaths in dylib
for rpath in rpaths:
subprocess.call(
Expand All @@ -52,12 +45,35 @@ if platform.system() == 'Darwin' and len(sys.argv) > 1 and sys.argv[1] == 'bdist
for lib in os.listdir(dirPath):
libPath = dirPath + lib
if not os.path.isdir(libPath):
deps = getDyLibDependencies(libPath)
relinkDyLibAndSetRpaths(libPath, rpaths)

def copyDyLibsDependencies(dirPath, relativeCopyPath = './'):
lastNbProcessed = 0
toProcess = os.listdir(dirPath)
while lastNbProcessed == 0 or len(toProcess) > lastNbProcessed:
for lib in toProcess:
libPath = dirPath + lib
if not os.path.isdir(libPath):
libs = getDyLibDependencies(libPath)
for L in libs:
filename = os.path.basename(L)
dylibCopy = dirPath + relativeCopyPath + filename
if not os.path.isfile(dylibCopy):
shutil.copyfile(L, dylibCopy)
subprocess.call(
'install_name_tool -id @rpath/%s %s 2>/dev/null' %
(filename, dylibCopy),
shell=True)
lastNbProcessed = len(toProcess)
toProcess = os.listdir(dirPath)


tulipNativeLibsPath = os.getcwd() + '/tulip/native/'
tulipNativePluginsLibsPath = os.getcwd() + '/tulip/native/plugins/'

print("Copying dylibs dependencies in tulip-python wheel ...")
copyDyLibsDependencies(tulipNativeLibsPath)
copyDyLibsDependencies(tulipNativePluginsLibsPath, '../')
print("Relinking dylibs and setting rpaths in tulip-python wheel ...")
relinkDyLibsInDirAndSetRpaths(tulipNativeLibsPath, ['@loader_path/'])
relinkDyLibsInDirAndSetRpaths(tulipNativePluginsLibsPath, ['@loader_path/..'])
Expand Down
46 changes: 32 additions & 14 deletions library/tulip-python/bindings/tulip-gui/packaging/setup.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import os
import subprocess
import sys
import subprocess
import shutil

# On MacOS, we need to relink dylibs and set correct rpaths in
# order for the modules to be imported in a portable way when
Expand All @@ -33,18 +34,10 @@ if platform.system() == 'Darwin' and len(sys.argv) > 1 and sys.argv[1] == 'bdist
def relinkDyLibAndSetRpaths(dylib, rpaths=[]):
libs = getDyLibDependencies(dylib)
for L in libs:
# prefer system libs for libbz
if 'libbz2.1.0.dylib' in L:
subprocess.call(
'install_name_tool -change %s /usr/lib/libbz2.1.0.dylib %s 2>/dev/null' %
(L, dylib),
shell=True)
# change not system libraries path to @rpath/libname
else:
subprocess.call(
'install_name_tool -change %s @rpath/%s %s 2>/dev/null' %
(L, os.path.basename(L), dylib),
shell=True)
subprocess.call(
'install_name_tool -change %s @rpath/%s %s 2>/dev/null' %
(L, os.path.basename(L), dylib),
shell=True)
# add rpaths in dylib
for rpath in rpaths:
subprocess.call(
Expand All @@ -56,15 +49,40 @@ if platform.system() == 'Darwin' and len(sys.argv) > 1 and sys.argv[1] == 'bdist
for lib in os.listdir(dirPath):
libPath = dirPath + lib
if not os.path.isdir(libPath):
deps = getDyLibDependencies(libPath)
relinkDyLibAndSetRpaths(libPath, rpaths)

def copyDyLibsDependencies(dirPath, relativeCopyPath = './'):
lastNbProcessed = 0
toProcess = os.listdir(dirPath)
while lastNbProcessed == 0 or len(toProcess) > lastNbProcessed:
for lib in toProcess:
libPath = dirPath + lib
if not os.path.isdir(libPath):
libs = getDyLibDependencies(libPath)
for L in libs:
filename = os.path.basename(L)
dylibCopy = dirPath + relativeCopyPath + filename
if not os.path.isfile(dylibCopy) and not os.path.isfile(tulipNativeLibsPath + filename) and not os.path.isfile(tulipOglNativeLibsPath + filename):
shutil.copyfile(L, dylibCopy)
subprocess.call(
'install_name_tool -id @rpath/%s %s 2>/dev/null' %
(filename, dylibCopy),
shell=True)
lastNbProcessed = len(toProcess)
toProcess = os.listdir(dirPath)

tulipNativeLibsPath = os.getcwd() + '/../../tulip-core/tulip_module/tulip/native/'
tulipOglNativeLibsPath = os.getcwd() + '/tulipogl/native/'
tulipOglNativePluginsLibsPath = os.getcwd() + '/tulipogl/native/plugins/'
tulipGuiNativeLibsPath = os.getcwd() + '/tulipgui/native/'
tulipGuiNativePluginsLibsPath = os.getcwd() + '/tulipgui/native/plugins/'

print("Relinking dylibs and setting rpaths in tulip-gui wheel ...")
print("Copying dylibs dependencies in tulipgui-python wheel ...")
copyDyLibsDependencies(tulipOglNativeLibsPath)
copyDyLibsDependencies(tulipOglNativePluginsLibsPath, '../')
copyDyLibsDependencies(tulipGuiNativeLibsPath)
copyDyLibsDependencies(tulipGuiNativePluginsLibsPath, '../')
print("Relinking dylibs and setting rpaths in tulipgui-python wheel ...")
relinkDyLibsInDirAndSetRpaths(tulipOglNativeLibsPath, ['@loader_path/', '@loader_path/../../tulip/native/'])
relinkDyLibsInDirAndSetRpaths(tulipOglNativePluginsLibsPath, ['@loader_path/..', '@loader_path/../../../tulip/native/'])
relinkDyLibsInDirAndSetRpaths(tulipGuiNativeLibsPath, ['@loader_path/', '@loader_path/../../tulip/native/', '@loader_path/../../tulipogl/native/'])
Expand Down

0 comments on commit 7c3b81b

Please sign in to comment.