diff --git a/CMake/mitkSwigPrepareFiles.cmake b/CMake/mitkSwigPrepareFiles.cmake index 49a07a5c0a..8408f7e9f6 100644 --- a/CMake/mitkSwigPrepareFiles.cmake +++ b/CMake/mitkSwigPrepareFiles.cmake @@ -1,31 +1,39 @@ # This function is used to prepare all includes and files # that are necessary for a general swig project. function(mitkSwigPrepareFiles swig_file library_names) # Ensure that the input file is parsed as a c++ file. This is done via # an additional source file property. set_source_files_properties ( ${swig_file} PROPERTIES CPLUSPLUS ON ) # This variable is used to add additional parameters to SWIG. # Using a list is necessary in order to be able to pass multiple parameters # which are given as optional parameters to the input file. set(ADDITIONAL_TMP_SWIG_INCLUDES "") foreach(library_name ${library_names}) # Extracting all include directories from each given project and # then including these directories to the newly created swig project. get_property(LIBRARY_INCLUDES TARGET ${library_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) # Adding each include path as an additional swig parameter using # the swig-option "-I": foreach(INCLUDE_PATH ${LIBRARY_INCLUDES}) list(APPEND ADDITIONAL_TMP_SWIG_INCLUDES -I${INCLUDE_PATH} ) endforeach() endforeach() # Add the Common Folder to the include system of SWIG list(APPEND ADDITIONAL_TMP_SWIG_INCLUDES -I${MITK_WRAPPING_COMMON_DIR} ) + + # This is necessary, because SWIG hard-codeds the integer size. See + # https://github.com/swig/swig/issues/568 + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + list(APPEND ADDITIONAL_TMP_SWIG_INCLUDES -DSWIGWORDSIZE64) + endif() + + # Set the additional parameters to the input project file: set_property(SOURCE ${swig_file} PROPERTY SWIG_FLAGS ${ADDITIONAL_TMP_SWIG_INCLUDES} ) -endfunction() \ No newline at end of file +endfunction() diff --git a/Wrapping/Python/LegacyPackaging.cmake b/Wrapping/Python/LegacyPackaging.cmake index 2c7b214824..2924b14860 100644 --- a/Wrapping/Python/LegacyPackaging.cmake +++ b/Wrapping/Python/LegacyPackaging.cmake @@ -1,111 +1,113 @@ if ( SimpleITK_DOC_FILES ) # create a python list for the import documents to include in # packaging # specially handle the first element list( GET SimpleITK_DOC_FILES 0 d ) file(TO_NATIVE_PATH "${d}" d ) set( SimpleITK_DOC_FILES_AS_LIST "[r'${d}'") set( _doc_list "${SimpleITK_DOC_FILES}" ) list( REMOVE_AT _doc_list 0 ) foreach( d ${_doc_list} ) file(TO_NATIVE_PATH "${d}" d ) set( SimpleITK_DOC_FILES_AS_LIST "${SimpleITK_DOC_FILES_AS_LIST},r'${d}'") endforeach() set( SimpleITK_DOC_FILES_AS_LIST "${SimpleITK_DOC_FILES_AS_LIST}]") endif() # Step 1: # Do initial configuration of setup.py with variable a available # at configuration time. set(MITK_BINARY_MODULE "@MITK_BINARY_MODULE@") set(MITK_RUNTIME_PATH "@MITK_RUNTIME_PATH@") set(PYTHON_LIB_DEPENDENCIES "@PYTHON_LIB_DEPENDENCIES@") +set(TMP_MITK_BINARY_MODULE "@MITK_BINARY_MODULE@" ) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/Packaging/setup.py.in" "${CMAKE_CURRENT_BINARY_DIR}/Packaging/setup.py.in" ) set(MITK_BINARY_MODULE) # Step 2: # Do file configuration during compilation with generator expressions mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH release) + add_custom_command(TARGET ${SWIG_MODULE_PythonMITK_REAL_NAME} POST_BUILD WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND ${CMAKE_COMMAND} "-DMITK_BINARY_MODULE=$" "-DMITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY=${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}" - "-DMITK_RUNTIME_PATH=${MITK_RUNTIME_PATH}" + "-\"DMITK_RUNTIME_PATH=${MITK_RUNTIME_PATH}\"" "-DCONFIGUREBUILDTIME_filename=${CMAKE_CURRENT_BINARY_DIR}/Packaging/setup.py.in" "-DCONFIGUREBUILDTIME_out_filename=${CMAKE_CURRENT_BINARY_DIR}/Packaging/setup.py" -P "${MITK_SOURCE_DIR}/CMake/mitkSWIGConfigurePythonfileBuildtime.cmake" COMMENT "Generating setup.py..." ) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py" "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" COPYONLY ) # Hopefully being able to turn this option on at some point in future. option(MITK_PYTHON_USE_VIRTUALENV "Create a Python Virtual Environment for testing." OFF) mark_as_advanced(MITK_PYTHON_USE_VIRTUALENV) set(VIRTUAL_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) if (MITK_PYTHON_USE_VIRTUALENV) # Executable to setup a new Python virtual environment find_package( PythonVirtualEnv REQUIRED ) sitk_enforce_forbid_downloads( MITK_PYTHON_USE_VIRTUALENV ) if (SimpleITK_PYTHON_WHEEL AND PYTHON_VIRTUALENV_VERSION_STRING VERSION_LESS "13") message(SEND_ERROR "In sufficient version of virutalenv for \ building wheels. Require virtualenv>=13.0.") endif() # # Setup Python Virtual Environment for testing and packaging # set( PythonVirtualenvHome "${${CMAKE_PROJECT_NAME}_BINARY_DIR}/Testing/Installation/PythonVirtualenv" ) # virtualenv places the python executable in different # locations. Also note than on windows installations where python is # installed only for a single user the may be a missing dll issue. if( WIN32 ) set( VIRTUAL_PYTHON_EXECUTABLE "${PythonVirtualenvHome}/Scripts/python") else( ) set( VIRTUAL_PYTHON_EXECUTABLE "${PythonVirtualenvHome}/bin/python" ) endif() set(SimpleITK_PYTHON_TEST_EXECUTABLE "${VIRTUAL_PYTHON_EXECUTABLE}" CACHE INTERNAL "Python executable for testing." FORCE ) # configure a scripts which creates the virtualenv and installs numpy configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/PythonVirtualEnvInstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/PythonVirtualEnvInstall.cmake" @ONLY ) set( PythonVirtualEnv_ALL "" ) if ( BUILD_TESTING ) set( PythonVirtualEnv_ALL "ALL" ) endif() add_custom_target( PythonVirtualEnv ${PythonVirtualEnv_ALL} DEPENDS "${VIRTUAL_PYTHON_EXECUTABLE}" SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/PythonVirtualEnvInstall.cmake.in ) add_custom_command( OUTPUT "${VIRTUAL_PYTHON_EXECUTABLE}" COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/PythonVirtualEnvInstall.cmake" DEPENDS "${SWIG_MODULE_SimpleITKPython_TARGET_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/PythonVirtualEnvInstall.cmake" COMMENT "Creating python virtual enviroment..." ) endif() # Packaging for distribution add_subdirectory(dist) diff --git a/Wrapping/Python/Packaging/setup.py.in b/Wrapping/Python/Packaging/setup.py.in index 12ff67d4ae..f332045b14 100644 --- a/Wrapping/Python/Packaging/setup.py.in +++ b/Wrapping/Python/Packaging/setup.py.in @@ -1,126 +1,131 @@ import sys import os import glob +import itertools as it + +def multiple_file_types(path, *patterns): + return it.chain.from_iterable(glob.iglob(os.path.joing(path,pattern)) for pattern in patterns) try: from setuptools import setup, Extension from setuptools.command.build_ext import build_ext as _build_ext except ImportError: from distutils.core import setup, Extension from distutils.command.build_ext import build_ext as _build_ext import re doc_files = "" dependency_paths = "@MITK_RUNTIME_PATH@" dependency_files = "@PYTHON_LIB_DEPENDENCIES@" +binary_module_file = "@TMP_MITK_BINARY_MODULE@" def get_pep386version(): """This method examines the SimpleITK's CMake version variables to make a pep 386 compliant version string when building a version indented for distribution.""" sitkMAJOR = "@MITK_VERSION_MAJOR@" sitkMINOR = "@MITK_VERSION_MINOR@" sitkPATCH = "@MITK_VERSION_PATCH@" sitkTWEAK = "@MITK_VERSION_TWEAK@" sitkRC = "@MITK_VERSION_RC@" sitkPOST = "@MITK_VERSION_POST@" sitkDEV = "@MITK_VERSION_DEV@" sitkHASH = "@MITK_VERSION_HASH@" version = sitkMAJOR+"."+sitkMINOR if sitkPATCH: version += "."+sitkPATCH if sitkTWEAK: version += "."+sitkTWEAK if sitkRC: version += sitkRC if sitkPOST: version += ".post"+sitkPOST elif sitkDEV: version += ".dev"+sitkDEV # Local Version Identifier if sitkHASH and not "@SimpleITK_BUILD_DISTRIBUTE@" in ['1', 'ON']: version += "+g"+sitkHASH return version class build_ext(_build_ext): """ Override standard command class to build an extension, to simply copy an existing compiled library into the packaging directory structure. """ def build_extension(self, ext): """ """ from distutils.errors import DistutilsSetupError sources = ext.sources if sources is None or not len(sources) == 1: raise DistutilsSetupError( "Expected only one compiled library." ) expected_ext_filename = os.path.split(self.get_ext_filename(ext.name))[1] ext_file = self.get_ext_fullpath(ext.name) abs_sources = list( map(os.path.abspath, sources) ) module_name=ext.name.split(".")[0] placeholder = self.get_ext_filename("placeholder") for current_path in dependency_paths.split(";"): - for pyd_file in glob.glob(os.path.join(current_path,"*.pyd")): - if sources[0] in pyd_file: - self.copy_file(pyd_file, ext_file) - for dll_file in glob.glob(os.path.join(current_path,"*.dll")): - if "Qt" in dll_file: + for library_file in multiple_file_types(current_path, "*.pyd","*.so","*.dll"): + if binary_module_file in library_file: + self.copy_file(library_file, ext_file) + continue + if "Qt" in library_file: continue - dll_basename=os.path.basename(dll_file) - if dll_basename not in dependency_files: + library_basename=os.path.basename(library_file) + if library_basename not in dependency_files: continue - dll_target= self.get_ext_fullpath(module_name+".placeholder") - self.copy_file(dll_file,dll_target.replace(placeholder,dll_basename)) + library_target= self.get_ext_fullpath(module_name+".placeholder") + self.copy_file(library_file,library_target.replace(placeholder,library_basename)) #self.copy_file(abs_sources[0], ext_file) setup( name = 'PythonMITK', version = get_pep386version(), author = 'Medical Image Computing, DKFZ Heidelberg', author_email = 'm.goetz@dkfz-heidelberg.de', ext_modules=[Extension('PythonMITK._PythonMITK', [r'@MITK_BINARY_MODULE@'])], packages= ['PythonMITK'], package_dir = {'PythonMITK':r'@MITK_PYTHON_PACKAGE_DIR@'}, download_url = r'https://www.itk.org/SimpleITKDoxygen/html/PyDownloadPage.html', platforms = [], description = r'SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation', long_description = 'SimpleITK provides an abstraction layer to ITK that enables developers \ and users to access the powerful features of the InsightToolkit in an easy \ to use manner for biomedical image analysis.', classifiers=[ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: C++", "Development Status :: 5 - Production/Stable", "Intended Audience :: Education", "Intended Audience :: Healthcare Industry", "Intended Audience :: Science/Research", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Medical Science Apps.", "Topic :: Scientific/Engineering :: Information Analysis", "Topic :: Software Development :: Libraries", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Operating System :: Unix", "Operating System :: MacOS" ], license='Apache', keywords = 'SimpleITK ITK InsightToolkit segmentation registration', url = r'http://simpleitk.org/', cmdclass={'build_ext':build_ext} )