ceph/cmake/modules/Distutils.cmake
Kefu Chai ea4ae6d2f1 cmake/modules: use exact version of python3 when finding cython
* CMakeLists.txt:
    always pass "EXACT" to find_package(Python3).
    because per cmake document, "EXACT" only takes effect when
    <Package>_FIND_VERSION_COUNT is greater than 1, where <Package>
    is "Python3". see also cmake/modules/FindPython/Support.cmake
* cmake/modules/AddCephTest.cmake:
    drop redundant find_package(Python3) calls. since Python3 is
    a mandatory requirement for building Ceph, we only need a
    single call of find_package(Python3..) in the top of the source
    tree. the only possible case to repeat it is to ensure that we
    have the correct version of Python3 used in following CMake
    script. but there is no need to repeat it if we just want to
    ensure that we have a python3 interpretor in place.
* cmake/modules/Distutils.cmake:
    always pass "EXACT" to find_package(Python3).
    we should always pass EXACT to find_package() when finding python3,
    this is a follow-up of e2babdfae8

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
2022-04-21 06:52:18 +08:00

162 lines
6.7 KiB
CMake

include(CMakeParseArguments)
# ensure that we are using the exact python version specified by
# 'WITH_PYTHON3', in case some included 3rd party libraries call
# 'find_package(Python3 ...) without specifying the exact version number. if
# the building host happens to have a higher version of python3, that version
# would be picked up instead by find_package(Python3). and that is not want we
# expect.
find_package(Python3 ${WITH_PYTHON3} EXACT
QUIET
REQUIRED
COMPONENTS Interpreter)
function(distutils_install_module name)
set(py_srcs setup.py README.rst requirements.txt test-requirements.txt bin ${name})
foreach(src ${py_srcs})
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${src})
list(APPEND py_clone ${CMAKE_CURRENT_BINARY_DIR}/${src})
add_custom_command(
OUTPUT ${src}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${src}
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${src})
endif()
endforeach()
if(NOT TARGET ${name}-clone)
add_custom_target(${name}-clone ALL
DEPENDS ${py_clone})
endif()
cmake_parse_arguments(DU "" "INSTALL_SCRIPT" "" ${ARGN})
install(CODE "
set(options --prefix=${CMAKE_INSTALL_PREFIX})
if(DEFINED ENV{DESTDIR})
if(EXISTS /etc/debian_version)
list(APPEND options --install-layout=deb)
endif()
list(APPEND options
--root=\$ENV{DESTDIR}
--single-version-externally-managed)
endif()
if(NOT \"${DU_INSTALL_SCRIPT}\" STREQUAL \"\")
list(APPEND options --install-script=${DU_INSTALL_SCRIPT})
endif()
execute_process(
COMMAND ${Python3_EXECUTABLE}
setup.py install \${options}
WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")")
endfunction(distutils_install_module)
function(distutils_add_cython_module target name src)
get_property(compiler_launcher GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
get_property(link_launcher GLOBAL PROPERTY RULE_LAUNCH_LINK)
# When using ccache, CMAKE_C_COMPILER is ccache executable absolute path
# and the actual C compiler is CMAKE_C_COMPILER_ARG1.
# However with a naive
# set(PY_CC ${compiler_launcher} ${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1})
# distutils tries to execve something like "/usr/bin/cmake gcc" and fails.
# Removing the leading whitespace from CMAKE_C_COMPILER_ARG1 helps to avoid
# the failure.
string(STRIP "${CMAKE_C_COMPILER_ARG1}" c_compiler_arg1)
string(STRIP "${CMAKE_CXX_COMPILER_ARG1}" cxx_compiler_arg1)
# Note: no quotes, otherwise distutils will execute "/usr/bin/ccache gcc"
# CMake's implicit conversion between strings and lists is wonderful, isn't it?
set(PY_CFLAGS ${COMPILE_OPTIONS})
cmake_parse_arguments(DU "DISABLE_VTA" "" "" ${ARGN})
if(DU_DISABLE_VTA AND HAS_VTA)
list(APPEND PY_CFLAGS -fno-var-tracking-assignments)
endif()
list(APPEND PY_CPPFLAGS -iquote${CMAKE_SOURCE_DIR}/src/include -w)
# This little bit of magic wipes out __Pyx_check_single_interpreter()
# Note: this is reproduced in distutils_install_cython_module
list(APPEND PY_CPPFLAGS -D'void0=dead_function\(void\)')
list(APPEND PY_CPPFLAGS -D'__Pyx_check_single_interpreter\(ARG\)=ARG \#\# 0')
set(PY_CC ${compiler_launcher} ${CMAKE_C_COMPILER} ${c_compiler_arg1})
set(PY_CXX ${compiler_launcher} ${CMAKE_CXX_COMPILER} ${cxx_compiler_arg1})
set(PY_LDSHARED ${link_launcher} ${CMAKE_C_COMPILER} ${c_compiler_arg1} "-shared")
execute_process(COMMAND "${Python3_EXECUTABLE}" -c
"import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"
RESULT_VARIABLE result
OUTPUT_VARIABLE ext_suffix
ERROR_VARIABLE error
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Unable to tell python extension's suffix: ${error}")
endif()
set(output_dir "${CYTHON_MODULE_DIR}/lib.3")
set(setup_py ${CMAKE_CURRENT_SOURCE_DIR}/setup.py)
if(DEFINED ENV{VERBOSE})
set(maybe_verbose --verbose)
endif()
add_custom_command(
OUTPUT ${output_dir}/${name}${ext_suffix}
COMMAND
env
CC="${PY_CC}"
CFLAGS="${PY_CFLAGS}"
CPPFLAGS="${PY_CPPFLAGS}"
CXX="${PY_CXX}"
LDSHARED="${PY_LDSHARED}"
OPT=\"-DNDEBUG -g -fwrapv -O2 -w\"
LDFLAGS=-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
CYTHON_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}
CEPH_LIBDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
${Python3_EXECUTABLE} ${setup_py}
build ${maybe_verbose} --build-base ${CYTHON_MODULE_DIR}
--build-platlib ${output_dir}
MAIN_DEPENDENCY ${src}
DEPENDS ${setup_py}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(${target} ALL
DEPENDS ${output_dir}/${name}${ext_suffix})
endfunction(distutils_add_cython_module)
function(distutils_install_cython_module name)
get_property(compiler_launcher GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
get_property(link_launcher GLOBAL PROPERTY RULE_LAUNCH_LINK)
set(PY_CC "${compiler_launcher} ${CMAKE_C_COMPILER}")
set(PY_LDSHARED "${link_launcher} ${CMAKE_C_COMPILER} -shared")
cmake_parse_arguments(DU "DISABLE_VTA" "" "" ${ARGN})
if(DU_DISABLE_VTA AND HAS_VTA)
set(CFLAG_DISABLE_VTA -fno-var-tracking-assignments)
endif()
if(DEFINED ENV{VERBOSE})
set(maybe_verbose --verbose)
endif()
install(CODE "
set(ENV{CC} \"${PY_CC}\")
set(ENV{LDSHARED} \"${PY_LDSHARED}\")
set(ENV{CPPFLAGS} \"-iquote${CMAKE_SOURCE_DIR}/src/include
-D'void0=dead_function\(void\)' \
-D'__Pyx_check_single_interpreter\(ARG\)=ARG \#\# 0' \
${CFLAG_DISABLE_VTA}\")
set(ENV{LDFLAGS} \"-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY}\")
set(ENV{CYTHON_BUILD_DIR} \"${CMAKE_CURRENT_BINARY_DIR}\")
set(ENV{CEPH_LIBDIR} \"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}\")
set(options --prefix=${CMAKE_INSTALL_PREFIX})
if(DEFINED ENV{DESTDIR})
if(EXISTS /etc/debian_version)
list(APPEND options --install-layout=deb)
endif()
list(APPEND options --root=\$ENV{DESTDIR})
else()
list(APPEND options --root=/)
endif()
execute_process(
COMMAND
${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/setup.py
build ${maybe_verbose} --build-base ${CYTHON_MODULE_DIR}
--build-platlib ${CYTHON_MODULE_DIR}/lib.3
build_ext --cython-c-in-temp --build-temp ${CMAKE_CURRENT_BINARY_DIR} --cython-include-dirs ${PROJECT_SOURCE_DIR}/src/pybind/rados
install \${options} --single-version-externally-managed --record /dev/null
egg_info --egg-base ${CMAKE_CURRENT_BINARY_DIR}
${maybe_verbose}
WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"
RESULT_VARIABLE install_res)
if(NOT \"\${install_res}\" STREQUAL 0)
message(FATAL_ERROR \"Failed to build and install ${name} python module\")
endif()
")
endfunction(distutils_install_cython_module)