From 4cbd8d7393f8864cb6f5719ce63afad17b7b18e9 Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Mon, 1 Oct 2018 19:23:46 +0200 Subject: [PATCH 1/6] travis.yml: Fix some MacOS builds Use Sphinx 1.7 as Sphinx 1.8 seems buggy on that platform. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02c7de0862..c9c3cdb5bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -411,7 +411,7 @@ jobs: - sudo port -N install cppunit - curl -O https://bootstrap.pypa.io/get-pip.py - sudo python get-pip.py - - sudo pip install sphinx + - sudo pip install sphinx==1.7.9 env: # use system Python 2.7 @@ -462,7 +462,7 @@ jobs: - sudo port -N install cppunit - curl -O https://bootstrap.pypa.io/get-pip.py - sudo python get-pip.py - - sudo pip install sphinx --ignore-installed six + - sudo pip install sphinx==1.7.9 --ignore-installed six env: # use system Python 2.7 - PYTHON_EXECUTABLE=/usr/bin/python2.7 From 2bd39b662c1a8528ef84dcbd0156f4b3ecaac209 Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Mon, 1 Oct 2018 19:33:12 +0200 Subject: [PATCH 2/6] AppVeyor: Fix and improve MSYS2 builds - store the Inetc NSIS plugin in the repository instead of downloading it - use CMake provided by AppVeyor instead of the MSYS2 one - force install dependencies - remove Sphinx/Doxygen installation as it is not needed anymore --- appveyor_msys2.bat | 35 +++++++++++++---------------------- bundlers/win/Inetc.zip | Bin 0 -> 83045 bytes 2 files changed, 13 insertions(+), 22 deletions(-) create mode 100644 bundlers/win/Inetc.zip diff --git a/appveyor_msys2.bat b/appveyor_msys2.bat index 9c36df16ad..d091b64ffb 100644 --- a/appveyor_msys2.bat +++ b/appveyor_msys2.bat @@ -12,22 +12,20 @@ rem Upgrade the MSYS2 platform bash -lc "pacman --noconfirm --sync --refresh --sysupgrade" rem Install required tools -bash -lc "pacman --noconfirm -S --needed base-devel wget unzip mingw-w64-%MSYS2_ARCH%-toolchain" +bash -lc "pacman --noconfirm -S --needed base-devel unzip mingw-w64-%MSYS2_ARCH%-toolchain" rem Install the relevant native dependencies -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-yajl" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-qhull" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-freetype" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-glew" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-libpng" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-pcre2" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-qt5" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-quazip" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-qtwebkit" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-cppunit" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-cmake" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-ccache" -bash -lc "pacman --noconfirm -S --needed mingw-w64-%MSYS2_ARCH%-doxygen" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-yajl" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-qhull" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-freetype" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-glew" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-libpng" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-pcre2" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-qt5" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-quazip" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-qtwebkit" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-cppunit" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-ccache" rem Invoke subsequent bash in the build tree cd %APPVEYOR_BUILD_FOLDER% @@ -38,14 +36,7 @@ bash -lc "set pwd" bash -lc "env" rem Install Inetc plugin for NSIS -rem because the connection to the original source site seems to be difficult -rem if it fails we use our copy -curl -fsS -o Inetc.zip http://nsis.sourceforge.net/mediawiki/images/c/c9/Inetc.zip || curl -fsS -o Inetc.zip http://tulip.labri.fr/code/Inetc.zip -7z x Inetc.zip -o"C:\Program Files (x86)\NSIS" - -rem Install sphinx for Python 3 -set PATH=%PYTHON3_HOME%;%PYTHON3_HOME%/Scripts;%PATH% -pip install sphinx +bash -lc "unzip bundlers/win/Inetc.zip -d\"C:\Program Files (x86)\NSIS\"" rem Build Tulip with Python 3, run its unit tests and package it bash -lc "mkdir build" diff --git a/bundlers/win/Inetc.zip b/bundlers/win/Inetc.zip new file mode 100644 index 0000000000000000000000000000000000000000..c3d233fadc2128cfe10b4c011f9e2e74872b5ab5 GIT binary patch literal 83045 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 Date: Wed, 26 Sep 2018 22:00:44 +0200 Subject: [PATCH 3/6] tulip-python: Remove tulipgui packaging and deployment on PyPI Distributing tulipgui-python on PyPI was a silly idea from my part. Thinking it back, only tulip-python should be provided on PyPI. The reasons of this removal are the following: - the module is not really used - bundling needed binaries in the wheel (notably the Qt ones) is painful and hard to maintain (especially on Linux) - the module is quite redundant with the main Tulip software, while being less intuituve to use Previous users should now be redirected to use the main Tulip software for visualization purposes or use the modules located in an official Tulip installation instead. --- CMakeLists.txt | 88 +++++-------- cmake/FindQtX.cmake | 9 +- cmake/TulipUseFile.cmake | 29 +---- doc/CMakeLists.txt | 12 +- library/CMakeLists.txt | 4 +- library/tulip-core/src/CMakeLists.txt | 8 +- library/tulip-gui/src/CMakeLists.txt | 4 - library/tulip-ogdf/CMakeLists.txt | 6 +- library/tulip-ogl/bitmaps/CMakeLists.txt | 21 --- library/tulip-ogl/src/CMakeLists.txt | 4 - library/tulip-python/CMakeLists.txt | 6 +- library/tulip-python/bindings/CMakeLists.txt | 4 +- .../tulip-python/bindings/stl/CMakeLists.txt | 10 +- .../bindings/tulip-core/CMakeLists.txt | 28 ++-- .../bindings/tulip-core/packaging/README.rst | 3 +- .../bindings/tulip-gui/CMakeLists.txt | 56 +------- .../bindings/tulip-gui/packaging/MANIFEST.in | 1 - .../bindings/tulip-gui/packaging/README.rst | 123 ------------------ .../configure_tulipgui_python_setup.cmake | 2 - .../copyTulipGuiDllDependencies.cmake | 72 ---------- .../bindings/tulip-gui/packaging/setup.cfg.in | 10 -- library/tulip-python/modules/CMakeLists.txt | 8 +- library/tulip-python/plugins/CMakeLists.txt | 6 +- plugins/CMakeLists.txt | 7 +- plugins/clustering/CMakeLists.txt | 10 +- plugins/colors/CMakeLists.txt | 6 +- plugins/export/CMakeLists.txt | 6 +- plugins/glyph/CMakeLists.txt | 9 -- plugins/import/CMakeLists.txt | 14 +- textures/CMakeLists.txt | 6 - thirdparty/CMakeLists.txt | 4 +- thirdparty/OGDF/CMakeLists.txt | 6 +- thirdparty/ftgl/CMakeLists.txt | 4 - thirdparty/gzstream/CMakeLists.txt | 8 +- thirdparty/libtess2/CMakeLists.txt | 4 - thirdparty/quazip/CMakeLists.txt | 4 - thirdparty/sip-4.19.12/siplib/CMakeLists.txt | 16 +-- thirdparty/yajl/src/CMakeLists.txt | 8 +- 38 files changed, 130 insertions(+), 496 deletions(-) delete mode 100644 library/tulip-python/bindings/tulip-gui/packaging/MANIFEST.in delete mode 100644 library/tulip-python/bindings/tulip-gui/packaging/README.rst delete mode 100644 library/tulip-python/bindings/tulip-gui/packaging/configure_tulipgui_python_setup.cmake delete mode 100644 library/tulip-python/bindings/tulip-gui/packaging/copyTulipGuiDllDependencies.cmake delete mode 100644 library/tulip-python/bindings/tulip-gui/packaging/setup.cfg.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fd0f088ac..051a94b921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,14 +239,14 @@ IF(TULIP_BUILD_PYTHON_COMPONENTS) SET(TULIPGUI_PYTHON_FOLDER ${TULIPGUI_PYTHON_ROOT_FOLDER}/tulipgui) SET(TULIP_PYTHON_NATIVE_FOLDER ${TULIP_PYTHON_FOLDER}/native) SET(TULIPGUI_PYTHON_NATIVE_FOLDER ${TULIPGUI_PYTHON_FOLDER}/native) - SET(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS OFF CACHE BOOL "Add a wheel make target for generating Tulip Python modules wheels ? [ON|OFF]") - IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND APPLE) + SET(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET OFF CACHE BOOL "Add a wheel make target for generating Tulip Python module wheel ? [ON|OFF]") + IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND APPLE) # build universal binaries when generating Tulip Python wheels for MacOs SET(CMAKE_OSX_ARCHITECTURES "i386;x86_64") # build binaries with install rpath when generating Tulip Python wheels for MacOs # as we don't install the project in that case SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON) - ELSEIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND LINUX) + ELSEIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND LINUX) FILE(READ /etc/issue LINUX_ISSUE) IF(NOT "${LINUX_ISSUE}" MATCHES ".*CentOS release 5\\.11 \\(Final\\).*" OR NOT EXISTS /usr/local/bin/auditwheel) MESSAGE(FATAL_ERROR "Python binary wheels for Linux platform must be compiled using the CentOS 5.11 docker image provided by the manylinux project from the Python Packaging Authority.\nSee https://github.com/pypa/manylinux for more details.") @@ -254,7 +254,7 @@ IF(TULIP_BUILD_PYTHON_COMPONENTS) # build binaries with install rpath when generating Tulip Python wheels for Linux # as we don't install the project in that case SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON) - ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND APPLE) + ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND APPLE) ENDIF(TULIP_BUILD_PYTHON_COMPONENTS) ## ======================================================== @@ -357,7 +357,7 @@ IF(NOT CLANG OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.7.0 OR CMAKE_CXX_CO ENDIF(NOT CMAKE_BUILD_TYPE STREQUAL "") ENDIF(NOT CLANG OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 3.7.0) -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) # OpenGL FIND_PACKAGE(OpenGL REQUIRED) @@ -378,7 +378,7 @@ IF(NOT TULIP_BUILD_CORE_ONLY) # Quazip FIND_PACKAGE(QuaZip) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) IF(TULIP_BUILD_PYTHON_COMPONENTS) @@ -459,7 +459,7 @@ else: # Ensure that correct Python include path and library are selected by CMake on Linux (in case of non standard installation) ELSEIF(LINUX) SET(CMAKE_INCLUDE_PATH ${PYTHON_HOME_PATH}/../include ${CMAKE_INCLUDE_PATH}) - SET(CMAKE_LIBRARY_PATH ${PYTHON_HOME_PATH}/../lib ${CMAKE_LIBRARY_PATH}) + SET(CMAKE_LIBRARY_PATH ${PYTHON_HOME_PATH}/../lib ${CMAKE_LIBRARY_PATH}) ENDIF(WIN32) FIND_PACKAGE(PythonLibs REQUIRED) @@ -523,7 +523,7 @@ else: MESSAGE(STATUS "Using SIP ${SIP_VERSION_THIRDPARTY} located in thirdparty for generating the Python bindings.") SET(SIP_LIB sip) SET(SYSTEM_SIP FALSE) - + TRY_COMPILE(SIP_OK ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/sip-${SIP_VERSION_THIRDPARTY}/sipgen ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/sip-${SIP_VERSION_THIRDPARTY}/sipgen sip CMAKE_FLAGS -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2=${PYTHON_INCLUDE_DIR2} @@ -541,7 +541,7 @@ else: ENDIF(SIP_OK) ENDIF(SIP_OK AND NOT ${SIP_VERSION_STR} VERSION_LESS ${SIP_VERSION_THIRDPARTY}) - IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) IF(NOT LINUX) EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import wheel" RESULT_VARIABLE WHEEL_OK OUTPUT_QUIET ERROR_QUIET) EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import twine" RESULT_VARIABLE TWINE_OK OUTPUT_QUIET ERROR_QUIET) @@ -554,15 +554,10 @@ else: MESSAGE("You can install it through the 'pip' tool ($ pip install twine)") ENDIF(NOT TWINE_OK EQUAL 0) - ADD_CUSTOM_TARGET(tulip-core-wheel + ADD_CUSTOM_TARGET(wheel COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_wheel WORKING_DIRECTORY ${TULIP_PYTHON_ROOT_FOLDER}) - ADD_CUSTOM_TARGET(tulip-gui-wheel - COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_wheel - WORKING_DIRECTORY ${TULIPGUI_PYTHON_ROOT_FOLDER} - DEPENDS tulip-core-wheel) - ELSE(NOT LINUX) IF(NOT EXISTS ${PYTHON_HOME_PATH}/wheel) @@ -576,25 +571,12 @@ else: # in order for the tulip modules to be successfully imported and loaded on every computer. # The 'auditwheel' tool (see https://github.com/pypa/auditwheel) has been developed # in order to ease that patching task. - # We use our patched version of the auditwheel tool - # as the official one does not repair tulip-gui wheel correctly - IF(NOT IS_DIRECTORY /tmp/auditwheel) - EXECUTE_PROCESS(COMMAND bash -c "echo $(dirname $(readlink /usr/local/bin/auditwheel))" OUTPUT_VARIABLE PYBIN OUTPUT_STRIP_TRAILING_WHITESPACE) - EXECUTE_PROCESS(COMMAND bash -c "${PYBIN}/pip uninstall -y auditwheel; cd /tmp; curl -LO http://tulip.labri.fr/code/auditwheel.tar.gz; tar zxvf auditwheel.tar.gz; ${PYBIN}/pip install /tmp/auditwheel") - ENDIF(NOT IS_DIRECTORY /tmp/auditwheel) - - ADD_CUSTOM_TARGET(tulip-core-wheel - COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_wheel - COMMAND bash -c "auditwheel repair -L native -w ./dist ./dist/$(ls -t ./dist/ | head -1)" + ADD_CUSTOM_TARGET(wheel + COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_wheel + COMMAND bash -c "auditwheel repair -L native -w ./dist ./dist/$(ls -t ./dist/ | head -1)" WORKING_DIRECTORY ${TULIP_PYTHON_ROOT_FOLDER} VERBATIM) - ADD_CUSTOM_TARGET(tulip-gui-wheel - COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_wheel - COMMAND bash -c "auditwheel repair -L native -w ./dist ./dist/$(ls -t ./dist/ | head -1)" - WORKING_DIRECTORY ${TULIPGUI_PYTHON_ROOT_FOLDER} VERBATIM - DEPENDS tulip-core-wheel) - - ENDIF(NOT LINUX) + ENDIF(NOT LINUX) # In order to upload the generated wheels, an account must be created on PyPi # and the following configuration must be stored in the ~/.pypirc file @@ -604,7 +586,7 @@ else: # pypi # testpypi # - # [testpypi] + # [pypitest] # repository: https://test.pypi.org/legacy/ # username: # password: @@ -627,23 +609,14 @@ else: IF(LINUX) SET(WHEEL_FILES_REGEXP "*manylinux*") ENDIF(LINUX) - ADD_CUSTOM_TARGET(tulip-core-wheel-upload-test - COMMAND ${TWINE} upload -r testpypi dist/${WHEEL_FILES_REGEXP} + ADD_CUSTOM_TARGET(wheel-upload-test + COMMAND ${TWINE} upload -r pypitest dist/${WHEEL_FILES_REGEXP} WORKING_DIRECTORY ${TULIP_PYTHON_ROOT_FOLDER}) - ADD_CUSTOM_TARGET(tulip-gui-wheel-upload-test - COMMAND ${TWINE} upload -r testpypi dist/${WHEEL_FILES_REGEXP} - WORKING_DIRECTORY ${TULIPGUI_PYTHON_ROOT_FOLDER}) - ADD_CUSTOM_TARGET(tulip-core-wheel-upload + ADD_CUSTOM_TARGET(wheel-upload COMMAND ${TWINE} upload -r pypi dist/${WHEEL_FILES_REGEXP} WORKING_DIRECTORY ${TULIP_PYTHON_ROOT_FOLDER}) - ADD_CUSTOM_TARGET(tulip-gui-wheel-upload - COMMAND ${TWINE} upload -r pypi dist/${WHEEL_FILES_REGEXP} - WORKING_DIRECTORY ${TULIPGUI_PYTHON_ROOT_FOLDER}) - ADD_CUSTOM_TARGET(wheels DEPENDS tulip-core-wheel tulip-gui-wheel) - ADD_CUSTOM_TARGET(wheels-upload-test DEPENDS tulip-core-wheel-upload-test tulip-gui-wheel-upload-test) - ADD_CUSTOM_TARGET(wheels-upload DEPENDS tulip-core-wheel-upload tulip-gui-wheel-upload) - ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ENDIF(PYTHONLIBS_FOUND) ENDIF(PYTHONINTERP_FOUND) @@ -710,11 +683,11 @@ FUNCTION(ADD_LIBRARY name) _ADD_LIBRARY(${name} ${ARGN}) IF(APPLE) # relative locations of Tulip dylibs dependencies are not the sames when generating Python wheels - IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET_TARGET_PROPERTIES(${name} PROPERTIES INSTALL_RPATH "@loader_path/;@loader_path/../") - ELSE(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ELSE(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET_TARGET_PROPERTIES(${name} PROPERTIES INSTALL_RPATH "@loader_path/../lib;@loader_path/../Frameworks;${QT_FRAMEWORKS_DIR}") - ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ELSE(APPLE) # CMake >= 3.1.0 does not allow to set the INSTALL_RPATH property on INTERFACE_LIBRARY target type GET_TARGET_PROPERTY(TARGET_TYPE ${name} TYPE) @@ -737,10 +710,9 @@ FUNCTION(ADD_LIBRARY name) ENDIF(MSVC) ENDIF(NOT "${TARGET_TYPE}" STREQUAL "INTERFACE_LIBRARY") ENDIF(APPLE) - IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_DEPENDENCIES(tulip-core-wheel ${name}) - ADD_DEPENDENCIES(tulip-gui-wheel ${name}) - ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + ADD_DEPENDENCIES(wheel ${name}) + ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ENDFUNCTION() FUNCTION(ADD_EXECUTABLE name) @@ -807,14 +779,12 @@ ADD_SUBDIRECTORY(library) ADD_SUBDIRECTORY(plugins) IF(NOT TULIP_BUILD_CORE_ONLY) ADD_SUBDIRECTORY(doc) - ADD_SUBDIRECTORY(textures) - IF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + IF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + ADD_SUBDIRECTORY(textures) ADD_SUBDIRECTORY(externalplugins) ADD_SUBDIRECTORY(demos) ADD_SUBDIRECTORY(software) - ELSE(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_CUSTOM_TARGET(copyTulipColorScales ALL ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/software/bitmaps/colorscales ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/colorscales) - ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ENDIF(NOT TULIP_BUILD_CORE_ONLY) IF(TULIP_BUILD_TESTS) @@ -907,7 +877,7 @@ ENDIF(NOT TULIP_BUILD_FOR_APPIMAGE) # updated in plugins/view/GeographicView, # and finally used in software/tulip_perpective/CMakeLists.txt SET_PROPERTY(GLOBAL PROPERTY FIXUP_BUNDLE_LIBS "") - + GET_FILENAME_COMPONENT(NSIS_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS]" ABSOLUTE) STRING(COMPARE EQUAL "${NSIS_PATH}" "" NSIS_PATH_EMPTY) IF(NSIS_PATH_EMPTY) diff --git a/cmake/FindQtX.cmake b/cmake/FindQtX.cmake index ffcf71b81a..dddf4cabac 100644 --- a/cmake/FindQtX.cmake +++ b/cmake/FindQtX.cmake @@ -13,8 +13,7 @@ SET(QT_HAS_WEBENGINE FALSE) # If CMake does not automatically find Qt5 , the root directory # of the Qt5 installation must be provided in the CMAKE_PREFIX_PATH variable. -# Also, when building Tulip Python wheels, force the use of Qt4 (more lightweight, easier to deploy) -IF(TULIP_USE_QT5 AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_USE_QT5) # Unset related CMake variables in order to change the Qt5 version (by modifying the root Qt5 directory through the CMAKE_PREFIX_PATH variable) # without having to delete the current CMake cache @@ -62,7 +61,7 @@ IF(TULIP_USE_QT5 AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) FIND_PACKAGE(Qt5OpenGL) FIND_PACKAGE(Qt5Network) -ENDIF(TULIP_USE_QT5 AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(TULIP_USE_QT5) # Qt5 and all the required modules are present, do global setup IF(${Qt5Widgets_FOUND} AND ${Qt5OpenGL_FOUND} AND ${Qt5Network_FOUND}) @@ -197,10 +196,10 @@ IF(${Qt5Widgets_FOUND} AND ${Qt5OpenGL_FOUND} AND ${Qt5Network_FOUND}) # Use Qt4 otherwise ELSE(${Qt5Widgets_FOUND} AND ${Qt5OpenGL_FOUND} AND ${Qt5Network_FOUND}) - IF(TULIP_USE_QT5 AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + IF(TULIP_USE_QT5) MESSAGE("Qt 5 required components or the CMake modules to locate them have not been found.") MESSAGE("Falling back to Qt 4.") - ENDIF(TULIP_USE_QT5 AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(TULIP_USE_QT5) FIND_PACKAGE(Qt4 4.6.0 REQUIRED) SET(USE_QT4 true) diff --git a/cmake/TulipUseFile.cmake b/cmake/TulipUseFile.cmake index a52df1aaec..8b2255b983 100644 --- a/cmake/TulipUseFile.cmake +++ b/cmake/TulipUseFile.cmake @@ -446,33 +446,10 @@ MACRO(TULIP_INSTALL_PLUGIN plugin_target destination) # When building a Python wheel, copy Tulip plugins in wheel build folder # in order to package them with the Tulip Python bindings - IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET(TULIP_PLUGIN_WHEEL_INSTALL_DIR "${TULIP_PYTHON_NATIVE_FOLDER}/plugins") - SET(TULIPGUI_PLUGIN_WHEEL_INSTALL_DIR "${TULIPGUI_PYTHON_NATIVE_FOLDER}/plugins") - - # Default install folder : tulip-core plugins - SET(PLUGIN_WHEEL_INSTALL_DIR ${TULIP_PLUGIN_WHEEL_INSTALL_DIR}) - # Copy interactor and view plugins in tulipgui wheel folder - IF(CMAKE_CURRENT_SOURCE_DIR MATCHES "^.*view.*$" OR CMAKE_CURRENT_SOURCE_DIR MATCHES "^.*interactor.*$") - SET(PLUGIN_WHEEL_INSTALL_DIR ${TULIPGUI_PLUGIN_WHEEL_INSTALL_DIR}) - ENDIF(CMAKE_CURRENT_SOURCE_DIR MATCHES "^.*view.*$" OR CMAKE_CURRENT_SOURCE_DIR MATCHES "^.*interactor.*$") - # Copy glyph plugins in tulipgui wheel folder - IF(CMAKE_CURRENT_SOURCE_DIR MATCHES "^.*glyph.*$") - SET(PLUGIN_WHEEL_INSTALL_DIR ${TULIPGUI_PLUGIN_WHEEL_INSTALL_DIR}) - ENDIF(CMAKE_CURRENT_SOURCE_DIR MATCHES "^.*glyph.*$") - - # Those plugins depend on Qt, copy them in tulipgui wheel folder - IF("${plugin_target}" MATCHES "^.*ConvolutionClustering.*$" OR - "${plugin_target}" MATCHES "^.*ConvolutionClustering.*$" OR - "${plugin_target}" MATCHES "^.*FileSystem.*$" OR - "${plugin_target}" MATCHES "^.*GEXFImport.*$" OR - "${plugin_target}" MATCHES "^.*WebImport.*$" OR - "${plugin_target}" MATCHES "^.*SVGExport.*$") - SET(PLUGIN_WHEEL_INSTALL_DIR ${TULIPGUI_PLUGIN_WHEEL_INSTALL_DIR}) - ENDIF() - - TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${plugin_target} ${PLUGIN_WHEEL_INSTALL_DIR} wheels) - ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${plugin_target} ${TULIP_PLUGIN_WHEEL_INSTALL_DIR} wheel) + ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ENDMACRO(TULIP_INSTALL_PLUGIN) # for backward compatibility with Tulip < 5.1 for external projects diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 37d9f81529..6d5d034547 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -7,23 +7,23 @@ IF(TULIP_BUILD_DOC) UNSET(SPHINX_EXECUTABLE CACHE) FIND_PACKAGE(Sphinx) IF(SPHINX_FOUND) - IF(TULIP_BUILD_PYTHON_COMPONENTS) + IF(TULIP_BUILD_PYTHON_COMPONENTS AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ADD_SUBDIRECTORY(python) - ENDIF(TULIP_BUILD_PYTHON_COMPONENTS) - IF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(TULIP_BUILD_PYTHON_COMPONENTS AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + IF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ADD_SUBDIRECTORY(user) ADD_SUBDIRECTORY(developer) - ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ELSE(SPHINX_FOUND) MESSAGE(AUTHOR_WARNING "Sphinx not found: unable to generate the documentation.") ENDIF(SPHINX_FOUND) - IF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND NOT TULIP_BUILD_FOR_APPIMAGE) + IF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND NOT TULIP_BUILD_FOR_APPIMAGE) FIND_PACKAGE(Doxygen) IF(DOXYGEN_FOUND) ADD_SUBDIRECTORY(doxygen) ELSE(DOXYGEN_FOUND) MESSAGE(AUTHOR_WARNING "doxygen not found: unable to generate the Tulip API documentation.") ENDIF(DOXYGEN_FOUND) - ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND NOT TULIP_BUILD_FOR_APPIMAGE) + ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND NOT TULIP_BUILD_FOR_APPIMAGE) ENDIF(TULIP_BUILD_DOC) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index f481216710..ae8d354ecc 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -2,10 +2,10 @@ ADD_CORE_FILES(CMakeLists.txt) ADD_SUBDIRECTORY(tulip-core) ADD_SUBDIRECTORY(tulip-ogdf) -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ADD_SUBDIRECTORY(tulip-ogl) ADD_SUBDIRECTORY(tulip-gui) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) IF(TULIP_BUILD_PYTHON_COMPONENTS) ADD_SUBDIRECTORY(tulip-python) ENDIF(TULIP_BUILD_PYTHON_COMPONENTS) diff --git a/library/tulip-core/src/CMakeLists.txt b/library/tulip-core/src/CMakeLists.txt index 36f8d31d10..7e71ed765e 100644 --- a/library/tulip-core/src/CMakeLists.txt +++ b/library/tulip-core/src/CMakeLists.txt @@ -105,9 +105,9 @@ INSTALL(TARGETS ${LibTulipCoreName} LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT tulip_core ARCHIVE DESTINATION ${TulipLibInstallDir} COMPONENT tulip_core) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipCoreName} ${TULIP_PYTHON_NATIVE_FOLDER} wheels) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipCoreName} ${TULIP_PYTHON_NATIVE_FOLDER} wheel) IF(LINUX) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipCoreName} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipCoreName} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheel) ENDIF(LINUX) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/library/tulip-gui/src/CMakeLists.txt b/library/tulip-gui/src/CMakeLists.txt index 5625ed9068..f3cd887ad1 100644 --- a/library/tulip-gui/src/CMakeLists.txt +++ b/library/tulip-gui/src/CMakeLists.txt @@ -252,7 +252,3 @@ INSTALL(TARGETS ${LibTulipGUIName} INSTALL(FILES ../resources/icons/tulip.ico DESTINATION ${TulipBitmapInstallDir}) INSTALL(FILES ../resources/icons/tulip-file-icon.ico DESTINATION ${TulipBitmapInstallDir}) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipGUIName} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/library/tulip-ogdf/CMakeLists.txt b/library/tulip-ogdf/CMakeLists.txt index 1cb1693874..eabb9cd37d 100644 --- a/library/tulip-ogdf/CMakeLists.txt +++ b/library/tulip-ogdf/CMakeLists.txt @@ -30,6 +30,6 @@ DESTINATION ${TulipIncludeInstallDir}/tulip2ogdf/ COMPONENT tulip_ogdf_dev) ENDIF(NOT TULIP_BUILD_FOR_APPIMAGE) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipOGDFName} ${TULIP_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipOGDFName} ${TULIP_PYTHON_NATIVE_FOLDER} wheel) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/library/tulip-ogl/bitmaps/CMakeLists.txt b/library/tulip-ogl/bitmaps/CMakeLists.txt index fb6c2bf38d..3f4cd8ebd1 100644 --- a/library/tulip-ogl/bitmaps/CMakeLists.txt +++ b/library/tulip-ogl/bitmaps/CMakeLists.txt @@ -22,24 +22,3 @@ INSTALL(DIRECTORY fonts COMPONENT tulip_ogl DESTINATION ${TulipBitmapInstallDir} PATTERN ".svn" EXCLUDE) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -ADD_CUSTOM_TARGET(copyTulipGuiBitmaps ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fontb.ttf ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fontb.ttf - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/font.ttf ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/font.ttf - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-brands-400.ttf ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-brands-400.ttf - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-brands-400.woff ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-brands-400.woff - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-brands-400.woff2 ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-brands-400.woff2 - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-regular-400.ttf ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-regular-400.ttf - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-regular-400.woff ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-regular-400.woff - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-regular-400.woff2 ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-regular-400.woff2 - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-solid-900.ttf ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-solid-900.ttf - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-solid-900.woff ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-solid-900.woff - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/fa-solid-900.woff2 ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/fa-solid-900.woff2 - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/materialdesignicons-webfont.ttf ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/materialdesignicons-webfont.ttf - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/materialdesignicons-webfont.woff ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/materialdesignicons-webfont.woff - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/materialdesignicons-webfont.woff2 ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/materialdesignicons-webfont.woff2 - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/halfCylinderTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/halfCylinderTexture.png - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/cylinderTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/cylinderTexture.png - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/roundTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/roundTexture.png) -ADD_DEPENDENCIES(tulip-gui-wheel copyTulipGuiBitmaps) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/library/tulip-ogl/src/CMakeLists.txt b/library/tulip-ogl/src/CMakeLists.txt index 35381e3cb4..c6c0b1a9cf 100644 --- a/library/tulip-ogl/src/CMakeLists.txt +++ b/library/tulip-ogl/src/CMakeLists.txt @@ -91,7 +91,3 @@ INSTALL(TARGETS ${LibTulipOGLName} RUNTIME DESTINATION ${TulipBinInstallDir} COMPONENT tulip_ogl LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT tulip_ogl ARCHIVE DESTINATION ${TulipLibInstallDir} COMPONENT tulip_ogl) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${LibTulipOGLName} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/library/tulip-python/CMakeLists.txt b/library/tulip-python/CMakeLists.txt index 7348198176..0a37d278ac 100644 --- a/library/tulip-python/CMakeLists.txt +++ b/library/tulip-python/CMakeLists.txt @@ -20,9 +20,9 @@ ADD_SUBDIRECTORY(modules) ADD_SUBDIRECTORY(bindings) ADD_SUBDIRECTORY(plugins) -# libtulip-python is not needed when building Python wheels -IF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND NOT TULIP_BUILD_CORE_ONLY) +# libtulip-python is not needed when building tulip-python wheel +IF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND NOT TULIP_BUILD_CORE_ONLY) ADD_SUBDIRECTORY(api) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(src) -ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS AND NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET AND NOT TULIP_BUILD_CORE_ONLY) diff --git a/library/tulip-python/bindings/CMakeLists.txt b/library/tulip-python/bindings/CMakeLists.txt index 4c3260434d..b76b7e7f30 100644 --- a/library/tulip-python/bindings/CMakeLists.txt +++ b/library/tulip-python/bindings/CMakeLists.txt @@ -3,6 +3,6 @@ ADD_CORE_FILES(CMakeLists.txt) ADD_SUBDIRECTORY(stl) ADD_SUBDIRECTORY(tulip-core) -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ADD_SUBDIRECTORY(tulip-gui) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/library/tulip-python/bindings/stl/CMakeLists.txt b/library/tulip-python/bindings/stl/CMakeLists.txt index ed725e739f..ed459fa138 100644 --- a/library/tulip-python/bindings/stl/CMakeLists.txt +++ b/library/tulip-python/bindings/stl/CMakeLists.txt @@ -61,13 +61,13 @@ ENDIF(WIN32) # and use dynamic lookup for retrieving its symbols. # That way, we can produce a C extension module that can be imported through the Python interpreter # provided by Apple with the System and the one provided by Python.org -IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET_TARGET_PROPERTIES(${LibStlPythonBindingsName} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TARGET_LINK_LIBRARIES(${LibStlPythonBindingsName} ${PYTHON_LIBRARY}) - ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TULIP_INSTALL_PYTHON_FILES(tulip/native ${LibStlPythonBindingsName}) diff --git a/library/tulip-python/bindings/tulip-core/CMakeLists.txt b/library/tulip-python/bindings/tulip-core/CMakeLists.txt index a8bca0ac32..d3f85703f2 100644 --- a/library/tulip-python/bindings/tulip-core/CMakeLists.txt +++ b/library/tulip-python/bindings/tulip-core/CMakeLists.txt @@ -113,11 +113,11 @@ ADD_DEPENDENCIES(${LibTulipCorePythonBindingsName} create-tulip-python-native-fo ADD_CUSTOM_TARGET(copyTulipInitPy ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${TULIP_PYTHON_FOLDER}/__init__.py) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_DEPENDENCIES(tulip-core-wheel copyTulipInitPy) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + ADD_DEPENDENCIES(wheel copyTulipInitPy) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) STRING(REGEX REPLACE "[^0-9.]" "" TulipVersionClean ${TulipVersion}) IF(WIN32) @@ -144,8 +144,8 @@ IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/packaging/README.rst ${TULIP_PYTHON_FOLDER}/../README.rst COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/packaging/copyTulipCoreDllDependencies.cmake ${TULIP_PYTHON_FOLDER}/../copyTulipCoreDllDependencies.cmake DEPENDS ${TULIP_PYTHON_FOLDER}/../setup.py ${TULIP_PYTHON_FOLDER}/../setup.cfg) - ADD_DEPENDENCIES(tulip-core-wheel copyTulipPythonPackagingFiles) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ADD_DEPENDENCIES(wheel copyTulipPythonPackagingFiles) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) IF(NOT SYSTEM_SIP) ADD_DEPENDENCIES(${LibTulipCorePythonBindingsName} ${SIP_LIB}) @@ -168,26 +168,26 @@ ENDIF(WIN32) FILE(RELATIVE_PATH TulipLibsInstallRelPath ${TulipPythonModulesInstallDir}/tulip/native ${CMAKE_INSTALL_PREFIX}/${TulipLibInstallDir}) -IF(APPLE AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(APPLE AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) GET_TARGET_PROPERTY(CURRENT_INSTALL_RPATHS ${LibTulipCorePythonBindingsName} INSTALL_RPATH) SET_TARGET_PROPERTIES(${LibTulipCorePythonBindingsName} PROPERTIES INSTALL_RPATH "${CURRENT_INSTALL_RPATHS};@loader_path/${TulipLibsInstallRelPath};@loader_path/../../../../Frameworks") -ELSEIF(LINUX AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ELSEIF(LINUX AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) GET_TARGET_PROPERTY(CURRENT_INSTALL_RPATHS ${LibTulipCorePythonBindingsName} INSTALL_RPATH) SET_TARGET_PROPERTIES(${LibTulipCorePythonBindingsName} PROPERTIES INSTALL_RPATH "${CURRENT_INSTALL_RPATHS}:$ORIGIN/${TulipLibsInstallRelPath}") -ENDIF(APPLE AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(APPLE AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TARGET_LINK_LIBRARIES(${LibTulipCorePythonBindingsName} ${LibTulipCoreName}) # When building Python wheel for MacOS, don't link the C extension module with the Python library # and use dynamic lookup for retrieving its symbols. # That way, we can produce a C extension module that can be imported through the Python interpreter # provided by Apple with the System and the one provided by Python.org -IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET_TARGET_PROPERTIES(${LibTulipCorePythonBindingsName} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TARGET_LINK_LIBRARIES(${LibTulipCorePythonBindingsName} ${PYTHON_LIBRARY}) - ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TULIP_INSTALL_PYTHON_FILES(tulip ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py) TULIP_INSTALL_PYTHON_FILES(tulip/native ${LibTulipCorePythonBindingsName}) diff --git a/library/tulip-python/bindings/tulip-core/packaging/README.rst b/library/tulip-python/bindings/tulip-core/packaging/README.rst index 278b173fcc..e507463506 100644 --- a/library/tulip-python/bindings/tulip-core/packaging/README.rst +++ b/library/tulip-python/bindings/tulip-core/packaging/README.rst @@ -86,8 +86,7 @@ Example The following script imports the dependency graph from the locally installed pip packages, draws it using a force directed layout algorithm and serializes the resulting graph to a file through the TLP graph format. The imported graph can then be visualized through the Tulip software -or the use of the dedicated `tulipgui `_ module, -enabling to create the OpenGL visualizations available in Tulip from Python. +for interactive analysis. .. code:: python diff --git a/library/tulip-python/bindings/tulip-gui/CMakeLists.txt b/library/tulip-python/bindings/tulip-gui/CMakeLists.txt index 929cc514f9..c5ce7c409a 100644 --- a/library/tulip-python/bindings/tulip-gui/CMakeLists.txt +++ b/library/tulip-python/bindings/tulip-gui/CMakeLists.txt @@ -23,38 +23,8 @@ QTX_WRAP_CPP(tulipguiutils_MOC TulipViewsUtils.h) QTX_ADD_RESOURCES(tulipgui_RCC_SRCS TulipGui.qrc) SET(TULIP_GUI_PYTHON_BINDINGS_SRC ${TULIP_GUI_PYTHON_BINDINGS_SRC} TulipViewsUtils.cpp ${tulipguiutils_MOC} ${tulipgui_RCC_SRCS}) - -DISABLE_COMPILER_WARNINGS() -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - STRING(REGEX REPLACE "[^0-9.]" "" TulipVersionClean ${TulipVersion}) - - IF(WIN32) - SET(WHEEL_INSTALL_PATH "\\") - ELSE(WIN32) - SET(WHEEL_INSTALL_PATH "/") - ENDIF(WIN32) - - ADD_CUSTOM_COMMAND(OUTPUT ${TULIPGUI_PYTHON_FOLDER}/../setup.py ${TULIPGUI_PYTHON_FOLDER}/../setup.cfg - COMMAND ${CMAKE_COMMAND} -DINPUT_DIR=${CMAKE_CURRENT_SOURCE_DIR}/packaging/ - -DOUTPUT_DIR=${TULIPGUI_PYTHON_FOLDER}/../ - -DTulipVersion=${TulipVersion} - -DTulipVersionClean=${TulipVersionClean} - -DPythonWheelVersionSuffix=${PythonWheelVersionSuffix} - -DWHEEL_INSTALL_PATH=${WHEEL_INSTALL_PATH} - -P ${CMAKE_CURRENT_SOURCE_DIR}/packaging/configure_tulipgui_python_setup.cmake - DEPENDS - packaging/setup.py.in - packaging/setup.cfg.in - COMMENT "Generating tulipgui-python packaging files" - VERBATIM) - - ADD_CUSTOM_TARGET(copyTulipGuiPythonPackagingFiles ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/packaging/MANIFEST.in ${TULIPGUI_PYTHON_FOLDER}/../MANIFEST.in - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/packaging/README.rst ${TULIPGUI_PYTHON_FOLDER}/../README.rst - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/packaging/copyTulipGuiDllDependencies.cmake ${TULIPGUI_PYTHON_FOLDER}/../copyTulipGuiDllDependencies.cmake - DEPENDS ${TULIPGUI_PYTHON_FOLDER}/../setup.py ${TULIPGUI_PYTHON_FOLDER}/../setup.cfg) - ADD_DEPENDENCIES(tulip-gui-wheel copyTulipGuiPythonPackagingFiles) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +DISABLE_COMPILER_WARNINGS() # Force to use SIP headers located in thirdparty # instead of those installed in the system @@ -79,9 +49,6 @@ ADD_CUSTOM_TARGET(create-tulipgui-python-native-folder ALL ADD_DEPENDENCIES(${LibTulipGUIPythonBindingsName} create-tulipgui-python-native-folder) ADD_CUSTOM_TARGET(copyTulipGuiInitPy ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${TULIPGUI_PYTHON_FOLDER}/__init__.py) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_DEPENDENCIES(tulip-gui-wheel copyTulipGuiInitPy) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) IF(NOT SYSTEM_SIP) ADD_DEPENDENCIES(${LibTulipGUIPythonBindingsName} ${SIP_LIB}) @@ -103,26 +70,15 @@ FILE(RELATIVE_PATH TulipLibsInstallRelPath ${TulipPythonModulesInstallDir}/tulip # On MacOS, add the paths of dependencies dylibs in install rpaths of the _tulipgui.so binary # That way, the tulipgui module can be imported in a classical Python shell without having to # modify the content of the DYLD_LIBRARY_PATH environment variable -IF(APPLE AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(APPLE) GET_TARGET_PROPERTY(CURRENT_INSTALL_RPATHS ${LibTulipGUIPythonBindingsName} INSTALL_RPATH) SET_TARGET_PROPERTIES(${LibTulipGUIPythonBindingsName} PROPERTIES INSTALL_RPATH "${CURRENT_INSTALL_RPATHS};@loader_path/${TulipLibsInstallRelPath}/;@loader_path/../../../../Frameworks") -ELSEIF(LINUX AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ELSEIF(LINUX) GET_TARGET_PROPERTY(CURRENT_INSTALL_RPATHS ${LibTulipGUIPythonBindingsName} INSTALL_RPATH) SET_TARGET_PROPERTIES(${LibTulipGUIPythonBindingsName} PROPERTIES INSTALL_RPATH "${CURRENT_INSTALL_RPATHS}:$ORIGIN/${TulipLibsInstallRelPath}") -ENDIF(APPLE AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - -TARGET_LINK_LIBRARIES(${LibTulipGUIPythonBindingsName} ${LibTulipCoreName} ${LibTulipOGLName} ${LibTulipGUIName} ${QT_LIBRARIES}) -# When building Python wheel for MacOS, don't link the C extension module with the Python library -# and use dynamic lookup for retrieving its symbols. -# That way, we can produce a C extension module that can be imported through the Python interpreter -# provided by Apple with the System and the one provided by Python.org -IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - SET_TARGET_PROPERTIES(${LibTulipGUIPythonBindingsName} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - TARGET_LINK_LIBRARIES(${LibTulipGUIPythonBindingsName} ${PYTHON_LIBRARY}) - ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(APPLE) + +TARGET_LINK_LIBRARIES(${LibTulipGUIPythonBindingsName} ${LibTulipCoreName} ${LibTulipOGLName} ${LibTulipGUIName} ${QT_LIBRARIES} ${PYTHON_LIBRARY}) TULIP_INSTALL_PYTHON_FILES(tulipgui ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py) TULIP_INSTALL_PYTHON_FILES(tulipgui/native ${LibTulipGUIPythonBindingsName}) diff --git a/library/tulip-python/bindings/tulip-gui/packaging/MANIFEST.in b/library/tulip-python/bindings/tulip-gui/packaging/MANIFEST.in deleted file mode 100644 index 2c6efd23bb..0000000000 --- a/library/tulip-python/bindings/tulip-gui/packaging/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include README.rst diff --git a/library/tulip-python/bindings/tulip-gui/packaging/README.rst b/library/tulip-python/bindings/tulip-gui/packaging/README.rst deleted file mode 100644 index c4b57f1291..0000000000 --- a/library/tulip-python/bindings/tulip-gui/packaging/README.rst +++ /dev/null @@ -1,123 +0,0 @@ -Module description -================== - -Graphs play an important role in many research areas, such as biology, microelectronics, social -sciences, data mining, and computer science. Tulip (http://tulip.labri.fr) [1]_ [2]_ is an -Information Visualization framework dedicated to the analysis and visualization of such relational -data. Written in C++ the framework enables the development of algorithms, visual encodings, -interaction techniques, data models, and domain-specific visualizations. - -The Tulip GUI library is available to the Python community through the Tulip-Python -bindings [3]_ allowing to create and manipulate Tulip views (typically Node Link diagrams) -trough the tulipgui module. It has to be used with the `tulip `_ module -dedicated to the creation, storage and manipulation of the graphs to visualize. -The bindings have been developed using the `SIP `_ -tool [4]_ from Riverbank Computed Limited, allowing to easily create quality Python bindings for any C/C++ library. - -The main features provided by the bindings are the following ones: - - * creation of interactive Tulip visualizations (Adjacency Matrix, Geographic, Histogram, - Node Link Diagram, Parallel Coordinates, Pixel Oriented, Scatter Plot, Self Organizing Map, Spreadsheet) - * the ability to change the data source on opened visualizations - * the possibilty to modify the rendering parameters for node link diagram visualizations - * the ability to save visualization snapshots to image files on disk - -Release notes -============== - -Some information regarding the Tulip-Python releases pushed on the Python Packaging Index: - - * **5.1.0**: based on Tulip 5.1.0 released on 07/11/2017 - - * **5.0.0**: based on Tulip 5.0.0 released on 27/06/2017 - - * **4.10.0**: based on Tulip 4.10.0 released on 08/12/2016 - - * **4.9.0** : based on Tulip 4.9.0 released on 08/07/2016 - - * **4.8.1** : based on Tulip 4.8.1 released on 16/02/2016 - - * **4.8.0** : Initial release based on Tulip 4.8 - -Example -======== - -The following script imports the tree structure of the file system directory of the Python -standard library, applies colors to nodes according to degrees, computes a tree layout and quadratic -Bézier shapes for edges. The imported graph and its visual encoding are then visualized -by creating an interactive Node Link Diagram view. -A window containing an OpenGL visualization of the graph will be created and displayed. - -.. code:: python - - from tulip import tlp - from tulipgui import tlpgui - - import os - - # get the root directory of the Python Standard Libraries - pythonStdLibPath = os.path.dirname(os.__file__) - - # call the 'File System Directory' import plugin from Tulip - # importing the tree structure of a file system - params = tlp.getDefaultPluginParameters('File System Directory') - params['directory color'] = tlp.Color.Blue - params['other color'] = tlp.Color.Red - params['directory'] = pythonStdLibPath - graph = tlp.importGraph('File System Directory', params) - - # compute an anonymous graph double property that will store node degrees - degree = tlp.DoubleProperty(graph) - degreeParams = tlp.getDefaultPluginParameters('Degree') - graph.applyDoubleAlgorithm('Degree', degree, degreeParams) - - # create a heat map color scale - heatMap = tlp.ColorScale([tlp.Color.Green, tlp.Color.Black, tlp.Color.Red]) - - # linearly map node degrees to colors using the 'Color Mapping' plugin from Tulip - # using the heat map color scale - colorMappingParams = tlp.getDefaultPluginParameters('Color Mapping', graph) - colorMappingParams['input property'] = degree - colorMappingParams['color scale'] = heatMap - graph.applyColorAlgorithm('Color Mapping', colorMappingParams) - - # apply the 'Bubble Tree' graph layout plugin from Tulip - graph.applyLayoutAlgorithm('Bubble Tree') - - # compute quadratic bezier shapes for edges - curveEdgeParams = tlp.getDefaultPluginParameters('Curve edges', graph) - curveEdgeParams['curve type'] = 'QuadraticDiscrete' - graph.applyAlgorithm('Curve edges', curveEdgeParams) - - # create a node link diagram view of the graph, - # a window containing the Tulip OpenGL visualization - # will be created and displayed - nodeLinkView = tlpgui.createNodeLinkDiagramView(graph) - # set some rendering parameters for the graph - renderingParameters = nodeLinkView.getRenderingParameters() - renderingParameters.setViewArrow(True) - renderingParameters.setMinSizeOfLabel(8) - renderingParameters.setEdgeColorInterpolate(True) - nodeLinkView.setRenderingParameters(renderingParameters) - -References -========== - -.. [1] David Auber, Romain Bourqui, Maylis Delest, Antoine Lambert, - Patrick Mary, Guy Mélançon, Bruno Pinaud, Benjamin Renoust and Jason Vallet. - TULIP 4. Research report. LaBRI - Laboratoire Bordelais de Recherche en Informatique. 2016. - https://hal.archives-ouvertes.fr/hal-01359308 - -.. [2] David Auber, Daniel Archambault, Romain Bourqui, Antoine Lambert, Morgan Mathiaut, - Patrick Mary, Maylis Delest, Jonathan Dubois, and Guy Mélançon. The Tulip 3 Framework: - A Scalable Software Library for Information Visualization Applications Based on Relational - Data. Technical report RR-7860, INRIA, January 2012 - https://hal.archives-ouvertes.fr/hal-00659880 - -.. [3] Antoine Lambert and David Auber. Graph analysis and visualization with Tulip-Python. - EuroSciPy 2012 - 5th European meeting on Python in Science, Bruxelles - https://hal.archives-ouvertes.fr/hal-00744969 - -.. [4] Riverbank Computing Limited. SIP - a tool for automatically generating Python bindings for - C and C++ libraries. http://www.riverbankcomputing.co.uk/software/sip - diff --git a/library/tulip-python/bindings/tulip-gui/packaging/configure_tulipgui_python_setup.cmake b/library/tulip-python/bindings/tulip-gui/packaging/configure_tulipgui_python_setup.cmake deleted file mode 100644 index 1039bf2156..0000000000 --- a/library/tulip-python/bindings/tulip-gui/packaging/configure_tulipgui_python_setup.cmake +++ /dev/null @@ -1,2 +0,0 @@ -CONFIGURE_FILE(${INPUT_DIR}/setup.py.in ${OUTPUT_DIR}/setup.py) -CONFIGURE_FILE(${INPUT_DIR}/setup.cfg.in ${OUTPUT_DIR}/setup.cfg) diff --git a/library/tulip-python/bindings/tulip-gui/packaging/copyTulipGuiDllDependencies.cmake b/library/tulip-python/bindings/tulip-gui/packaging/copyTulipGuiDllDependencies.cmake deleted file mode 100644 index 08970c803f..0000000000 --- a/library/tulip-python/bindings/tulip-gui/packaging/copyTulipGuiDllDependencies.cmake +++ /dev/null @@ -1,72 +0,0 @@ -INCLUDE(GetPrerequisites) - -SET(TULIP_NATIVE_PYTHON_PATH "${CWD}/../../tulip-core/tulip_module/tulip/native/") -SET(TULIPGUI_NATIVE_PYTHON_PATH "${CWD}/tulipgui/native/") - -SET(TULIPGUI_NATIVE_PYTHON_MODULE "${TULIPGUI_NATIVE_PYTHON_PATH}/_tulipgui.pyd") - -STRING(REPLACE ";" "\;" LIBRARY_PATHS "${LIBRARY_PATHS}") - -SET(DIRS "${TULIP_NATIVE_PYTHON_PATH}\;${TULIPGUI_NATIVE_PYTHON_PATH}\;${LIBRARY_PATHS}") - -MESSAGE("Gathering dll dependencies for tulipgui Python module ...") - -GET_PREREQUISITES(${TULIPGUI_NATIVE_PYTHON_MODULE} TULIPGUI_NATIVE_PYTHON_MODULE_TL_DEPS 1 0 "" ${DIRS}) - -GET_PREREQUISITES("${TULIPGUI_NATIVE_PYTHON_PATH}/plugins/libGeographicView-${TulipVersion}.dll" GEOVIEW_DEPS 1 0 "" ${DIRS}) - -SET(TULIPGUI_NATIVE_PYTHON_MODULE_TL_DEPS ${TULIPGUI_NATIVE_PYTHON_MODULE_TL_DEPS} ${GEOVIEW_DEPS}) - -# The DLL_DEP_RESOLVED variable is not set when calling GP_RESOLVE_ITEM -# even if the item is correctly resolved (I added some debug messages to GetPrerequisites.cmake to verify). -# My guess is PARENT_SCOPE is not honored when executing cmake in script mode ($ cmake -P ...). -# Hopefully, CMake provides a hook mechanism called at the end of the GP_RESOLVE_ITEM process -# that enables us to get the resolved item - -# Store the resolved top level items for the tulipgui module in an environment variable (as PARENT_SCOPE does not seem -# to work when executing CMake in script mode ($ cmake -P ...) -FUNCTION(gp_resolve_item_override context item exepath dirs resolved_item_var resolved) - IF(DEFINED ENV{TULIPGUI_NATIVE_PYTHON_MODULE_DEPS}) - SET(ENV{TULIPGUI_NATIVE_PYTHON_MODULE_DEPS} "$ENV{TULIPGUI_NATIVE_PYTHON_MODULE_DEPS};${${resolved_item_var}}") - ELSE() - SET(ENV{TULIPGUI_NATIVE_PYTHON_MODULE_DEPS} "${${resolved_item_var}}") - ENDIF() -ENDFUNCTION() - -# Append the top level prerequisites items to the TULIPGUI_NATIVE_PYTHON_MODULE_DEPS list -# and resolve them (get their absolute path) -FOREACH(DLL_DEP ${TULIPGUI_NATIVE_PYTHON_MODULE_TL_DEPS}) - IF(NOT "${DLL_DEP}" MATCHES "^python[0-9][0-9].dll$") - LIST(APPEND TULIPGUI_NATIVE_PYTHON_MODULE_DEPS ${DLL_DEP}) - GP_RESOLVE_ITEM(${TULIPGUI_NATIVE_PYTHON_MODULE} ${DLL_DEP} "" ${DIRS} DLL_DEP_RESOLVED) - ENDIF() -ENDFOREACH() - -FUNCTION(gp_resolve_item_override context item exepath dirs resolved_item_var resolved) -ENDFUNCTION() - -# Get recusively prerequisites of top level prerequisites for the tulipgui module and append them to the TULIPGUI_NATIVE_PYTHON_MODULE_DEPS list -FOREACH(DLL_DEP $ENV{TULIPGUI_NATIVE_PYTHON_MODULE_DEPS}) - GET_PREREQUISITES(${DLL_DEP} DLL_DEP_DEPS 1 1 "" ${DIRS}) - FOREACH(DLL_DEP_DEP ${DLL_DEP_DEPS}) - LIST(APPEND TULIPGUI_NATIVE_PYTHON_MODULE_DEPS ${DLL_DEP_DEP}) - ENDFOREACH() -ENDFOREACH() - -# Remove duplicate entries in the TULIPGUI_NATIVE_PYTHON_MODULE_DEPS list -LIST(REMOVE_DUPLICATES TULIPGUI_NATIVE_PYTHON_MODULE_DEPS) - -FUNCTION(gp_resolve_item_override context item exepath dirs resolved_item_var resolved) - IF("${context}" MATCHES ".*tulipgui.*") - IF(NOT EXISTS "${TULIP_NATIVE_PYTHON_PATH}/${item}" AND - NOT EXISTS "${TULIPGUI_NATIVE_PYTHON_PATH}/${item}") - MESSAGE("Copying ${item} inside tulipgui Python module native folder") - FILE(COPY ${${resolved_item_var}} DESTINATION ${TULIPGUI_NATIVE_PYTHON_PATH}) - ENDIF() - ENDIF() -ENDFUNCTION() - -# Finally, resolve all prerequisites for the tulipgui Python module and copy them to the module native folder -FOREACH(DLL_DEP ${TULIPGUI_NATIVE_PYTHON_MODULE_DEPS}) - GP_RESOLVE_ITEM(${TULIPGUI_NATIVE_PYTHON_MODULE} ${DLL_DEP} "" ${DIRS} DLL_DEP_RESOLVED) -ENDFOREACH() diff --git a/library/tulip-python/bindings/tulip-gui/packaging/setup.cfg.in b/library/tulip-python/bindings/tulip-gui/packaging/setup.cfg.in deleted file mode 100644 index b005b10347..0000000000 --- a/library/tulip-python/bindings/tulip-gui/packaging/setup.cfg.in +++ /dev/null @@ -1,10 +0,0 @@ -[bdist_wheel] -# This flag says that the code is written to work on both Python 2 and Python -# 3. If at all possible, it is good practice to do this. If you cannot, you -# will need to generate wheels for each Python version that you support. -universal=0 - -# Force tulip wheels to be installed in install_platlib and not install_purelib -# as extension modules are not compiled through setuptools -[install] -install_lib=${WHEEL_INSTALL_PATH} diff --git a/library/tulip-python/modules/CMakeLists.txt b/library/tulip-python/modules/CMakeLists.txt index 9abb9a40a7..dd36e13780 100644 --- a/library/tulip-python/modules/CMakeLists.txt +++ b/library/tulip-python/modules/CMakeLists.txt @@ -7,7 +7,7 @@ TULIP_INSTALL_PYTHON_FILES("" ${CMAKE_CURRENT_SOURCE_DIR}/tulipplugins.py) # so we will copy it in the current binary dir ADD_CUSTOM_TARGET(copyTulipPluginsPyInBuild ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/tulipplugins.py ${CMAKE_CURRENT_BINARY_DIR}/tulipplugins.py) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -ADD_CUSTOM_TARGET(copyTulipPluginsPy ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/tulipplugins.py ${TULIP_PYTHON_FOLDER}/../tulipplugins/__init__.py) -ADD_DEPENDENCIES(tulip-core-wheel copyTulipPluginsPy) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + ADD_CUSTOM_TARGET(copyTulipPluginsPy ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/tulipplugins.py ${TULIP_PYTHON_FOLDER}/../tulipplugins/__init__.py) + ADD_DEPENDENCIES(wheel copyTulipPluginsPy) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/library/tulip-python/plugins/CMakeLists.txt b/library/tulip-python/plugins/CMakeLists.txt index 1c3fbeb0fd..83a7f8c0f4 100644 --- a/library/tulip-python/plugins/CMakeLists.txt +++ b/library/tulip-python/plugins/CMakeLists.txt @@ -14,6 +14,6 @@ ADD_CUSTOM_TARGET(copyTulipPythonPlugins ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${TULIPGUI_PYTHON_FOLDER}/plugins/general COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/general/H3LayoutHelper.py ${TULIPGUI_PYTHON_FOLDER}/plugins/general) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_DEPENDENCIES(tulip-core-wheel copyTulipPythonPlugins) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + ADD_DEPENDENCIES(wheel copyTulipPythonPlugins) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 6aefa24c43..42bc982d39 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,13 +10,10 @@ ADD_SUBDIRECTORY(selection) ADD_SUBDIRECTORY(sizes) ADD_SUBDIRECTORY(test) ADD_SUBDIRECTORY(colors) -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ADD_SUBDIRECTORY(glyph) ADD_SUBDIRECTORY(interactor) -# Tulip perspective is not bundled in tulipgui Python wheel -IF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) ADD_SUBDIRECTORY(perspective) -ENDIF(NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) ADD_SUBDIRECTORY(string) ADD_SUBDIRECTORY(view) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/plugins/clustering/CMakeLists.txt b/plugins/clustering/CMakeLists.txt index 4a5414bfc5..ee73cab8d3 100644 --- a/plugins/clustering/CMakeLists.txt +++ b/plugins/clustering/CMakeLists.txt @@ -29,7 +29,7 @@ ADD_LIBRARY(CliqueEnumeration-${TulipVersion} SHARED ${CliqueEnumeration_SRCS}) TARGET_LINK_LIBRARIES(CliqueEnumeration-${TulipVersion} ${LibTulipCoreName}) ##---------------------------------------------------------------------------------------------------------------------------- -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) QTX_SET_INCLUDES_AND_DEFINITIONS() QTX_WRAP_UI(ConvolutionClustering_UI_SRCS @@ -46,7 +46,7 @@ SET(ConvolutionClustering_SRCS ADD_LIBRARY(ConvolutionClustering-${TulipVersion} SHARED ${ConvolutionClustering_SRCS} ${ConvolutionClustering_UI_SRCS} ${ConvolutionClustering_MOC_SRCS}) TARGET_LINK_LIBRARIES(ConvolutionClustering-${TulipVersion} ${LibTulipCoreName} ${QT_LIBRARIES}) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ##---------------------------------------------------------------------------------------------------------------------------- SET(EqualValueClustering_SRCS EqualValueClustering.h @@ -66,9 +66,9 @@ TARGET_LINK_LIBRARIES(QuotientClustering-${TulipVersion} ${LibTulipCoreName}) ##---------------------------------------------------------------------------------------------------------------------------- TULIP_INSTALL_PLUGIN(StrengthClustering-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(HierarchicalClustering-${TulipVersion} ${TulipPluginsInstallDir}) -IF(NOT TULIP_BUILD_CORE_ONLY) -TULIP_INSTALL_PLUGIN(ConvolutionClustering-${TulipVersion} ${TulipPluginsInstallDir}) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + TULIP_INSTALL_PLUGIN(ConvolutionClustering-${TulipVersion} ${TulipPluginsInstallDir}) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TULIP_INSTALL_PLUGIN(EqualValueClustering-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(QuotientClustering-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(CliqueEnumeration-${TulipVersion} ${TulipPluginsInstallDir}) diff --git a/plugins/colors/CMakeLists.txt b/plugins/colors/CMakeLists.txt index 7c06f6a62a..ac7d815974 100644 --- a/plugins/colors/CMakeLists.txt +++ b/plugins/colors/CMakeLists.txt @@ -4,7 +4,7 @@ INCLUDE_DIRECTORIES(${TulipCoreBuildInclude} ${TulipCoreInclude} ${TulipOGLInclu ##---------------------------------------------------------------------------------------------------------------------------- -IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) QTX_SET_INCLUDES_AND_DEFINITIONS() @@ -24,7 +24,7 @@ QTX_WRAP_CPP(ColorMapping_MOC_SRCS ADD_LIBRARY(ColorMapping-${TulipVersion} SHARED ${ColorMapping_SRCS} ${ColorMapping_UI_SRCS} ${ColorMapping_MOC_SRCS}) TARGET_LINK_LIBRARIES(ColorMapping-${TulipVersion} ${LibTulipCoreName} ${LibTulipGUIName}) -ELSE(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ELSE(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET(ColorMapping_SRCS ColorMapping.cpp @@ -36,7 +36,7 @@ SET_SOURCE_FILES_PROPERTIES(ColorMapping.cpp ADD_LIBRARY(ColorMapping-${TulipVersion} SHARED ${ColorMapping_SRCS}) TARGET_LINK_LIBRARIES(ColorMapping-${TulipVersion} ${LibTulipCoreName}) -ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ##---------------------------------------------------------------------------------------------------------------------------- TULIP_INSTALL_PLUGIN(ColorMapping-${TulipVersion} ${TulipPluginsInstallDir}) diff --git a/plugins/export/CMakeLists.txt b/plugins/export/CMakeLists.txt index 3592e19fc2..add8f9fa94 100644 --- a/plugins/export/CMakeLists.txt +++ b/plugins/export/CMakeLists.txt @@ -1,6 +1,6 @@ -IF(NOT TULIP_BUILD_CORE_ONLY) -ADD_SUBDIRECTORY(SVGExport) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + ADD_SUBDIRECTORY(SVGExport) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) INCLUDE_DIRECTORIES(${TulipCoreBuildInclude} ${TulipCoreInclude}) diff --git a/plugins/glyph/CMakeLists.txt b/plugins/glyph/CMakeLists.txt index 64728b202d..d0b47856ad 100644 --- a/plugins/glyph/CMakeLists.txt +++ b/plugins/glyph/CMakeLists.txt @@ -40,12 +40,3 @@ FONTGLYPH(FontIcon fonticon.cpp) INSTALL(FILES radialGradientTexture.png bottomShadowTexture.png leftBottomShadowTexture.png rightBottomShadowTexture.png DESTINATION ${TulipBitmapInstallDir} COMPONENT tulip_plugins) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_CUSTOM_TARGET(copyGlyphTextures ALL - ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/radialGradientTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/radialGradientTexture.png - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/bottomShadowTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/bottomShadowTexture.png - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/leftBottomShadowTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/leftBottomShadowTexture.png - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/rightBottomShadowTexture.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/rightBottomShadowTexture.png ) - ADD_DEPENDENCIES(tulip-gui-wheel copyGlyphTextures) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/plugins/import/CMakeLists.txt b/plugins/import/CMakeLists.txt index 740ec9bd15..39464debef 100644 --- a/plugins/import/CMakeLists.txt +++ b/plugins/import/CMakeLists.txt @@ -85,7 +85,7 @@ ADD_LIBRARY(EmptyGraph-${TulipVersion} SHARED EmptyGraph.cpp) TARGET_LINK_LIBRARIES(EmptyGraph-${TulipVersion} ${LibTulipCoreName}) ##---------------------------------------------------------------------------------------------------------------------------- -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) QTX_SET_INCLUDES_AND_DEFINITIONS() SET(FileSystem_SRCS FileSystem.cpp) ADD_LIBRARY(FileSystem-${TulipVersion} SHARED ${FileSystem_SRCS}) @@ -101,7 +101,7 @@ ADD_LIBRARY(GEXFImport-${TulipVersion} SHARED GEXFImport.cpp) TARGET_LINK_LIBRARIES(GEXFImport-${TulipVersion} ${LibTulipCoreName} ${QT_LIBRARIES}) ##---------------------------------------------------------------------------------------------------------------------------- -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ##---------------------------------------------------------------------------------------------------------------------------- TULIP_INSTALL_PLUGIN(PlanarGraph-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(DotImport-${TulipVersion} ${TulipPluginsInstallDir}) @@ -115,11 +115,11 @@ TULIP_INSTALL_PLUGIN(RandomTree-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(RandomTreeGeneral-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(CompleteTree-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(SmallWorldGraph-${TulipVersion} ${TulipPluginsInstallDir}) -IF(NOT TULIP_BUILD_CORE_ONLY) -TULIP_INSTALL_PLUGIN(FileSystem-${TulipVersion} ${TulipPluginsInstallDir}) -TULIP_INSTALL_PLUGIN(WebImport-${TulipVersion} ${TulipPluginsInstallDir}) -TULIP_INSTALL_PLUGIN(GEXFImport-${TulipVersion} ${TulipPluginsInstallDir}) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + TULIP_INSTALL_PLUGIN(FileSystem-${TulipVersion} ${TulipPluginsInstallDir}) + TULIP_INSTALL_PLUGIN(WebImport-${TulipVersion} ${TulipPluginsInstallDir}) + TULIP_INSTALL_PLUGIN(GEXFImport-${TulipVersion} ${TulipPluginsInstallDir}) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TULIP_INSTALL_PLUGIN(ImportPajek-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(ImportUCINET-${TulipVersion} ${TulipPluginsInstallDir}) TULIP_INSTALL_PLUGIN(EmptyGraph-${TulipVersion} ${TulipPluginsInstallDir}) diff --git a/textures/CMakeLists.txt b/textures/CMakeLists.txt index da586acb65..8e646d5b23 100644 --- a/textures/CMakeLists.txt +++ b/textures/CMakeLists.txt @@ -7,9 +7,3 @@ INSTALL(FILES arrowSprite.png logolabri.jpg DESTINATION ${TulipBitmapInstallDir} COMPONENT tulip_textures) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - ADD_CUSTOM_TARGET(copyTextures ALL ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/titlebarGradient.png ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/titlebarGradient.png - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/logolabri.jpg ${TULIPGUI_PYTHON_FOLDER}/share/bitmaps/logolabri.jpg) - ADD_DEPENDENCIES(tulip-gui-wheel copyTextures) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 2b762aee9e..7908791799 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -22,14 +22,14 @@ ENDIF(NOT YAJL_FOUND) ADD_SUBDIRECTORY(antlr) ADD_SUBDIRECTORY(xdkbibtex) -IF(NOT TULIP_BUILD_CORE_ONLY) +IF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ADD_SUBDIRECTORY(ftgl) ADD_SUBDIRECTORY(libtess2) IF(NOT QUAZIP_FOUND) MESSAGE(STATUS "Quazip library was not found on the system, the version located in thirdparty will be compiled and used instead.") ADD_SUBDIRECTORY(quazip) ENDIF(NOT QUAZIP_FOUND) -ENDIF(NOT TULIP_BUILD_CORE_ONLY) +ENDIF(NOT TULIP_BUILD_CORE_ONLY AND NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) IF(PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) IF(SIP_OK AND NOT SIP_FOUND) ADD_SUBDIRECTORY(sip-${SIP_VERSION_THIRDPARTY}) diff --git a/thirdparty/OGDF/CMakeLists.txt b/thirdparty/OGDF/CMakeLists.txt index 92db9d6b69..0e698aadb5 100644 --- a/thirdparty/OGDF/CMakeLists.txt +++ b/thirdparty/OGDF/CMakeLists.txt @@ -25,6 +25,6 @@ INSTALL(TARGETS ${OGDFLibrary} LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT ogdf ARCHIVE DESTINATION ${TulipLibInstallDir} COMPONENT ogdf) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${OGDFLibrary} ${TULIP_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${OGDFLibrary} ${TULIP_PYTHON_NATIVE_FOLDER} wheel) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/thirdparty/ftgl/CMakeLists.txt b/thirdparty/ftgl/CMakeLists.txt index 07aac967af..dd4aae163f 100644 --- a/thirdparty/ftgl/CMakeLists.txt +++ b/thirdparty/ftgl/CMakeLists.txt @@ -114,7 +114,3 @@ INSTALL(TARGETS ${FTGLLibrary} RUNTIME DESTINATION ${TulipBinInstallDir} COMPONENT ftgl LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT ftgl ARCHIVE DESTINATION ${TulipLibInstallDir} COMPONENT ftgl) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${FTGLLibrary} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/thirdparty/gzstream/CMakeLists.txt b/thirdparty/gzstream/CMakeLists.txt index 5fc5097d3a..147fa18e50 100644 --- a/thirdparty/gzstream/CMakeLists.txt +++ b/thirdparty/gzstream/CMakeLists.txt @@ -21,9 +21,9 @@ INSTALL(TARGETS ${GZStreamLibrary} LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT gzstream ARCHIVE DESTINATION ${TulipLibInstallDir} COMPONENT gzstream) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${GZStreamLibrary} ${TULIP_PYTHON_NATIVE_FOLDER} wheels) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${GZStreamLibrary} ${TULIP_PYTHON_NATIVE_FOLDER} wheel) IF(LINUX) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${GZStreamLibrary} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${GZStreamLibrary} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheel) ENDIF(LINUX) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) diff --git a/thirdparty/libtess2/CMakeLists.txt b/thirdparty/libtess2/CMakeLists.txt index acb4f89791..3879d563e4 100755 --- a/thirdparty/libtess2/CMakeLists.txt +++ b/thirdparty/libtess2/CMakeLists.txt @@ -19,7 +19,3 @@ INSTALL(TARGETS ${Tess2Library} RUNTIME DESTINATION ${TulipBinInstallDir} LIBRARY DESTINATION ${TulipLibInstallDir} ARCHIVE DESTINATION ${TulipLibInstallDir}) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${Tess2Library} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/thirdparty/quazip/CMakeLists.txt b/thirdparty/quazip/CMakeLists.txt index ca5974ada1..72982bdf66 100644 --- a/thirdparty/quazip/CMakeLists.txt +++ b/thirdparty/quazip/CMakeLists.txt @@ -19,7 +19,3 @@ INSTALL(TARGETS ${QuazipLibrary} RUNTIME DESTINATION ${TulipBinInstallDir} COMPONENT quazip LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT quazip ARCHIVE DESTINATION ${TulipLibInstallDir} COMPONENT quazip) - -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${QuazipLibrary} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) diff --git a/thirdparty/sip-4.19.12/siplib/CMakeLists.txt b/thirdparty/sip-4.19.12/siplib/CMakeLists.txt index f80d33006e..9a90839d86 100644 --- a/thirdparty/sip-4.19.12/siplib/CMakeLists.txt +++ b/thirdparty/sip-4.19.12/siplib/CMakeLists.txt @@ -46,13 +46,13 @@ ENDIF(WIN32) # and use dynamic lookup for retrieving its symbols. # That way, we can produce a C extension module that can be imported through the Python interpreter # provided by Apple with the System and the one provided by Python.org -IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET_TARGET_PROPERTIES(${SIP_LIB} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ELSE(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + IF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) TARGET_LINK_LIBRARIES(${SIP_LIB} ${PYTHON_LIBRARY}) - ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) + ENDIF(NOT LINUX OR NOT TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +ENDIF(APPLE AND TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) SET_TARGET_PROPERTIES(${SIP_LIB} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${TULIP_PYTHON_NATIVE_FOLDER}) SET_TARGET_PROPERTIES(${SIP_LIB} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TULIP_PYTHON_NATIVE_FOLDER}) @@ -69,8 +69,8 @@ ADD_DEPENDENCIES(${SIP_LIB} create-sip-output-folder) TULIP_INSTALL_PYTHON_FILES(tulip/native ${SIP_LIB} ${TULIP_PYTHON_NATIVE_FOLDER}/__init__.py) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) - TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${SIP_LIB} ${TULIP_PYTHON_NATIVE_FOLDER} wheels) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) + TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${SIP_LIB} ${TULIP_PYTHON_NATIVE_FOLDER} wheel) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) ENDIF (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) diff --git a/thirdparty/yajl/src/CMakeLists.txt b/thirdparty/yajl/src/CMakeLists.txt index e4638e518c..64a13c4197 100644 --- a/thirdparty/yajl/src/CMakeLists.txt +++ b/thirdparty/yajl/src/CMakeLists.txt @@ -89,9 +89,9 @@ INSTALL(TARGETS ${YajlLibrary} LIBRARY DESTINATION ${TulipLibInstallDir} COMPONENT yajl) -IF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${YajlLibrary} ${TULIP_PYTHON_NATIVE_FOLDER} wheels) +IF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${YajlLibrary} ${TULIP_PYTHON_NATIVE_FOLDER} wheel) IF(LINUX) -TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${YajlLibrary} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheels) +TULIP_COPY_TARGET_LIBRARY_POST_BUILD(${YajlLibrary} ${TULIPGUI_PYTHON_NATIVE_FOLDER} wheel) ENDIF(LINUX) -ENDIF(TULIP_ACTIVATE_PYTHON_WHEELS_TARGETS) +ENDIF(TULIP_ACTIVATE_PYTHON_WHEEL_TARGET) From 296ff721f87260e1555dee7abdeda96dc936d4d7 Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Wed, 26 Sep 2018 23:40:30 +0200 Subject: [PATCH 4/6] travis.yml: Add job to build tulip-python wheel on manylinux1 --- .travis.yml | 25 +++++++++++++++ bundlers/linux/tulip_python_wheels_build.sh | 34 +++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 bundlers/linux/tulip_python_wheels_build.sh diff --git a/.travis.yml b/.travis.yml index c9c3cdb5bd..95f8882c3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -240,7 +240,32 @@ jobs: - sudo ninja -j4 install || travis_terminate 1 # run Tulip unit tests - ninja runTests + #============================================================================================================================================================== + # Tulip-Python wheels build on manylinux1 + - stage: Tulip-Python wheels build (CentOS 5.11 manylinux1) + os: linux + dist: trusty + cache: + directories: + - $HOME/ccache + sudo: required + env: + - ARCH=x86_64 + - DOCKER_IMAGE=quay.io/pypa/manylinux1_x86_64 + + services: + - docker + + before_install: + - echo 'DOCKER_OPTS="-H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock -s devicemapper"' | sudo tee /etc/default/docker > /dev/null + - sudo service docker restart + - sleep 5 + - sudo docker pull ${DOCKER_IMAGE} + - sudo docker create -v $HOME/ccache:/ccache --name ccache ${DOCKER_IMAGE} + + script: + - sudo docker run --rm=true -e CCACHE_DIR=/ccache --volumes-from ccache --cap-add SYS_ADMIN -v `pwd`:/tulip:rw ${DOCKER_IMAGE} /bin/bash -c "bash -xe /tulip/bundlers/linux/tulip_python_wheels_build.sh" #============================================================================================================================================================== # Tulip AppImage build on CentOS - stage: Tulip AppImage build (CentOS) diff --git a/bundlers/linux/tulip_python_wheels_build.sh b/bundlers/linux/tulip_python_wheels_build.sh new file mode 100644 index 0000000000..f7f7276f66 --- /dev/null +++ b/bundlers/linux/tulip_python_wheels_build.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# This script is only intended to be run in the pypa/manylinux1 +# docker image based on Centos 5.11 + +cd + +# install tulip-python wheel deps +yum -y install zlib-devel qhull-devel ccache + +# we need at least CMake 2.8.12 in order to build tulip-python wheel +# so let's grab it, compile it and install it +curl -LO https://cmake.org/files/v2.8/cmake-2.8.12.tar.gz +tar -xvzf cmake-2.8.12.tar.gz +cd cmake-2.8.12 +./bootstrap --enable-ccache +make -j4 +make -j4 install + +cd + +mkdir tulip_build && cd tulip_build +# iterate on available Python versions +for PYTHON_BIN_PATH in /opt/python/cp*/bin +do + # configure and build tulip-python with specific Python version + cmake -DTULIP_USE_CCACHE=ON -DTULIP_ACTIVATE_PYTHON_WHEEL_TARGET=ON -DPYTHON_EXECUTABLE=$PYTHON_BIN_PATH/python -DCMAKE_BUILD_TYPE=Release /tulip + make -j4 wheel + # install and check that the produced module can be successfully imported + cd ./library/tulip-python/bindings/tulip-core/tulip_module/dist + $PYTHON_BIN_PATH/pip install $(ls -t | head -1) + $PYTHON_BIN_PATH/python -c "import tulip" + cd && cd tulip_build +done From dc9d77cd2131e2da49fe3d2a232cef4355db0f01 Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Thu, 27 Sep 2018 19:22:36 +0200 Subject: [PATCH 5/6] travis.yml: Add tulip-python wheels build for MacOS --- .travis.yml | 52 +++++++++++++++++++++++++++++++++++++++++++++++++- CMakeLists.txt | 3 +++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95f8882c3e..486662ff8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -456,7 +456,7 @@ jobs: #-------------------------------------------------------------------------------------------------------------------------------------------------------------- # modern Tulip complete build on Mac OS - - + - os: osx # use xcode9 travis image to get a recent clang compiler osx_image: xcode9 @@ -504,3 +504,53 @@ jobs: - ninja runTests # build Tulip bundle - ninja bundle + #============================================================================================================================================================== + # Tulip-Python wheels build stage on Mac OS + - stage: Tulip-Python wheels build (Mac OS) + os: osx + osx_image: xcode7.3 + compiler: clang + cache: ccache + install: + # set columns in terminal, required for curl to work correctly: + - export COLUMNS=80 + # install MacPorts in order to easily retrieve Tulip dependencies + - wget https://raw.githubusercontent.com/GiovanniBussi/macports-ci/master/macports-ci + - chmod +x ./macports-ci + - travis_wait ./macports-ci install + - export PATH=/opt/local/bin:$PATH + # install Tulip core build dependencies + - sudo port -N install cmake + - sudo port -N install ccache + - sudo port -N install ninja + - sudo port -N install qhull +universal + - sudo port -N install yajl +universal + # use official Python releases for building the wheels + - curl -LO https://www.python.org/ftp/python/2.7.15/python-2.7.15-macosx10.6.pkg + - sudo installer -pkg python-2.7.15-macosx10.6.pkg -target / + - sudo /Library/Frameworks/Python.framework/Versions/2.7/bin/pip install wheel + - curl -LO https://www.python.org/ftp/python/3.7.0/python-3.7.0-macosx10.6.pkg + - sudo installer -pkg python-3.7.0-macosx10.6.pkg -target / + - sudo /Library/Frameworks/Python.framework/Versions/3.7/bin/pip3 install wheel + + script: + # create build directory + - mkdir build && cd build + # configure Tulip-Python wheel build for Python 2 using cmake + - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DTULIP_ACTIVATE_PYTHON_WHEEL_TARGET=ON -DPYTHON_EXECUTABLE=/Library/Frameworks/Python.framework/Versions/2.7/bin/python -DTULIP_USE_CCACHE=ON || travis_terminate 1 + # compile Tulip and build the Python wheel + - ninja -j4 wheel || travis_terminate 1 + # check that the produced wheel can be correctly imported + - cd ./library/tulip-python/bindings/tulip-core/tulip_module/dist + - /Library/Frameworks/Python.framework/Versions/2.7/bin/pip install $(ls -t | head -1) + - cd - + - /Library/Frameworks/Python.framework/Versions/2.7/bin/python -c "import tulip" + # configure Tulip-Python wheel build for Python 3 using cmake + - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DTULIP_ACTIVATE_PYTHON_WHEEL_TARGET=ON -DPYTHON_EXECUTABLE=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3 -DTULIP_USE_CCACHE=ON || travis_terminate 1 + # compile Tulip and build the Python wheel + - ninja -j4 wheel || travis_terminate 1 + # check that the produced wheel can be correctly imported + - cd ./library/tulip-python/bindings/tulip-core/tulip_module/dist + - /Library/Frameworks/Python.framework/Versions/3.7/bin/pip3 install $(ls -t | head -1) + - cd - + - /Library/Frameworks/Python.framework/Versions/3.7/bin/python3 -c "import tulip" diff --git a/CMakeLists.txt b/CMakeLists.txt index 051a94b921..171befdeb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,9 @@ ENDIF(POLICY CMP0020) IF(POLICY CMP0042) CMAKE_POLICY(SET CMP0042 NEW) ENDIF(POLICY CMP0042) +IF(POLICY CMP0068) + CMAKE_POLICY(SET CMP0068 NEW) +ENDIF(POLICY CMP0068) # enable the use of ccache for Tulip developers to speed up the build process IF(NOT MSVC) From d62cde8fe3b0f494251140bc3077de48fcf95e80 Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Sat, 29 Sep 2018 00:22:14 +0200 Subject: [PATCH 6/6] AppVeyor: Add tulip-python wheels build jobs --- appveyor.yml | 29 ++++++++++++++------- appveyor_msys2_wheel.bat | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 appveyor_msys2_wheel.bat diff --git a/appveyor.yml b/appveyor.yml index 5a2f90d0b6..fe92546b82 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,39 +22,50 @@ init: # define build jobs environment: matrix: + # 64 bits GCC build - MSYS2_ARCH: x86_64 MSYSTEM: MINGW64 PYTHON2_HOME: "C:/Python27-x64" - PYTHON3_HOME: "C:/Python36-x64" + PYTHON3_HOME: "C:/Python37-x64" # 64 bits MSVC build - CMAKE_VS_GENERATOR: "Visual Studio 14 2015 Win64" MSVC_PLATFORM: "x64" MSVC_PLATFORM_TOOLSET: "v140" QT5_DIR: "C:/Qt/5.9/msvc2015_64" - PYTHON_EXECUTABLE: "C:/Python36-x64/python.exe" + PYTHON_EXECUTABLE: "C:/Python37-x64/python.exe" # 32 bits GCC build - MSYS2_ARCH: i686 MSYSTEM: MINGW32 PYTHON2_HOME: "C:/Python27" - PYTHON3_HOME: "C:/Python36" + PYTHON3_HOME: "C:/Python37" # 32 bits MSVC build - CMAKE_VS_GENERATOR: "Visual Studio 14 2015" MSVC_PLATFORM: "Win32" MSVC_PLATFORM_TOOLSET: "v140" QT5_DIR: "C:/Qt/5.9/msvc2015" - PYTHON_EXECUTABLE: "C:/Python36/python.exe" + PYTHON_EXECUTABLE: "C:/Python37/python.exe" + + # 64 bits GCC tulip-python wheels build + - MSYS2_ARCH: x86_64 + MSYSTEM: MINGW64 + PYTHON2_HOME: "C:/Python27-x64" + PYTHON3_HOME: "C:/Python37-x64" + WHEEL: 1 + + # 32 bits GCC tulip-python wheels build + - MSYS2_ARCH: i686 + MSYSTEM: MINGW32 + PYTHON2_HOME: "C:/Python27" + PYTHON3_HOME: "C:/Python37" + WHEEL: 1 # build script that simply call the right batch script depending on the compiler used build_script: - - 'if defined MSYS2_ARCH ("%APPVEYOR_BUILD_FOLDER%\appveyor_msys2.bat") else ("%APPVEYOR_BUILD_FOLDER%\appveyor_msvc.bat")' - -# get the Tulip version for deployment -after_build: - - ps: "$env:TULIP_VERSION = (((Get-Content ($env:APPVEYOR_BUILD_FOLDER + '/build/library/tulip-core/include/tulip/TulipRelease.h') | %{ if ($_ -match '^# define TULIP_VERSION.*$') { $_; } }) -replace '# define TULIP_VERSION ', '') -replace '\"', '')" + - 'if defined MSYS2_ARCH (if defined WHEEL ("%APPVEYOR_BUILD_FOLDER%\appveyor_msys2_wheel.bat") else ("%APPVEYOR_BUILD_FOLDER%\appveyor_msys2.bat")) else ("%APPVEYOR_BUILD_FOLDER%\appveyor_msvc.bat")' # set generated installers as artifacts to deploy artifacts: diff --git a/appveyor_msys2_wheel.bat b/appveyor_msys2_wheel.bat new file mode 100644 index 0000000000..42abea66db --- /dev/null +++ b/appveyor_msys2_wheel.bat @@ -0,0 +1,56 @@ +rem original script taken here: https://github.com/mypaint/libmypaint/blob/master/appveyor.bat +rem Matrix-driven Appveyor CI script for Tulip using GCC compiler provided by MSYS2 +rem https://www.appveyor.com/docs/installed-software#mingw-msys-cygwin +rem Needs the following vars: +rem MSYS2_ARCH: x86_64 or i686 +rem MSYSTEM: MINGW64 or MINGW32 + +rem Set the paths appropriately +PATH C:\msys64\%MSYSTEM%\bin;C:\msys64\usr\bin;%PATH% + +rem Upgrade the MSYS2 platform +bash -lc "pacman --noconfirm --sync --refresh --sysupgrade" + +rem Install required tools +bash -lc "pacman --noconfirm -S --needed base-devel mingw-w64-%MSYS2_ARCH%-toolchain" + +rem Install the relevant native dependencies +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-yajl" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-qhull" +bash -lc "pacman --noconfirm -S --needed --force mingw-w64-%MSYS2_ARCH%-ccache" + +rem Invoke subsequent bash in the build tree +cd %APPVEYOR_BUILD_FOLDER% +set CHERE_INVOKING=yes + +rem Build/test scripting +bash -lc "set pwd" +bash -lc "env" + +rem Install needed wheel module for Python 2 +set PATH=%PYTHON2_HOME%;%PYTHON2_HOME%/Scripts;%PATH% +pip install wheel + +rem Build tulip-python wheel for Python 2 +bash -lc "mkdir build" +bash -lc "cd build && cmake -G \"MSYS Makefiles\" -DTULIP_ACTIVATE_PYTHON_WHEEL_TARGET=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_NEED_RESPONSE=ON -DTULIP_USE_CCACHE=ON -DPYTHON_EXECUTABLE=%PYTHON2_HOME%/python.exe .." +if %errorlevel% neq 0 exit /b %errorlevel% +bash -lc "cd build && make -j4 wheel" +if %errorlevel% neq 0 exit /b %errorlevel% +rem Check that the produced wheel can be correctly imported +bash -lc "cd ./build/library/tulip-python/bindings/tulip-core/tulip_module/dist && pip install $(ls -t | head -1)" +python -c "import tulip" +if %errorlevel% neq 0 exit /b %errorlevel% + +rem Install needed wheel module for Python 3 +set PATH=%PYTHON3_HOME%;%PYTHON3_HOME%/Scripts;%PATH% +pip install wheel + +rem Build tulip-python wheel for Python 3 +bash -lc "mkdir build" +bash -lc "cd build && cmake -G \"MSYS Makefiles\" -DTULIP_ACTIVATE_PYTHON_WHEEL_TARGET=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_NEED_RESPONSE=ON -DTULIP_USE_CCACHE=ON -DPYTHON_EXECUTABLE=%PYTHON3_HOME%/python.exe .." +if %errorlevel% neq 0 exit /b %errorlevel% +bash -lc "cd build && make -j4 wheel" +rem Check that the produced wheel can be correctly imported +bash -lc "cd ./build/library/tulip-python/bindings/tulip-core/tulip_module/dist && pip install $(ls -t | head -1)" +python -c "import tulip"