From b62b07b45452211d59e77a2351eadf171579d8d0 Mon Sep 17 00:00:00 2001 From: fcollot Date: Wed, 10 May 2023 09:55:04 +0200 Subject: [PATCH] Python packaging and initialization (#1123) * adapt to PYNCPP changes * switch to lowercase for pyncpp * Fix handling of install path of embedded Python * more Python fixes * Minor correction to find OpenSSL automatically on macOS --- packaging/apple/mac_packager.sh.in | 8 +++- packaging/windows/WindowsPackaging.cmake | 5 ++ src/CMakeLists.txt | 4 +- src/app/medInria/CMakeLists.txt | 32 +++++++++++++ src/app/medInria/main.cpp | 30 ++++++++++++ superbuild/CMakeLists.txt | 12 ++++- superbuild/projects_modules/medInria.cmake | 12 +++-- .../{PYNCPP.cmake => pyncpp.cmake} | 47 ++++++++++++------- 8 files changed, 125 insertions(+), 25 deletions(-) rename superbuild/projects_modules/{PYNCPP.cmake => pyncpp.cmake} (57%) diff --git a/packaging/apple/mac_packager.sh.in b/packaging/apple/mac_packager.sh.in index e20694cc09..693802ac19 100755 --- a/packaging/apple/mac_packager.sh.in +++ b/packaging/apple/mac_packager.sh.in @@ -15,8 +15,10 @@ cd @medInria_BINARY_DIR@/bin \rm -fr TmpInstall -mkdir TmpInstall -cp -r medInria.app TmpInstall +mkdir -p TmpInstall/medInria.app/Contents/Resources +cp -r medInria.app/Contents/MacOS TmpInstall/medInria.app/Contents +cp medInria.app/Contents/Info.plist TmpInstall/medInria.app/Contents +cp medInria.app/Contents/Resources/medInria.icns TmpInstall/medInria.app/Contents/Resources cd TmpInstall @@ -31,6 +33,8 @@ done @dtk_DIR@/bin/dtkDeploy medInria.app $injectDirs &>/dev/null +@CMAKE_COMMAND@ -DCMAKE_INSTALL_PREFIX:STRING=medInria.app/Contents/Resources -DCMAKE_INSTALL_COMPONENT:STRING=Python -P @pyncpp_DIR@/cmake_install.cmake + #Run fancy packaging apple script \cp -f @medInria_SOURCE_DIR@/utils/osx_packaging/BaseMedinriaPackage.sparseimage.gz @PROJECT_BINARY_DIR@/MedinriaPackage.sparseimage.gz diff --git a/packaging/windows/WindowsPackaging.cmake b/packaging/windows/WindowsPackaging.cmake index 0836d4ce03..deccaac3a8 100644 --- a/packaging/windows/WindowsPackaging.cmake +++ b/packaging/windows/WindowsPackaging.cmake @@ -105,6 +105,11 @@ list(APPEND ${RPI_DIR}/bin/Release ) +set(CPACK_INSTALL_CMAKE_PROJECTS + ${pyncpp_DIR} pyncpp Python "/" + ${CPACK_INSTALL_CMAKE_PROJECTS} + ) + install(CODE " file(GLOB_RECURSE itk_files LIST_DIRECTORIES true \"${ITK_DIR}/bin/*.dll\") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 846de4ff94..a53c3f5639 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,7 +86,7 @@ find_package(dtk REQUIRED) include_directories(${dtk_INCLUDE_DIRS}) if(USE_Python) - find_package(PYNCPP REQUIRED COMPONENTS Qt5) + find_package(pyncpp REQUIRED COMPONENTS CPP_API Qt5) endif() ## ############################################################################# @@ -166,7 +166,7 @@ if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") add_definitions(-DQT_NO_DEBUG) endif() -add_compile_definitions("USE_PYTHON=$") +add_compile_definitions(USE_PYTHON) ## ############################################################################# ## Windows specificity diff --git a/src/app/medInria/CMakeLists.txt b/src/app/medInria/CMakeLists.txt index 870b8ab68a..42f80ade62 100644 --- a/src/app/medInria/CMakeLists.txt +++ b/src/app/medInria/CMakeLists.txt @@ -147,6 +147,38 @@ target_link_libraries(${TARGET_NAME} medPacs ) +## ############################################################################# +## Python +## ############################################################################# + +if(USE_Python) + target_link_libraries(${TARGET_NAME} ${pyncpp_CPP_API_LIBRARY}) + + if(WIN32) + set(python_home ".") + else() + if(APPLE) + set(python_home "../Resources/${pyncpp_PYTHON_INSTALL_DESTINATION}") + else() + set(python_home "../${pyncpp_PYTHON_INSTALL_DESTINATION}") + endif() + + get_filename_component(python_home_base "${python_home}" DIRECTORY) + get_filename_component(python_dir "${python_home}" NAME) + + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "$/${python_home_base}" + ) + + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink "${pyncpp_PYTHON_DIR}" "${python_dir}" + WORKING_DIRECTORY "$/${python_home_base}" + ) + endif() + + target_compile_definitions(${TARGET_NAME} PUBLIC PYTHON_HOME="${python_home}") +endif() + ## ############################################################################# ## install ## ############################################################################# diff --git a/src/app/medInria/main.cpp b/src/app/medInria/main.cpp index fb6ffb6fda..6bd391f283 100644 --- a/src/app/medInria/main.cpp +++ b/src/app/medInria/main.cpp @@ -19,6 +19,10 @@ #include #endif +#if(USE_PYTHON) +#include +#endif + #include #include #include @@ -184,6 +188,24 @@ int main(int argc,char* argv[]) medDataManager::instance()->setDatabaseLocation(); +#if(USE_PYTHON) + pyncpp::Manager pythonManager; + QDir pythonHome = qApp->applicationDirPath(); + QString pythonErrorMessage; + + if (!pythonHome.cd(PYTHON_HOME)) + { + pythonErrorMessage = "The embedded Python could not be found "; + } + else + { + if(!pythonManager.initialize(qUtf8Printable(pythonHome.absolutePath()))) + { + pythonErrorMessage = "Initialization of the embedded Python failed."; + } + } +#endif + medPluginManager::instance()->setVerboseLoading(true); medPluginManager::instance()->initialize(); @@ -234,6 +256,14 @@ int main(int argc,char* argv[]) if (show_splash) splash.finish(mainwindow); +#if(USE_PYTHON) + if(!pythonErrorMessage.isEmpty()) + { + QMessageBox::warning(mainwindow, "Python", pythonErrorMessage); + qWarning() << pythonErrorMessage; + } +#endif + if (medPluginManager::instance()->plugins().isEmpty()) { QMessageBox::warning(mainwindow, QObject::tr("No plugin loaded"), diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index 626294e5e7..fac4976c35 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -30,6 +30,16 @@ find_package(Qt5 REQUIRED COMPONENTS find_package(Boost REQUIRED) +if(USE_Python AND UNIX) + if(APPLE) + set(default_root_dir "/usr/local/opt/openssl@1.1") + else() + set(default_root_dir) + endif() + set(OPENSSL_ROOT_DIR ${default_root_dir} CACHE PATH "Root directory of OpenSSL.") + find_package(OpenSSL COMPONENTS SSL) +endif() + ## ############################################################################# ## Add exteral projects ## ############################################################################# @@ -75,7 +85,7 @@ endif() if (USE_Python) list(APPEND external_projects - PYNCPP + pyncpp ) endif() diff --git a/superbuild/projects_modules/medInria.cmake b/superbuild/projects_modules/medInria.cmake index 260531f59b..261938aae2 100644 --- a/superbuild/projects_modules/medInria.cmake +++ b/superbuild/projects_modules/medInria.cmake @@ -28,6 +28,7 @@ list(APPEND ${ep}_dependencies QtDCM RPI LogDemons + pyncpp ) if (USE_DTKIMAGING) @@ -112,7 +113,7 @@ endif() if (USE_Python) list(APPEND cmake_cache_args - -DPYNCPP_DIR:PATH=${PYNCPP_DIR} + -Dpyncpp_DIR:PATH=${pyncpp_DIR} ) endif() @@ -152,6 +153,7 @@ if (WIN32) file(TO_NATIVE_PATH ${QtDCM_DIR} DCM_BIN_BASE) file(TO_NATIVE_PATH ${_qt5Core_install_prefix} QT5_BIN_BASE) file(TO_NATIVE_PATH ${medInria_BINARY_DIR} MED_BIN_BASE) + file(TO_NATIVE_PATH ${pyncpp_DIR} PYNCPP_BIN_BASE) set(CONFIG_MODE $<$:Debug>$<$:Release>$<$:MinSizeRel>$<$:RelWithDebInfo>) @@ -161,10 +163,12 @@ if (WIN32) POST_BUILD COMMAND for %%I in ( ${ITK_BIN_BASE}\\bin\\${CONFIG_MODE}\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) COMMAND for %%I in ( ${VTK_BIN_BASE}\\bin\\${CONFIG_MODE}\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) - COMMAND for %%I in ( ${DTK_BIN_BASE}\\bin\\${CONFIG_MODE}\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) - COMMAND for %%I in ( ${DCM_BIN_BASE}\\bin\\${CONFIG_MODE}\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) + COMMAND for %%I in ( ${DTK_BIN_BASE}\\bin\\${CONFIG_MODE}\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) + COMMAND for %%I in ( ${DCM_BIN_BASE}\\bin\\${CONFIG_MODE}\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) COMMAND for %%I in ( ${QT5_BIN_BASE}\\bin\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) - ) + COMMAND for %%I in ( ${PYTHON_BIN_BASE}\\bin\\*.dll ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /H ${MED_BIN_BASE}\\%%~nxI %%~fI) + COMMAND for %%I in ( ${PYTHON_BIN_BASE}\\bin\\DLLs ${PYTHON_BIN_BASE}\\bin\\Lib ) do (if EXIST ${MED_BIN_BASE}\\%%~nxI (del /S ${MED_BIN_BASE}\\%%~nxI & mklink /d /H ${MED_BIN_BASE}\\%%~nxI %%~fI) else mklink /d /H ${MED_BIN_BASE}\\%%~nxI %%~fI) + ) endif() diff --git a/superbuild/projects_modules/PYNCPP.cmake b/superbuild/projects_modules/pyncpp.cmake similarity index 57% rename from superbuild/projects_modules/PYNCPP.cmake rename to superbuild/projects_modules/pyncpp.cmake index 9ab6744882..e6f8b0076b 100644 --- a/superbuild/projects_modules/PYNCPP.cmake +++ b/superbuild/projects_modules/pyncpp.cmake @@ -11,25 +11,23 @@ # ################################################################################ -function(PYNCPP_project) +set(PYTHON_VERSION_MAJOR 3 CACHE STRING "Python major version") +set(PYTHON_VERSION_MINOR 10 CACHE STRING "Python minor version") +set(PYTHON_VERSION_PATCH 10 CACHE STRING "Python patch version") - set(ep PYNCPP) +function(pyncpp_project) + + set(ep pyncpp) EP_Initialisation(${ep} USE_SYSTEM OFF BUILD_SHARED_LIBS ON - REQUIRED_FOR_PLUGINS OFF + REQUIRED_FOR_PLUGINS ON ) - if(USE_SYSTEM_${ep}) - find_package(PYNCPP - REQUIRED COMPONENTS Qt5 - ) - else() - epComputPath(${ep}) + if(NOT USE_SYSTEM_${ep}) - set(source_dir ${EP_PATH_SOURCE}/${ep}) - set(binary_dir ${build_path}) + epComputPath(${ep}) set(project_args GIT_REPOSITORY ${GITHUB_PREFIX}LIRYC-IHU/pyncpp.git @@ -38,28 +36,45 @@ function(PYNCPP_project) GIT_PROGRESS True ) + set(cmake_args + -D "PYNCPP_PYTHON_VERSION_MAJOR:STRING=${PYTHON_VERSION_MAJOR}" + -D "PYNCPP_PYTHON_VERSION_MINOR:STRING=${PYTHON_VERSION_MINOR}" + -D "PYNCPP_PYTHON_VERSION_PATCH:STRING=${PYTHON_VERSION_PATCH}" + ) + + if(UNIX) + list(APPEND cmake_args + -D Qt5_DIR:PATH=${Qt5_DIR} + -D OPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR} + ) + if(APPLE) + list(APPEND cmake_args + -D CMAKE_MACOSX_RPATH:BOOL=OFF + ) + endif() + endif() + ## ##################################################################### ## Add external project ## ##################################################################### ExternalProject_Add(${ep} PREFIX ${EP_PATH_SOURCE} - SOURCE_DIR ${source_dir} - BINARY_DIR ${binary_dir} + SOURCE_DIR ${EP_PATH_SOURCE}/${ep} + BINARY_DIR ${build_path} TMP_DIR ${tmp_path} STAMP_DIR ${stamp_path} DEPENDS ${${ep}_dependencies} + CMAKE_ARGS ${cmake_args} INSTALL_COMMAND "" "${project_args}" ) - ExternalProject_Get_Property(${ep} binary_dir) - ## ##################################################################### ## Export variables ## ##################################################################### - set(${ep}_DIR ${binary_dir} PARENT_SCOPE) + set(${ep}_DIR ${build_path} PARENT_SCOPE) endif()