Skip to content

Commit

Permalink
ENH: When using cmake > 3.12 use FindPython3 module
Browse files Browse the repository at this point in the history
The FindPython3 module is more robust for ensuring that python 3 or greater is found.

The FindPythonInterp and FindPythonLib modules are deprecated
in cmake greater than 3.12.0

The GoogleTest framework uses the deprecated FindPythonInterp, so this
patch uses the FindPython3 module, and then uses that more robust
information to set the FindPythonInterp cmake variables so that
wrapping, google tests, documentation generation, etc.. all use the
same found version of Python 3.
  • Loading branch information
hjmjohnson committed Jan 6, 2020
1 parent f23c5cf commit 75fbf66
Show file tree
Hide file tree
Showing 15 changed files with 120 additions and 40 deletions.
22 changes: 19 additions & 3 deletions CMake/ITKModuleDoxygen.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,23 @@
# python is needed to verify the presence of the module name in the doxygen header
# Don't require it to not force the developers to install python to be able to build
# ITK. The tests will simply not be run if python is not available.
find_package(PythonInterp)
# Prefer to use more robust FindPython3 module if greater than cmake 3.12.0
if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "3.12.0")
# Use of PythonInterp and PythonLibs is dprecated since cmake version 3.12.0

# configure python (find PythonInterp first, as of cmake 3.1)
find_package(PythonInterp)
# Check for supported python versions
if(PYTHON_VERSION_STRING VERSION_LESS 3.5)
message(FATAL_ERROR "Python versions less than 3.5 are not supported. Python version: \"${PYTHON_VERSION_STRING}\".")
endif()

## For forward compatibility with cmake 3.12.0 or greater
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
else()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
endif()


macro( itk_module_doxygen _name )

Expand Down Expand Up @@ -43,8 +59,8 @@ macro( itk_module_doxygen _name )
endif()

if(NOT ${_name}_THIRD_PARTY AND EXISTS ${${_name}_SOURCE_DIR}/include)
if(PYTHON_EXECUTABLE AND BUILD_TESTING AND NOT DISABLE_MODULE_TESTS)
itk_add_test(NAME ${_name}InDoxygenGroup COMMAND ${PYTHON_EXECUTABLE} "${ITK_CMAKE_DIR}/../Utilities/Doxygen/mcdoc.py" check ${_name} ${${_name}_SOURCE_DIR}/include)
if(Python3_EXECUTABLE AND BUILD_TESTING AND NOT DISABLE_MODULE_TESTS)
itk_add_test(NAME ${_name}InDoxygenGroup COMMAND ${Python3_EXECUTABLE} "${ITK_CMAKE_DIR}/../Utilities/Doxygen/mcdoc.py" check ${_name} ${${_name}_SOURCE_DIR}/include)
itk_memcheck_ignore(${_name}InDoxygenGroup)
endif()
endif()
Expand Down
21 changes: 18 additions & 3 deletions CMake/ITKModuleHeaderTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,22 @@

# This does not force the developer to install python to be able to build ITK.
# The tests will simply not be run if python is unavailable.
find_package(PythonInterp)
# Prefer to use more robust FindPython3 module if greater than cmake 3.12.0
if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "3.12.0")
# Use of PythonInterp and PythonLibs is dprecated since cmake version 3.12.0

# configure python (find PythonInterp first, as of cmake 3.1)
find_package(PythonInterp)
# Check for supported python versions
if(PYTHON_VERSION_STRING VERSION_LESS 3.5)
message(FATAL_ERROR "Python versions less than 3.5 are not supported. Python version: \"${PYTHON_VERSION_STRING}\".")
endif()

## For forward compatibility with cmake 3.12.0 or greater
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
else()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
endif()

# Improve performance of MSVC GUI, by reducing number of header tests.
set( MAXIMUM_NUMBER_OF_HEADERS_default 35 )
Expand All @@ -29,7 +44,7 @@ endif()
macro( itk_module_headertest _name )
if( NOT ${_name}_THIRD_PARTY
AND EXISTS ${${_name}_SOURCE_DIR}/include
AND PYTHON_EXECUTABLE
AND Python3_EXECUTABLE
AND NOT (${_name} STREQUAL ITKTestKernel)
AND NOT (CMAKE_GENERATOR MATCHES "^Visual Studio 10.*"))

Expand Down Expand Up @@ -81,7 +96,7 @@ macro( itk_module_headertest _name )
get_filename_component( _test_name ${_header_test_src} NAME_WE )
add_custom_command(
OUTPUT ${_header_test_src}
COMMAND ${PYTHON_EXECUTABLE} ${ITK_CMAKE_DIR}/../Utilities/Maintenance/BuildHeaderTest.py
COMMAND ${Python3_EXECUTABLE} ${ITK_CMAKE_DIR}/../Utilities/Maintenance/BuildHeaderTest.py
${_name}
${${_name}_SOURCE_DIR}
${${_name}_BINARY_DIR}
Expand Down
2 changes: 1 addition & 1 deletion CMake/ITKModuleTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ function(itk_python_add_test)
set(multiValueArgs TEST_DRIVER_ARGS COMMAND)
cmake_parse_arguments(PYTHON_ADD_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

set(command "${PYTHON_EXECUTABLE}")
set(command "${Python3_EXECUTABLE}")
# add extra command which may be needed on some systems
if(CMAKE_OSX_ARCHITECTURES)
list(GET CMAKE_OSX_ARCHITECTURES 0 test_arch)
Expand Down
47 changes: 47 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${ITK_REQUIRED_LINK_
if(NOT CMAKE_POSITION_INDEPENDENT_CODE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# Because GoogleTest uses deprecated FindPythonInterp
set(Python_ADDITIONAL_VERSIONS 3.9 3.8 3.7 3.6 3.5)
# Because GoogleTest sets CMAKE_DEBUG_POSTFIX CMake CACHE variable to "d" when it is
# built in debug, we preemptively set it to an empty string to avoid having a postfix
# added to the ITK library names.
Expand Down Expand Up @@ -512,6 +514,51 @@ endif()

install(FILES "LICENSE" "NOTICE" "README.md" DESTINATION ${ITK_INSTALL_DOC_DIR} COMPONENT Runtime)

if(BUILD_TESTNG OR ITK_WRAP_PYTHON)
# Python3 is required if testing (for google tests) or wrapping for python is requested.
# Because GoogleTest uses deprecated FindPythonInterp
# Prefer to use more robust FindPython3 module if greater than cmake 3.12.0
if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "3.12.0")
# Use of PythonInterp and PythonLibs is dprecated since cmake version 3.12.0

# configure python (find PythonInterp first, as of cmake 3.1)
find_package(PythonInterp REQUIRED)
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})

if(ITK_WRAP_PYTHON)
find_package(PythonLibs REQUIRED)

# check for version mismatch.
if(PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND
AND NOT(PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING))
message(WARNING "Python executable (\"${PYTHON_VERSION_STRING}\") and library (\"${PYTHONLIBS_VERSION_STRING}\") version mismatch.")
endif()
# Check for supported python versions
if(PYTHON_VERSION_STRING VERSION_LESS 3.5)
message(FATAL_ERROR "Python versions less than 3.5 are not supported. Python version: \"${PYTHON_VERSION_STRING}\".")
endif()

## For forward compatibility with cmake 3.12.0 or greater
set(Python3_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
endif()
else()
if(ITK_WRAP_PYTHON)
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)

else()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
endif()
# For GoogleTest to force use of same python interpreter as found by the Python3 package
# as is looked for by the FindPythonInterp from the incluced GoogleTest package.
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND})
set(PYTHON_VERSION ${Python3_VERSION})
set(PYTHON_VERSION_MAJOR ${Python3_VERSION_MAJOR})
set(PYTHON_VERSION_MINOR ${Python3_VERSION_MINOR})
set(PYTHON_VERSION_PATCH ${Python3_VERSION_PATCH})
endif()
endif()

if(BUILD_TESTING)
# If building the testing, write the test costs (i.e. time to run)
# analysis to disk to more easily review long-running test times
Expand Down
2 changes: 1 addition & 1 deletion Documentation/Maintenance/Release.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ virtualenv itk-venv
git clone https://github.com/InsightSoftwareConsortium/ITKExamples
mkdir ITKExamples-build
cd ITKExamples-build
cmake -DITK_DIR=/path/to/ITK-build -DPYTHON_EXECUTABLE=../itk-venv/bin/python ../ITKExamples
cmake -DITK_DIR=/path/to/ITK-build -DPython3_ROOT_DIR=../itk-venv/bin/python -DPython3_FIND_VIRTUALENV=ONLY ../ITKExamples
ctest -R Python
```

Expand Down
2 changes: 1 addition & 1 deletion Modules/Bridge/NumPy/wrapping/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import numpy"
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import numpy"
RESULT_VARIABLE _have_numpy_return_code
OUTPUT_QUIET
ERROR_QUIET
Expand Down
2 changes: 1 addition & 1 deletion Modules/Core/Common/wrapping/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ itk_python_add_test(NAME itkDirectoryPythonTest COMMAND itkDirectoryTest.py)
itk_python_expression_add_test(NAME itkObjectPythonTest EXPRESSION "itkObject = itk.Object.New()")
itk_python_add_test(NAME itkIndexOffsetPythonTest COMMAND itkIndexOffsetTest.py)
itk_python_add_test(NAME itkImageDuplicatorPythonTest COMMAND itkImageDuplicatorTest.py)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import numpy"
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import numpy"
RESULT_VARIABLE _have_numpy_return_code
OUTPUT_QUIET
ERROR_QUIET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ if(ITK_WRAP_unsigned_char AND wrap_2_index GREATER -1)
endif()
itk_python_expression_add_test(NAME itkSymmetricEigenAnalysisImageFilterPythonTest
EXPRESSION "filt = itk.SymmetricEigenAnalysisImageFilter.New()")
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import numpy"
execute_process(COMMAND ${Python3_EXECUTABLE} -c "import numpy"
RESULT_VARIABLE _have_numpy_return_code
OUTPUT_QUIET
ERROR_QUIET
Expand Down
4 changes: 3 additions & 1 deletion Testing/ContinuousIntegration/AzurePipelinesLinuxPython.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ jobs:
- bash: |
python_executable=`which python3`
python_root_dir=$(dirname $(dirname ${python_executable}))
cat > dashboard.cmake << EOF
set(CTEST_BUILD_CONFIGURATION "MinSizeRel")
set(CTEST_CMAKE_GENERATOR "Ninja")
set(BUILD_NAME_SUFFIX "-Python")
set(dashboard_cache "
PYTHON_EXECUTABLE:FILEPATH=${python_executable}
Python3_ROOT_DIR:PATH=${python_root_dir}
Python3_EXECUTABLE:FILEPATH=${python_executable}
DISABLE_MODULE_TESTS:BOOL=ON
BUILD_SHARED_LIBS:BOOL=OFF
BUILD_EXAMPLES:BOOL=OFF
Expand Down
4 changes: 3 additions & 1 deletion Testing/ContinuousIntegration/AzurePipelinesMacOSPython.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ jobs:
- bash: |
python_executable=`which python3`
python_root_dir=$(dirname $(dirname ${python_executable}))
cat > dashboard.cmake << EOF
set(CTEST_BUILD_CONFIGURATION "Release")
set(CTEST_CMAKE_GENERATOR "Ninja")
set(BUILD_NAME_SUFFIX "-Python")
set(dashboard_cache "
PYTHON_EXECUTABLE:FILEPATH=${python_executable}
Python3_ROOT_DIR:PATH=${python_root_dir}
Python3_EXECUTABLE:FILEPATH=${python_executable}
DISABLE_MODULE_TESTS:BOOL=ON
BUILD_SHARED_LIBS:BOOL=OFF
BUILD_EXAMPLES:BOOL=OFF
Expand Down
2 changes: 1 addition & 1 deletion Wrapping/Generators/Doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ macro(itk_end_wrap_submodule_DOC)
set(swig_doc_interface_file ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/${WRAPPER_MODULE_NAME}_doc.i)
add_custom_command(
OUTPUT ${swig_doc_interface_file}
COMMAND ${PYTHON_EXECUTABLE} ${itk_doxy2swig_py} ${doxy2swig_config_file} ${swig_doc_interface_file}
COMMAND ${Python3_EXECUTABLE} ${itk_doxy2swig_py} ${doxy2swig_config_file} ${swig_doc_interface_file}
#DEPENDS ${ITK_WRAP_DOC_DOXYGEN_XML_FILES} ${doxy2swig_config_file} ${itk_doxy2swig_py}
DEPENDS ${WRAPPER_LIBRARY_NAME}Doxygen ${doxy2swig_config_file} ${itk_doxy2swig_py}
# COMMENT "-- Wrapping library ${WRAPPER_MODULE_NAME}: Generating swig interface for inline documentation."
Expand Down
1 change: 0 additions & 1 deletion Wrapping/Generators/Perl/ConfigureWrapping.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
find_package(PerlLibs)
find_package(Perl)
# mark_as_advanced(PYTHON_EXECUTABLE)

include_directories(${PERL_INCLUDE_PATH})
23 changes: 4 additions & 19 deletions Wrapping/Generators/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
###############################################################################
# configure python (find PythonInterp first, as of cmake 3.1)
find_package(PythonInterp)
find_package(PythonLibs)

# Check for supported python versions
if(PYTHON_VERSION_STRING VERSION_LESS 3.5)
message(WARNING "Python versions less than 3.5 are not supported. Python version: \"${PYTHON_VERSION_STRING}\".")
endif()

# check for version mismatch.
if(PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND
AND NOT(PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING))
message(WARNING "Python executable (\"${PYTHON_VERSION_STRING}\") and library (\"${PYTHONLIBS_VERSION_STRING}\") version mismatch.")
endif()

mark_as_advanced(PYTHON_EXECUTABLE)
include_directories("${PYTHON_INCLUDE_DIRS}")
include_directories("${Python3_INCLUDE_DIRS}")

include_directories("${CMAKE_CURRENT_SOURCE_DIR}")

Expand All @@ -36,15 +21,15 @@ file(MAKE_DIRECTORY ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/python)

###############################################################################
# Configure Python wrapping installation
if(PYTHON_EXECUTABLE AND NOT PY_SITE_PACKAGES_PATH)
if(Python3_EXECUTABLE AND NOT PY_SITE_PACKAGES_PATH)
set(python_check "from __future__ import print_function\ntry:\n import distutils.sysconfig\n print(distutils.sysconfig.get_python_lib(plat_specific=1, prefix=''))\nexcept:\n pass")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/detect_site_package_path.py ${python_check})
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/detect_site_package_path.py"
execute_process(COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/detect_site_package_path.py"
OUTPUT_VARIABLE py_spp
ERROR_VARIABLE py_spp
)

execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "from __future__ import print_function\nimport sys\nprint(sys.prefix)"
execute_process(COMMAND "${Python3_EXECUTABLE}" -c "from __future__ import print_function\nimport sys\nprint(sys.prefix)"
OUTPUT_VARIABLE py_prefix
ERROR_VARIABLE py_prefix
OUTPUT_STRIP_TRAILING_WHITESPACE
Expand Down
4 changes: 2 additions & 2 deletions Wrapping/Generators/Python/Tests/pythonTestDriver.py.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!@PYTHON_EXECUTABLE@
#!@Python3_EXECUTABLE@

# set environment variables

Expand Down Expand Up @@ -57,7 +57,7 @@ if len(args) < 1:

# call the program, and exit if it fail

command = ["@PYTHON_EXECUTABLE@"] + args
command = ["@Python3_EXECUTABLE@"] + args
if options.verbose:
print(sys.stderr, "+", " ".join(command))
returnValue = subprocess.call( command )
Expand Down
22 changes: 18 additions & 4 deletions Wrapping/Generators/SwigInterface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,23 @@ if("${CMAKE_BINARY_DIR}" MATCHES "^.* .*$")
message(FATAL_ERROR "Swig and PCRE do not support paths with space characters. Please change build directory name.")
endif()

###############################################################################
# Find python
find_package(PythonInterp REQUIRED)
# Prefer to use more robust FindPython3 module if greater than cmake 3.12.0
if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "3.12.0")
# Use of PythonInterp and PythonLibs is dprecated since cmake version 3.12.0

# configure python (find PythonInterp first, as of cmake 3.1)
find_package(PythonInterp)
# Check for supported python versions
if(PYTHON_VERSION_STRING VERSION_LESS 3.5)
message(FATAL_ERROR "Python versions less than 3.5 are not supported. Python version: \"${PYTHON_VERSION_STRING}\".")
endif()

## For forward compatibility with cmake 3.12.0 or greater
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
else()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
endif()


###############################################################################
# Build swig
Expand Down Expand Up @@ -354,7 +368,7 @@ macro(itk_end_wrap_module_swig_interface)
if(number_interface_files GREATER 0)
add_custom_command(
OUTPUT ${i_files} ${typedef_files} ${idx_files}
COMMAND ${PYTHON_EXECUTABLE} ${IGENERATOR}
COMMAND ${Python3_EXECUTABLE} ${IGENERATOR}
${mdx_opts}
${swig_libs}
-w1 -w3 -w51 -w52 -w53 -w54
Expand Down

0 comments on commit 75fbf66

Please sign in to comment.