From 9bc6dc71132d5d2335ad163b7f1367ab5f8ce5ea Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Tue, 16 Feb 2016 12:17:49 +0100 Subject: [PATCH] cmake: add python support FindCython.cmake was taken from https://github.com/thewtex/cython-cmake-example. The UseCython module works, but since it is lacking an installation target setup.py will be used instead. --- CMakeLists.txt | 60 ++++++++++++++-------------------- CMakeOptions.txt | 2 -- cmake/FindCython.cmake | 44 +++++++++++++++++++++++++ python/CMakeLists.txt | 45 ++++++++++++------------- python/install-python.cmake.in | 10 ++++++ python/setup.py.in | 1 + 6 files changed, 102 insertions(+), 60 deletions(-) create mode 100644 cmake/FindCython.cmake create mode 100644 python/install-python.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 58882726..123902a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,10 @@ HexVersion(PACKAGE_VERSION_NUM ${PROJECT_VERSION_MAJOR} ${PROJECT_VERSION_MINOR} include(GNUInstallDirs) +# For Python bindings and documentation +# (Must be called before PythonLibs for matching versions.) +find_package(PythonInterp) + # Auto-detection of features that can be toggled find_package(OpenSSL 1.0.1 QUIET) find_package(Libev 4.15 QUIET) @@ -55,8 +59,13 @@ find_package(Jansson 2.5 QUIET) set(ENABLE_HPACK_TOOLS_DEFAULT ${JANSSON_FOUND}) find_package(Libevent 2.0.8 QUIET COMPONENTS openssl) set(ENABLE_EXAMPLES_DEFAULT ${LIBEVENT_OPENSSL_FOUND}) -# XXX auto-detect python -set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF) +find_package(Cython QUIET) +find_package(PythonLibs QUIET) +if(CYTHON_FOUND AND PYTHONLIBS_FOUND) + set(ENABLE_PYTHON_BINDINGS_DEFAULT ON) +else() + set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF) +endif() find_package(LibXml2 QUIET) set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND}) @@ -68,12 +77,6 @@ set(WITH_SPDYLAY_DEFAULT ${SPDYLAY_FOUND}) include(CMakeOptions.txt) find_package(PkgConfig 0.20) -# For Python bindings and documentation -find_package(PythonInterp) -# XXX fail only when "ON" instead of "CHECK"? -if(ENABLE_PYTHON_BINDINGS) -endif() -# AM_PATH_PYTHON([2.7],, [:]) if(ENABLE_LIB_ONLY) set(ENABLE_APP OFF) @@ -82,21 +85,6 @@ if(ENABLE_LIB_ONLY) set(ENABLE_PYTHON_BINDINGS OFF) endif() -if(ENABLE_PYTHON_BINDINGS) - find_package(PythonLibs 2.7 REQUIRED) - # XXX find cython -endif() -# if [test "x$request_python_bindings" != "xno"]; then -# AX_PYTHON_DEVEL([>= '2.7']) -# fi -# -# if test "x${cython_path}" = "x"; then -# AC_CHECK_PROGS([CYTHON], [cython.py cython]) -# else -# CYTHON=${cython_path} -# AC_SUBST([CYTHON]) -# fi - # # If we're running GCC or clang define _U_ to be "__attribute__((unused))" # so we can use _U_ to flag unused function parameters and not get warnings @@ -143,6 +131,18 @@ cmake_pop_check_state() # Additional libraries required for programs under src directory. set(APP_LIBRARIES) +if(ENABLE_PYTHON_BINDINGS) + find_package(Cython REQUIRED) + find_package(PythonLibs REQUIRED) + if(NOT PYTHON_VERSION_STRING STREQUAL PYTHONLIBS_VERSION_STRING) + message(SEND_ERROR + "Python executable and library must have the same version!" + " Found Python ${PYTHON_VERSION_STRING} and" + " PythonLibs ${PYTHONLIBS_VERSION_STRING}" + ) + endif() +endif() + set(CMAKE_THREAD_PREFER_PTHREAD 1) find_package(Threads) if(CMAKE_USE_PTHREADS_INIT) @@ -311,16 +311,6 @@ else() set(HAVE_NEVERBLEED 0) endif() -# Python bindings -if(ENABLE_PYTHON_BINDINGS AND NOT CYTHON AND NOT PYTHONLIBS_FOUND) -# XXX PythonInterp and PythonLibs are looked up before, unreachable check? -# if test "x${request_python_bindings}" != "xno" && -# test "x${CYTHON}" != "x" && -# test "x${PYTHON}" != "x:" && -# test "x${have_python_dev}" = "xyes"; then - message(FATAL_ERROR "python bindings were requested (ENABLE_PYTHON_BINDINGS=1) but dependencies are not met.") -endif() - # Checks for header files. # XXX AC_HEADER_ASSERT adds --disable-assert which sets -DNDEBUG include(CheckIncludeFile) @@ -528,7 +518,6 @@ add_subdirectory(script) # XXX fix shared/static library -# XXX fix python string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type) message(STATUS "summary of build options: @@ -550,8 +539,7 @@ message(STATUS "summary of build options: Python: Python: ${PYTHON_EXECUTABLE} PYTHON_VERSION: ${PYTHON_VERSION_STRING} - pyexecdir: ${pyexecdir} - Python-dev: ${have_python_dev} + Library version:${PYTHONLIBS_VERSION_STRING} Cython: ${CYTHON_EXECUTABLE} Test: CUnit: ${HAVE_CUNIT} (LIBS='${CUNIT_LIBRARIES}') diff --git a/CMakeOptions.txt b/CMakeOptions.txt index a90b36ab..1cfde80d 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -23,7 +23,5 @@ option(WITH_SPDYLAY "Use spdylay" ${WITH_SPDYLAY_DEFAULT}) option(WITH_MRUBY "Use mruby") option(WITH_NEVERBLEED "Use neverbleed") -set(CYTHON_PATH "" CACHE PATH "Use cython in given path") -set(CYTHON "" CACHE FILEPATH "The Cython executable") # vim: ft=cmake: diff --git a/cmake/FindCython.cmake b/cmake/FindCython.cmake new file mode 100644 index 00000000..04aed1f8 --- /dev/null +++ b/cmake/FindCython.cmake @@ -0,0 +1,44 @@ +# Find the Cython compiler. +# +# This code sets the following variables: +# +# CYTHON_EXECUTABLE +# +# See also UseCython.cmake + +#============================================================================= +# Copyright 2011 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Use the Cython executable that lives next to the Python executable +# if it is a local installation. +find_package( PythonInterp ) +if( PYTHONINTERP_FOUND ) + get_filename_component( _python_path ${PYTHON_EXECUTABLE} PATH ) + find_program( CYTHON_EXECUTABLE + NAMES cython cython.bat cython3 + HINTS ${_python_path} + ) +else() + find_program( CYTHON_EXECUTABLE + NAMES cython cython.bat cython3 + ) +endif() + + +include( FindPackageHandleStandardArgs ) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( Cython REQUIRED_VARS CYTHON_EXECUTABLE ) + +mark_as_advanced( CYTHON_EXECUTABLE ) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 0a035e7c..0cfdc9b3 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,33 +1,34 @@ # EXTRA_DIST = cnghttp2.pxd nghttp2.pyx -# XXX consider https://github.com/thewtex/cython-cmake-example - if(ENABLE_PYTHON_BINDINGS) - # XXX add ALL? Will always be invoked as target is always out-of-date though. - add_custom_target(python - COMMAND ${PYTHON_EXECUTABLE} setup.py build + + add_custom_target(python ALL + COMMAND "${PYTHON_EXECUTABLE}" setup.py build + VERBATIM DEPENDS nghttp2.c ) - add_custom_target(python-install - COMMAND ${PYTHON_EXECUTABLE} setup.py install --prefix=${DESTDIR}${CMAKE_INSTALL_PREFIX} - ) + configure_file(install-python.cmake.in install-python.cmake ESCAPE_QUOTES @ONLY) + install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install-python.cmake") - # XXX cmake does not have an uninstall target, do not bother with this then. - # XXX glob patterns like this will probably not work - #add_custom_target(python-uninstall - # COMMAND ${CMAKE} -E remove -f ${DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}/python*/site-packages/nghttp2.so - # COMMAND ${CMAKE} -E remove -f ${DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}/python*/site-packages/python_nghttp2-*.egg - #) - - # XXX cleaner way to advertise the build artifacts? (note nghttp2.c is cleaned automatically) - add_custom_target(python-clean - COMMAND ${PYTHON_EXECUTABLE} setup.py clean --all - ) - - # XXX CYTHON_EXECUTABLE is not set! add_custom_command(OUTPUT nghttp2.c - COMMAND ${CYTHON_EXECUTABLE} -o nghttp2.c nghttp2.pyx + COMMAND "${CYTHON_EXECUTABLE}" -o nghttp2.c + "${CMAKE_CURRENT_SOURCE_DIR}/nghttp2.pyx" + VERBATIM DEPENDS nghttp2.pyx ) +## This works also, except that the installation target is missing... +# include(UseCython) +# cython_add_module(python_nghttp2 nghttp2.pyx) +# set_target_properties(python_nghttp2 PROPERTIES +# OUTPUT_NAME nghttp2 +# ) +# target_include_directories(python_nghttp2 PRIVATE +# "${CMAKE_SOURCE_DIR}/lib" +# "${CMAKE_SOURCE_DIR}/lib/includes" +# "${CMAKE_BINARY_DIR}/lib/includes" +# ) +# target_link_libraries(python_nghttp2 +# nghttp2 +# ) endif() diff --git a/python/install-python.cmake.in b/python/install-python.cmake.in new file mode 100644 index 00000000..f3edbdb0 --- /dev/null +++ b/python/install-python.cmake.in @@ -0,0 +1,10 @@ +get_filename_component(rootdir "$ENV{DESTDIR}" ABSOLUTE) +if(rootdir STREQUAL "") + set(rootdir /) +endif() +execute_process( + COMMAND "@PYTHON_EXECUTABLE@" setup.py install + --skip-build + --root=${rootdir} --prefix=${CMAKE_INSTALL_PREFIX} + WORKING_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@" +) diff --git a/python/setup.py.in b/python/setup.py.in index a2b4851d..93f89964 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -39,6 +39,7 @@ setup( '@top_srcdir@/lib/includes', '@top_builddir@/lib/includes'], library_dirs=['@top_builddir@/lib/.libs', + '@top_builddir@/lib', '@top_builddir@'], libraries=LIBS)], long_description='TBD'