Permalink
Browse files

Add generation of PythonConfig.cmake

For both install and build tree, the files:

  PythonConfig.cmake
  PythonConfigVersion.cmake
  PythonTargets.cmake

will be configured into:

   <prefix>/share/<libpython>/

It means the following option have to be passed when build a project
depending on python:

   -DPython_DIR:PATH=/path/to/<prefix>/share/<libpython>/

Since CMake 2.8.8, there is convenient module named "CMakePackageConfigHelpers"
that provided the helper macros "configure_package_config_file" and
"write_basic_package_version_file" allowing to easily configure
relocatable packages.
See http://www.cmake.org/cmake/help/v2.8.8/cmake.html#module:CMakePackageConfigHelpers

To avoid upgrading the minimum requirement version of CMake, the
generation of 'PythonConfig.cmake' is done only if possible. To display
message with the macro are not available, a convenient
macro named "check_cmake_command_exists" has also been added.

To allow find_package to work with both a build and install tree, the macro
"configure_package_config_file" is called twice with different value for
the variable:

  CONFIG_DIR_CONFIG
  INCLUDE_DIR_CONFIG
  PYTHON_CONFIG_CODE

The config variables (except PYTHON_CONFIG_CODE) are set using either
the *_BUILD_* or the *_INSTALL_* variables.

The PYTHON_CONFIG_CODE variable allows to inject some CMake code
in the configured PythonConfig.cmake files.

More specifically, for the case of the build tree, not all public headers
are available within INCLUDE_BUILD_DIR. For that reason, using PYTHON_CONFIG_CODE
the variable PYTHON_INCLUDE_DIR is updated with PYCONFIG_BUILD_DIR.

Finally, the PythonConfigVersion file is automatically generated with the
help of "write_basic_package_version_file" and is identical for both the
build and the install tree.

On Linux, I was able to successfully build a simple python module against
both trees. See corresponding CMakeLists.txt was:

cmake_minimum_required(VERSION 2.8.10)
project(example)

find_package(Python REQUIRED CONFIG)
include_directories(${PYTHON_INCLUDE_DIRS})

add_library(example MODULE examplemodule.cxx)
target_link_libraries(example ${PYTHON_LIBRARIES})
set_target_properties(example PROPERTIES PREFIX "")

Questions:

  - Does it make sens to configure the file in <prefix>/share/<libpython>
also for the build tree?  This has the advantages of keeping the build
directory uncluttered but it "less" conventional.

Todo:

  - Teach PythonConfig how to understand COMPONENTS. The list of COMPONENTS
that could be specified are the different python extension.

  - Provide a backward compatible interface for FindPythonLibs.cmake
and FindPythonInterp.cmake. It means existing code would have to simply
append a NO_MODULE or CONFIG option to their existing find_package
statement.

  - Configuration of pkg-config files
  • Loading branch information...
1 parent cf03cdc commit 3f504d8be5b41086f615494517ddd2cf66f4d365 @jcfr jcfr committed Mar 3, 2013
Showing with 110 additions and 0 deletions.
  1. +47 −0 CMakeLists.txt
  2. +13 −0 cmake/CheckCMakeCommandExists.cmake
  3. +5 −0 cmake/ConfigureChecks.cmake
  4. +45 −0 cmake/PythonConfig.cmake.in
View
@@ -222,7 +222,54 @@ if(UNIX)
RENAME Makefile)
endif(UNIX)
+
+if(HAVE_CONFIGURE_PACKAGE_CONFIG_FILE AND HAVE_WRITE_BASIC_PACKAGE_VERSION_FILE)
+
+# Configure 'PythonConfig.cmake' for a build tree
+set(CONFIG_DIR_CONFIG ${CONFIG_BUILD_DIR})
+set(INCLUDE_DIR_CONFIG ${INCLUDE_BUILD_DIR})
+set(PYTHON_CONFIG_CODE "####### Expanded from \@PYTHON_CONFIG_CODE\@ #######\n")
+set(PYTHON_CONFIG_CODE "${PYTHON_CONFIG_CODE}list(APPEND PYTHON_INCLUDE_DIR \"${PYCONFIG_BUILD_DIR}\")\n")
+set(PYTHON_CONFIG_CODE "${PYTHON_CONFIG_CODE}##################################################")
+set(python_config ${CONFIG_BUILD_DIR}/PythonConfig.cmake)
+configure_package_config_file(
+ cmake/PythonConfig.cmake.in
+ ${python_config}
+ INSTALL_DESTINATION ${CMAKE_BINARY_DIR}
+ PATH_VARS CONFIG_DIR_CONFIG INCLUDE_DIR_CONFIG
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
+)
+
+# Configure 'PythonConfig.cmake' for an install tree
+set(CONFIG_DIR_CONFIG ${CONFIG_INSTALL_DIR})
+set(INCLUDE_DIR_CONFIG ${INCLUDE_INSTALL_DIR})
+set(PYTHON_CONFIG_CODE "")
+set(python_install_config ${CMAKE_BINARY_DIR}/CMakeFiles/PythonConfig.cmake)
+configure_package_config_file(
+ cmake/PythonConfig.cmake.in
+ ${python_install_config}
+ INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/${CONFIG_INSTALL_DIR}
+ PATH_VARS CONFIG_DIR_CONFIG INCLUDE_DIR_CONFIG
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
+)
+
+# Configure 'PythonTargets.cmake' and 'PythonConfigVersion.cmake
get_property(PYTHON_TARGETS GLOBAL PROPERTY PYTHON_TARGETS)
export(TARGETS ${PYTHON_TARGETS} APPEND FILE ${CONFIG_BUILD_DIR}/PythonTargets.cmake)
+set(python_config_version ${CONFIG_BUILD_DIR}/PythonConfigVersion.cmake)
+write_basic_package_version_file(
+ ${python_config_version}
+ VERSION ${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}.${PY_VERSION_PATCH}
+ COMPATIBILITY SameMajorVersion
+)
+
+# Install 'PythonTargets.cmake', 'PythonConfig.cmake' and 'PythonConfigVersion.cmake
install(EXPORT PythonTargets FILE PythonTargets.cmake DESTINATION ${CONFIG_INSTALL_DIR})
+
+install(
+ FILES ${python_install_config} ${python_config_version}
+ DESTINATION ${CONFIG_INSTALL_DIR} COMPONENT Development
+)
+
+endif(HAVE_CONFIGURE_PACKAGE_CONFIG_FILE AND HAVE_WRITE_BASIC_PACKAGE_VERSION_FILE)
@@ -0,0 +1,13 @@
+
+macro(check_cmake_command_exists commandname)
+ message(STATUS "Looking for CMake command ${commandname}")
+ string(TOUPPER ${commandname} commandname_upper)
+ if(COMMAND ${commandname})
+ set(HAVE_${commandname_upper} TRUE)
+ message(STATUS "Looking for CMake command ${commandname} - found")
+ else()
+ set(HAVE_${commandname_upper} FALSE)
+ message(STATUS "Looking for CMake command ${commandname} - not found")
+ endif()
+endmacro()
+
@@ -8,9 +8,14 @@ include(CheckFunctionExists)
include(CheckLibraryExists)
include(CheckSymbolExists)
include(CheckVariableExists)
+include(cmake/CheckCMakeCommandExists.cmake)
include(cmake/CheckTypeExists.cmake)
include(cmake/PlatformTest.cmake)
+include(CMakePackageConfigHelpers OPTIONAL)
+check_cmake_command_exists("configure_package_config_file")
+check_cmake_command_exists("write_basic_package_version_file")
+
if(WIN32)
# From PC/pyconfig.h:
# This is a manually maintained version used for the Watcom,
@@ -0,0 +1,45 @@
+# PYTHON_USE_STATIC_LIB - Set to ON to force the use of the static
+# library. Default is OFF.
+
+@PACKAGE_INIT@
+
+set(PYTHON_BUILD_SHARED "@BUILD_SHARED@")
+set(PYTHON_BUILD_STATIC "@BUILD_STATIC@")
+
+set_and_check(PYTHON_CONFIG_DIR "@PACKAGE_CONFIG_DIR_CONFIG@")
+set_and_check(PYTHON_INCLUDE_DIR "@PACKAGE_INCLUDE_DIR_CONFIG@")
+set_and_check(PYTHON_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/PythonTargets.cmake")
+
+@PYTHON_CONFIG_CODE@
+
+if(NOT PYTHON_TARGETS_IMPORTED)
+ set(PYTHON_TARGETS_IMPORTED 1)
+ include(${PYTHON_TARGETS})
+endif()
+
+if(TARGET libpython-shared)
+ set(PYTHON_LIBRARY_SHARED libpython-shared)
+endif()
+if(TARGET libpython-static)
+ set(PYTHON_LIBRARY_STATIC libpython-static)
+endif()
+
+if(NOT Python_USE_STATIC_LIB)
+ if(PYTHON_LIBRARY_SHARED)
+ set(PYTHON_LIBRARIES ${PYTHON_LIBRARY_SHARED})
+ elseif(PYTHON_LIBRARY_STATIC)
+ set(PYTHON_LIBRARIES ${PYTHON_LIBRARY_STATIC})
+ endif()
+else()
+ if(PYTHON_LIBRARY_STATIC)
+ set(PYTHON_LIBRARIES ${PYTHON_LIBRARY_STATIC})
+ else()
+ set(PYTHON_LIBRARIES ${PYTHON_LIBRARY_SHARED})
+ endif()
+endif()
+
+if(NOT Python_FIND_QUIETLY)
+ message(STATUS "PYTHON_LIBRARIES set to ${PYTHON_LIBRARIES}")
+endif()
+
+set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR})

0 comments on commit 3f504d8

Please sign in to comment.