[CMake] Python Extension recipe for CMake
Guilherme Balena Versiani
guibv at comunip.com.br
Mon Jan 4 12:36:46 EST 2010
Hello all,
I got stuck while integrating CMake in Ohcount project (patches not
fully approved yet, but you can see it here
http://github.com/balena/ohcount). My objective was to create a Python
Extension from a SWIG-generated source file in a multi-platform fashion.
To accomplish this, I resolved to unscramble some parts of Python
libraries ('distutils' for instance), to get the extension name of the
compiling architecture without using IF(WIN32)/ELIF(UNIX)/.../ELSE(...)
approach (the if/elif/.../else recipe needs to explicitly declare each
supported platform in your CMakeLists.txt).
I don't know what you think, but the following recipe could be of use
for someone else, and maybe included in a macro somewhere else in CMake
scripts to simplify the building of Python Extensions. Here is the code
(substitute [package], [path/to/package].i, [dependencies], [link
libraries] and [target] accordingly to your project):
---------
# Set up Python binding
IF(ENABLE_PYTHON)
MESSAGE(STATUS "Enabled Python binding")
# Find Python executable
FIND_PACKAGE(PythonLibs REQUIRED)
FIND_PACKAGE(PythonInterp REQUIRED)
IF(NOT PYTHONLIBS_FOUND OR NOT PYTHON_EXECUTABLE)
MESSAGE(SEND_ERROR "You need Python to build Python binding")
ENDIF(NOT PYTHONLIBS_FOUND OR NOT PYTHON_EXECUTABLE)
FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/python/_*[package]*_)
FILE(GLOB _python_files "python/*.py")
FILE(COPY ${_python_files} DESTINATION
${CMAKE_BINARY_DIR}/python/_*[package]*_)
# SWIG execution ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_BINARY_DIR}/python/_*[package]*__wrap.c
${CMAKE_BINARY_DIR}/python/_*[package]*_/_*[package]*_.py
COMMAND ${SWIG_EXECUTABLE} -python
-o ${CMAKE_BINARY_DIR}/python/_*_*[package]*_*__wrap.c
-outdir ${CMAKE_BINARY_DIR}/python/_*_*[package]*_*_
${CMAKE_SOURCE_DIR}/_*[path/to/package]*_.i
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/python/_*_*[package]*_*_
DEPENDS ${CMAKE_SOURCE_DIR}/_*_*[path/to/package]*_*_.i
)
# Substitute the [...] below for your include dirs
INCLUDE_DIRECTORIES(_*[...]*_ ${PYTHON_INCLUDE_DIRS})
ADD_LIBRARY(_*[target]*_ SHARED
${CMAKE_BINARY_DIR}/python/_*_*[package]*_*__wrap.c)
ADD_DEPENDENCIES(_*_*[target]*_*_ _*[dependencies]*_)
TARGET_LINK_LIBRARIES(_*_*[target]*_*_ ${PYTHON_LIBRARIES}
_*[link_libraries]*_)
# The code below prints the Python extension for the current system
FILE(WRITE "${CMAKE_BINARY_DIR}/getmodsuffix.py"
"import imp
for s in imp.get_suffixes():
if s[1] == 'rb' and s[0][0] == '.':
break
print s[0],
"
) # Now execute it and remove any newlines from output
EXECUTE_PROCESS(
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/getmodsuffix.py
OUTPUT_VARIABLE _modsuffix
)
STRING(REPLACE "\n" "" _modsuffix ${_modsuffix}) # Setup specific
properties of the Python target
SET_TARGET_PROPERTIES(_*_*[target]*_*_
PROPERTIES
OUTPUT_NAME __*_*_*_*[package]*_*_*_*_ PREFIX "" # There is
no prefix even on UNIXes
SUFFIX "${_modsuffix}" # The extension got from Python libraries
LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/python/_*_*_*_*[package]*_*_*_*_
RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/python/_*_*_*_*[package]*_*_*_*_
) # You should set ADDITIONAL_MAKE_CLEAN_FILES using this variable #
at the end of the CMakeLists.txt file
LIST(APPEND _additional_clean_files
"${CMAKE_BINARY_DIR}/python/_*_*_*_*_*_*_*_*[package]*_*_*_*_*_*_*_*__wrap.c"
# SWIG C wrap file
"${CMAKE_BINARY_DIR}/python/_*_*_*_*_*_*_*_*[package]*_*_*_*_*_*_*_*_/_*_*_*_*_*_*_*_*[package]*_*_*_*_*_*_*_*_.py"
# SWIG python wrapper
)
# If you want, add some unit tests for the generated module this way:
ADD_TEST(_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*[package]*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_PythonTest
${CMAKE_COMMAND} -E chdir
"${CMAKE_SOURCE_DIR}/test/unit/python"
"${PYTHON_EXECUTABLE}" "python_test.py"
)
SET_TESTS_PROPERTIES(PythonTest PROPERTIES
ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python"
)
ENDIF(ENABLE_PYTHON)
---------
Best regards,
--
Guilherme Balena Versiani.
More information about the CMake
mailing list