diff --git a/CMake/configure_file_build_time.cmake b/CMake/configure_file_build_time.cmake new file mode 100644 index 0000000000..cf1a18002b --- /dev/null +++ b/CMake/configure_file_build_time.cmake @@ -0,0 +1 @@ +configure_file( "${CONFIGUREBUILDTIME_filename}" "${CONFIGUREBUILDTIME_out_filename}" ) diff --git a/CMake/mitkSwigAddLibraryDependencies.cmake b/CMake/mitkSwigAddLibraryDependencies.cmake new file mode 100644 index 0000000000..a2166beb99 --- /dev/null +++ b/CMake/mitkSwigAddLibraryDependencies.cmake @@ -0,0 +1,43 @@ +#! This CMake macro adds the necessary library and incllude +#! directories to a swig-project. +#! +#! params: +#! swig_module : Name of the SWIG module, for example PythonMITK +#! library_names : Semicolon separated list of the libraries that are included, for example "MitkCore;mbilog" +#! + + +# function inspired by +# https://stackoverflow.com/questions/37205274/swig-and-cmake-make-use-of-information-provided-by-target-include-directories +# This function tells cmake which additional dependencies are existing +# especially with respect to the linker dependencies. +function(mitkSwigAddLibraryDependencies swig_module library_names) + foreach(library_name ${library_names}) + # Adding each library as a linker dependency: + swig_link_libraries(${swig_module} ${library_name}) + # 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) + # Checking each given librarie to include all includes from this library. + foreach(INCLUDE_PATH ${LIBRARY_INCLUDES}) + file(GLOB_RECURSE header_files "${INCLUDE_PATH}/*.h") + list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${header_files}) + # export variable to parent scope + set(SWIG_MODULE_${swig_module}_EXTRA_DEPS + ${SWIG_MODULE_${swig_module}_EXTRA_DEPS} PARENT_SCOPE) + endforeach() + endforeach() + + # In addition include python dependencies: + include_directories( ${PYTHON_INCLUDE_DIR}) + list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${PYTHON_INCLUDE_DIR}) + swig_link_libraries(${swig_module} ${PYTHON_LIBRARIES} ) + + # Add additional include paths, for example to the common files: + list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${SWIG_EXTRA_DEPS}) + + set(SWIG_MODULE_${swig_module}_EXTRA_DEPS + ${SWIG_MODULE_${swig_module}_EXTRA_DEPS} PARENT_SCOPE) +endfunction() \ No newline at end of file diff --git a/CMake/mitkSwigPrepareFiles.cmake b/CMake/mitkSwigPrepareFiles.cmake new file mode 100644 index 0000000000..49a07a5c0a --- /dev/null +++ b/CMake/mitkSwigPrepareFiles.cmake @@ -0,0 +1,31 @@ + +# 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} ) + # 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 diff --git a/Wrapping/CMakeLists.txt b/Wrapping/CMakeLists.txt index d37427ae36..7d516b4e7d 100644 --- a/Wrapping/CMakeLists.txt +++ b/Wrapping/CMakeLists.txt @@ -1,58 +1,68 @@ find_package(SWIG REQUIRED) include(mitkLanguageOptions) include(UseSWIG) +include(mitkSwigAddLibraryDependencies) +include(mitkSwigPrepareFiles) + +# Path to common files +set(MITK_WRAPPING_COMMON_DIR ${MITK_SOURCE_DIR}/Wrapping/Common) +# make a manual list of dependencies for the Swig.i files +list( APPEND SWIG_EXTRA_DEPS + "${MITK_WRAPPING_COMMON_DIR}/MITK_Common.i" + ) + # A general packaging target, not built by default, to build packages for each # language. This should depend on all language specific targets. add_custom_target( dist ${CMAKE_COMMAND} -E echo "Finished generating wrapped packages for distribution..." ) # # lua SWIG configuration # #if ( WRAP_LUA ) # add_subdirectory ( Lua ) #endif() # # python SWIG configuration # if ( WRAP_PYTHON ) add_subdirectory ( Python ) endif() # # ruby SWIG configuration # #if ( WRAP_RUBY ) # add_subdirectory ( Ruby ) #endif() # # JAVA SWIG configuration # #if ( WRAP_JAVA ) # add_subdirectory( Java ) #endif() # # C# SWIG configuration # #if ( WRAP_CSHARP ) # add_subdirectory ( CSharp ) #endif() # # TCL SWIG configuration # #if ( WRAP_TCL ) # add_subdirectory ( Tcl ) #endif() # # R SWIG configuration # #if ( WRAP_R ) # add_subdirectory( R ) #endif() diff --git a/Wrapping/Common/mitk_swig_classes.i b/Wrapping/Common/mitk_swig_classes.i new file mode 100644 index 0000000000..80d3ac2deb --- /dev/null +++ b/Wrapping/Common/mitk_swig_classes.i @@ -0,0 +1,22 @@ + +// +// Defining some Macros that make problems with SWIG as the +// corresponding definitions are not included by default. +// Luckely, these includes are not necessary for SWIG. +// +#define ITK_NOEXCEPT +#define ITKCommon_EXPORT +#define ITK_OVERRIDE +#define MITKCORE_EXPORT + +%include +%include +%include +%include +%include +%include + +SWIG_ADD_MITK_CLASS(BaseData, mitkBaseData.h) +SWIG_ADD_MITK_CLASS(SlicedData, mitkSlicedData.h) +SWIG_ADD_MITK_CLASS(Image, mitkImage.h) +SWIG_ADD_MITK_CLASS(PointSet, mitkPointSet.h) \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_common.i b/Wrapping/Common/mitk_swig_common.i new file mode 100644 index 0000000000..9574fdca48 --- /dev/null +++ b/Wrapping/Common/mitk_swig_common.i @@ -0,0 +1,31 @@ + +// Ignore common warnings: +// 302 : Redefinition of Macro, usually not a problem +// 362 : Operator= is ignored. Can't help it. +// 503 : Can't wrap operator of type "*" unless renamed to a valid identifier, no problem as operator not needed. +// 509 : Overloaded function ignored. Usually not a problem, as overloaded functions shouldn't give different results. +// 511 : Can't use keyword arguments with overloaded functions +#pragma SWIG nowarn=302,362,503,509,511 + +// Splitted the information about the addition files into sub-files: + +// Include c++ code in this file. It is basically a c++-header wrapped in the commands so it is included in the std-file +%include +// SWIG-Macro definition goes in here, for example SWIG_ADD_MITK_CLASS +%include +// Includes of STD-Files goes in here +%include +// information about classes that are going to be wrapped are in here: +%include + +// +// How to wrap a new class: +// ------------------------------------ +// 1. Add the c++ include file to mitk_swig_cpp_include.i +// If the class is in a new module, make sure that this module is added as dependency in cmake +// 2. Add the class definition in mitk_swig_classes.i +// If the definition of the class needs new macros, for example because it is not in the core +// and has a new Export-Macro, be sure to define this macro first. +// If the class inherit from mitk::BaseData use the SWIG_ADD_MITK_CLASS macro, as it defines +// some redundante code. +// \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_cpp_include.i b/Wrapping/Common/mitk_swig_cpp_include.i new file mode 100644 index 0000000000..975a2bdc01 --- /dev/null +++ b/Wrapping/Common/mitk_swig_cpp_include.i @@ -0,0 +1,15 @@ +%{ + +#include +#include +#include +#include +#include +#include +#include + +// SWIG Doesn't wrap namespaces. This leads to some problems, if the namespaces are not used. +using namespace mitk; +using namespace itk; + +%} \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_macros.i b/Wrapping/Common/mitk_swig_macros.i new file mode 100644 index 0000000000..98a7bb977a --- /dev/null +++ b/Wrapping/Common/mitk_swig_macros.i @@ -0,0 +1,28 @@ +// +// This file contains macros for swig. +// + +// +// SWIG_ADD_MITK_CLASS is a helper macro in order to do +// all important stuff before an mitk::Class is included. +// Requires the name of the class as it is in c++ as classname +// and the include file, in which the class is defined. +// It is assumed that the class is somehow inherited from +// mitk::BaseData, and supports smartpointers. +// +%define SWIG_ADD_MITK_CLASS(classname, classinclude) + // Declaring that this class is a smart-pointer class, in order to handle + // online upcasting where necessary (for example python) + %feature("smartptr", noblock=1) mitk:: ## classname { itk::SmartPointer } + + // Include the given header, where the class definition is found + %include + + // Initianziation of std. vectors containing pointers to these classes. This allows to use + // vectors of these types as target language arrays. + %template(Vector ## classname ## Pointer) std::vector< itk::SmartPointer >; + %template(Vector ## classname) std::vector< mitk:: ## classname ## ::Self *>; + + // Defining the Smartpointer, allows easy access in target language + %template(classname ## Pointer) itk::SmartPointer; +%enddef \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_std.i b/Wrapping/Common/mitk_swig_std.i new file mode 100644 index 0000000000..e2f75ff752 --- /dev/null +++ b/Wrapping/Common/mitk_swig_std.i @@ -0,0 +1,33 @@ + +// +// Includes for STD-library support +// +%include +%include +%include +#if SWIGPYTHON || SWIGRUBY +%include +#endif +// Use C99 int support +%include + +// +// Template definition for the most common vector types +// +namespace std { + %template(VectorBool) vector; + %template(VectorUInt8) vector; + %template(VectorInt8) vector; + %template(VectorUInt16) vector; + %template(VectorInt16) vector; + %template(VectorUInt32) vector; + %template(VectorInt32) vector; + %template(VectorUInt64) vector; + %template(VectorInt64) vector; + %template(VectorFloat) vector; + %template(VectorDouble) vector; + %template(VectorUIntList) vector< vector >; + %template(VectorString) vector< std::string >; + + %template(DoubleDoubleMap) map; +} \ No newline at end of file diff --git a/Wrapping/Python/CMakeLists - Kopie.txt b/Wrapping/Python/CMakeLists - Kopie.txt deleted file mode 100644 index 303d899bf9..0000000000 --- a/Wrapping/Python/CMakeLists - Kopie.txt +++ /dev/null @@ -1,105 +0,0 @@ -# Version 2.8.1 is the minium requirement for this script. -# this is lower than the general minimum requirement. -#cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) - -project( MITK_Python ) - -include(../sitkProjectLanguageCommon.cmake NO_POLICY_SCOPE) - -# -# Find the necessary libraries etc.. -# -if ( SITK_UNDEFINED_SYMBOLS_ALLOWED ) - set( _QUIET_LIBRARY "QUIET" ) -else() - set( _QUIET_LIBRARY "REQUIRED" ) -endif() -find_package ( PythonInterp REQUIRED ) -find_package ( PythonLibs ${_QUIET_LIBRARY} ) -include_directories ( ${SimpleITK_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ) - -# -# Options -# -option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) -mark_as_advanced( MITK_PYTHON_THREADS ) -option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) -mark_as_advanced( MITK_PYTHON_EGG ) -option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) -mark_as_advanced( MITK_PYTHON_WHEEL ) - -#################################### Neeeds to be adapted ###################################### -set_source_files_properties ( SimpleITK.i PROPERTIES CPLUSPLUS ON ) - -# Run swig -set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) -if( MITK_PYTHON_THREADS ) - set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) -endif() -set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) - -#################################### Neeeds to be adapted ###################################### -set(SWIG_MODULE_SimpleITK_EXTRA_DEPS ${SWIG_EXTRA_DEPS} - ${CMAKE_CURRENT_SOURCE_DIR}/Python.i ) - -#################################### Neeeds to be adapted ###################################### -swig_add_module ( SimpleITK python - SimpleITK.i - sitkPyCommand.cxx ) -set(SWIG_MODULE_MITKPython_TARGET_NAME "${SWIG_MODULE_MITK_TARGET_NAME}") -target_link_libraries( ${SWIG_MODULE_MITKPython_TARGET_NAME} ${SimpleITK_LIBRARIES} ) -if(NOT PYTHON_DEBUG_LIBRARIES AND MSVC) - # If there is not a specified debug library use the release library, - # via a special sitkPython.h header. - target_compile_definitions(${SWIG_MODULE_MITKPython_TARGET_NAME} - PRIVATE - $<$:SWIG_PYTHON_INTERPRETER_NO_DEBUG>) -endif() -sitk_target_link_libraries_with_dynamic_lookup( ${SWIG_MODULE_MITKPython_TARGET_NAME} ${PYTHON_LIBRARIES} ) - -target_include_directories( ${SWIG_MODULE_MITKPython_TARGET_NAME} - PRIVATE - ${PYTHON_INCLUDE_DIR} ) -target_include_directories( ${SWIG_MODULE_MITKPython_TARGET_NAME} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} ) - -set_target_properties( ${SWIG_MODULE_MITK_TARGET_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -if ( MSVC ) - foreach ( CMAKE_CONFIGURATION_TYPE ${CMAKE_CONFIGURATION_TYPES} ) - string(TOUPPER ${CMAKE_CONFIGURATION_TYPE} CMAKE_CONFIGURATION_TYPE) - set_target_properties(${SWIG_MODULE_MITK_TARGET_NAME} - PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${CMAKE_CONFIGURATION_TYPE} "${CMAKE_CURRENT_BINARY_DIR}") - set_target_properties(${SWIG_MODULE_MITK_TARGET_NAME} - PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${CMAKE_CONFIGURATION_TYPE} "${CMAKE_CURRENT_BINARY_DIR}") - endforeach( ) -endif() -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-w") -sitk_strip_target( ${SWIG_MODULE_MITKPython_TARGET_NAME} ) - - - -# Installation -set( MITK_PYTHON_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}" ) -file( TO_NATIVE_PATH "${MITK_PYTHON_PACKAGE_DIR}" MITK_PYTHON_PACKAGE_DIR ) - -set(SimpleITK_PYTHON_TEST_EXECUTABLE "${PYTHON_EXECUTABLE}" CACHE INTERNAL "Python executable for testing." FORCE ) - -if(DEFINED SKBUILD) - # Currently this installation - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/SimpleITK.py - ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py - ${SimpleITK_DOC_FILES} - DESTINATION MITK - COMPONENT Runtime - ) - - install(TARGETS ${SWIG_MODULE_MITKPython_TARGET_NAME} - RUNTIME DESTINATION MITK - LIBRARY DESTINATION MITK - COMPONENT Runtime - ) -else() - include(LegacyPackaging.cmake) -endif() diff --git a/Wrapping/Python/CMakeLists.txt b/Wrapping/Python/CMakeLists.txt index bc8e54130e..7cdce96568 100644 --- a/Wrapping/Python/CMakeLists.txt +++ b/Wrapping/Python/CMakeLists.txt @@ -1,68 +1,64 @@ # Version 2.8.1 is the minium requirement for this script. # this is lower than the general minimum requirement. #cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) project( MITK_Python ) -# function taken from -# https://stackoverflow.com/questions/37205274/swig-and-cmake-make-use-of-information-provided-by-target-include-directories -function(swig_add_library_dependencies swig_module library_names) - foreach(library_name ${library_names}) - get_property(LIBRARY_INCLUDES - TARGET ${library_name} - PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - foreach(INCLUDE_PATH ${LIBRARY_INCLUDES}) - include_directories(${INCLUDE_PATH}) - file(GLOB_RECURSE header_files "${INCLUDE_PATH}/*.h") - list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${header_files}) - message(STATUS ${header_files}) - # export variable to parent scope - set(SWIG_MODULE_${swig_module}_EXTRA_DEPS - ${SWIG_MODULE_${swig_module}_EXTRA_DEPS} PARENT_SCOPE) - endforeach() - endforeach() -endfunction() - # # Find the necessary libraries etc.. # if ( MITK_UNDEFINED_SYMBOLS_ALLOWED ) set( _QUIET_LIBRARY "QUIET" ) else() set( _QUIET_LIBRARY "REQUIRED" ) endif() + find_package ( PythonInterp REQUIRED ) find_package ( PythonLibs ${_QUIET_LIBRARY} ) # # Options # option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) mark_as_advanced( MITK_PYTHON_THREADS ) option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) mark_as_advanced( MITK_PYTHON_EGG ) option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) mark_as_advanced( MITK_PYTHON_WHEEL ) -set_source_files_properties ( MITK.i PROPERTIES CPLUSPLUS ON ) -set(ADDITIONAL_TMP_SWIG_INCLUDES "-IE:/Projects/MitkPython/mitk/Modules/Core/include" "-IE:/Projects/MitkPython/mitk-bin/ep/include/ITK-4.12" ) -#set_source_files_properties ( MITK.i PROPERTIES SWIG_FLAGS "${ADDITIONAL_TMP_SWIG_INCLUDES}" ) -set_property(SOURCE MITK.i PROPERTY SWIG_FLAGS ${ADDITIONAL_TMP_SWIG_INCLUDES} ) +# Prepare the SWIG-File, i.e. especially add necessary include folders +mitkSwigPrepareFiles(MITK.i "MitkCore") -# Run swig +# Add additional SWIG Parameters +# These parameters depend on the target language set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) if( MITK_PYTHON_THREADS ) set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) endif() set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) - - -swig_add_module ( PythonMITK python - MITK.i ) -swig_link_libraries(PythonMITK MitkCore ) -swig_link_libraries(PythonMITK ${PYTHON_LIBRARIES} ) +# Create the actual SWIG project +swig_add_module(PythonMITK python MITK.i ) + +mitkSwigAddLibraryDependencies(PythonMITK "MitkCore") -include_directories( ${PYTHON_INCLUDE_DIR}) -list(APPEND SWIG_MODULE_PythonMITK_EXTRA_DEPS ${PYTHON_INCLUDE_DIR}) -swig_add_library_dependencies(PythonMITK "MitkCore;mbilog;CppMicroServices") \ No newline at end of file +if(DEFINED SKBUILD) + message(WARNING "SKBuild exists") + # Currently this installation + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/PythonMITK.py + ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py + # ${SimpleITK_DOC_FILES} + DESTINATION PythonMITK + COMPONENT Runtime + ) + + install(TARGETS ${SWIG_MODULE_PythonMITK_REAL_NAME} + RUNTIME DESTINATION PythonMITK + LIBRARY DESTINATION PythonMITK + COMPONENT Runtime + ) +else() + message(WARNING "SKBuild missing") + include(LegacyPackaging.cmake) +endif() \ No newline at end of file diff --git a/Wrapping/Python/LegacyPackaging.cmake b/Wrapping/Python/LegacyPackaging.cmake new file mode 100644 index 0000000000..e9c0c80ade --- /dev/null +++ b/Wrapping/Python/LegacyPackaging.cmake @@ -0,0 +1,106 @@ +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@") +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 +add_custom_command(TARGET ${SWIG_MODULE_PythonMITK_REAL_NAME} + POST_BUILD + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND ${CMAKE_COMMAND} + "-DMITK_BINARY_MODULE=$" + "-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/configure_file_build_time.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/MITK.i b/Wrapping/Python/MITK.i index 6e87d5df69..536ae52089 100644 --- a/Wrapping/Python/MITK.i +++ b/Wrapping/Python/MITK.i @@ -1,68 +1,4 @@ %module PythonMITK -%{ -#include -#include -using namespace mitk; -using namespace itk; -int hello() {return 1;}; - -mitk::BaseData::Pointer Load(const std::string &path) -{ - return mitk::IOUtil::Load(path)[0]; -} - -%} - -// Use STL support -%include -%include -%include -#if SWIGPYTHON || SWIGRUBY -%include -#endif -// Use C99 int support -%include - -#define MITKCORE_EXPORT -%define mitkClassMacroItkParent(className, SuperClassName) - typedef className Self; - typedef SuperClassName Superclass; - typedef itk::SmartPointer Pointer; - typedef itk::SmartPointer ConstPointer; - static const char *GetStaticNameOfClass() { return #className; } - virtual std::vector GetClassHierarchy() const { return mitk::GetClassHierarchy(); } - // itkTypeMacro(className, SuperClassName) -%enddef -#define DEPRECATED(...) ##__VA_ARGS__ -#define ITK_NOEXCEPT - -%include -%include -%include - -extern int hello(); -extern mitk::BaseData::Pointer Load(const std::string &path); - -namespace std { - %template(VectorBaseDataPointer) vector< itk::SmartPointer >; - %template(VectorBaseData) vector< mitk::BaseData::Self *>; - - %template(VectorBool) vector; - %template(VectorUInt8) vector; - %template(VectorInt8) vector; - %template(VectorUInt16) vector; - %template(VectorInt16) vector; - %template(VectorUInt32) vector; - %template(VectorInt32) vector; - %template(VectorUInt64) vector; - %template(VectorInt64) vector; - %template(VectorFloat) vector; - %template(VectorDouble) vector; - %template(VectorUIntList) vector< vector >; - %template(VectorString) vector< std::string >; - - %template(DoubleDoubleMap) map; -} -%template(BaseDataPointer) itk::SmartPointer; +%include diff --git a/Wrapping/Python/Packaging/__init__.py b/Wrapping/Python/Packaging/__init__.py new file mode 100644 index 0000000000..14549ece6b --- /dev/null +++ b/Wrapping/Python/Packaging/__init__.py @@ -0,0 +1 @@ +from .PythonMITK import * diff --git a/Wrapping/Python/Packaging/setup.py.in b/Wrapping/Python/Packaging/setup.py.in new file mode 100644 index 0000000000..492aa95fbc --- /dev/null +++ b/Wrapping/Python/Packaging/setup.py.in @@ -0,0 +1,107 @@ +import sys +import os + +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 = "" + +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 = "@SimpleITK_VERSION_MAJOR@" + sitkMINOR = "@SimpleITK_VERSION_MINOR@" + sitkPATCH = "@SimpleITK_VERSION_PATCH@" + sitkTWEAK = "@SimpleITK_VERSION_TWEAK@" + sitkRC = "@SimpleITK_VERSION_RC@" + sitkPOST = "@SimpleITK_VERSION_POST@" + sitkDEV = "@SimpleITK_VERSION_DEV@" + sitkHASH = "@SimpleITK_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) ) + + 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} + ) diff --git a/Wrapping/Python/Packaging/setupegg.py b/Wrapping/Python/Packaging/setupegg.py new file mode 100644 index 0000000000..05e090f934 --- /dev/null +++ b/Wrapping/Python/Packaging/setupegg.py @@ -0,0 +1,17 @@ +""" +A setup.py script to use setuptools, which gives wheel and egg goodness, etc. +""" +try: + from setuptools import setup +except ImportError: + # SimpleITK no longer provides ez_setup, but a copy may be around + # so we give it a try. It's intended that setuptools be install in + # a constructed virtualenv during the make process. + from ez_setup import use_setuptools + use_setuptools() +import os + +from setuptools import setup + +fn = os.path.dirname(os.path.realpath(__file__)) + '/setup.py' +exec(open(fn).read()) diff --git a/Wrapping/Python/dist/CMakeLists.txt b/Wrapping/Python/dist/CMakeLists.txt new file mode 100644 index 0000000000..ac404601f9 --- /dev/null +++ b/Wrapping/Python/dist/CMakeLists.txt @@ -0,0 +1,43 @@ +# +# Packaging +# +if( MITK_PYTHON_EGG OR MITK_PYTHON_WHEEL ) + if( NOT MITK_PYTHON_USE_VIRTUALENV ) + message( STATUS "Not using SimpleITK's virtualenv for distribution!\n +Using unknown versions of pip, setuptools and/or wheel packages/" ) + endif() + + set(bdist_setup "${MITK_Python_BINARY_DIR}/Packaging/setup.py") + set(bdist_commands "") + + if( MITK_PYTHON_EGG ) + set(bdist_commands "bdist_egg") + endif() + + if( MITK_PYTHON_WHEEL ) + set(bdist_commands ${bdist_commands} "bdist_wheel") + endif() + + set( MITK_PYTHON_PLAT_NAME "" CACHE STRING + "Optional value passed to setup.py with the '--plat-name' argument") + + if( NOT "${MITK_PYTHON_PLAT_NAME}" STREQUAL "" ) + set(bdist_commands ${bdist_commands} "--plat-name" "${MITK_PYTHON_PLAT_NAME}") + endif() + + message(WARNING ${VIRTUAL_PYTHON_EXECUTABLE}) + message(WARNING ${bdist_setup}) + message(WARNING ${bdist_commands}) + add_custom_target( dist.Python + ${VIRTUAL_PYTHON_EXECUTABLE} ${bdist_setup} ${bdist_commands} + WORKING_DIRECTORY ${MITK_Python_BINARY_DIR} + DEPENDS ${SWIG_MODULE_PythonMITK_REAL_NAME} + COMMENT "Creating Python binary distribution" ) + + if( MITK_PYTHON_USE_VIRTUALENV ) + add_dependencies( dist.Python PythonVirtualEnv) + endif() + add_dependencies( dist dist.Python ) +elseif() + message( STATUS "Not creating dist.Python target since SimpleITK_FORBID_DOWNLOADS is enabled" ) +endif()