From b655e2103ff9d572b4145722f98b14e9ebe49f10 Mon Sep 17 00:00:00 2001 From: Dominique Leuenberger Date: Thu, 4 Aug 2016 12:07:27 +0200 Subject: [PATCH] Add support to build Python2 and Python3 bindings in parallel Fixes issue #22 --- .travis.yml | 2 +- INSTALL | 4 +- NEWS | 7 ++ bindings/CMakeLists.txt | 11 ++- bindings/python/CMakeLists.txt | 25 ------ bindings/python/python2/CMakeLists.txt | 25 ++++++ bindings/python/python3/CMakeLists.txt | 25 ++++++ cmake/FindPython2Interp.cmake | 145 +++++++++++++++++++++++++++++++++ cmake/FindPython3Interp.cmake | 145 +++++++++++++++++++++++++++++++++ 9 files changed, 359 insertions(+), 30 deletions(-) delete mode 100644 bindings/python/CMakeLists.txt create mode 100644 bindings/python/python2/CMakeLists.txt create mode 100644 bindings/python/python3/CMakeLists.txt create mode 100644 cmake/FindPython2Interp.cmake create mode 100644 cmake/FindPython3Interp.cmake diff --git a/.travis.yml b/.travis.yml index 01f0312..b64a7d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ script: - | cmake . \ -DWITH_PERL=ON \ - -DWITH_PYTHON=ON \ + -DWITH_PYTHON2=ON \ -DWITH_GNOME3=ON \ -DWITH_KDE=ON \ -DWITH_WEBKIT3=ON \ diff --git a/INSTALL b/INSTALL index 8fc0c1a..bf04881 100644 --- a/INSTALL +++ b/INSTALL @@ -110,7 +110,9 @@ WITH_NM: Default to ON. Enable NetworkManager bindings. WITH_PERL: Default to ON. Enable Perl bindings. -WITH_PYTHON: Default to ON. Enable Python bindings. +WITH_PYTHON2: Default to ON. Enable Python bindings. + +WITH_PYTHON3: Default to ON. Enable Python bindings. WITH_VALA: Default to OFF. Enable Vala bindings. diff --git a/NEWS b/NEWS index f822bbd..9eb8136 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +New in Version 0.4.14: +============================== +* Parallel build support for python2 and python3. + -DWITH_PYTHON has been replaced with -DWITH_PYTHON2 and + -DWITH_PYTHON3 to have full control over this. Default is + ON for both (issue#22) + New in Version 0.4.13 ============================== * Allow linking webkit pacrunner against javascriptcore-4.0 diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 28bad03..2b0ede4 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,6 +1,11 @@ -option(WITH_PYTHON "Enables Python bindings" ON) -if (WITH_PYTHON) - add_subdirectory(python) +option(WITH_PYTHON2 "Enables Python 2 bindings" ON) +if (WITH_PYTHON2) + add_subdirectory(python/python2) +endif() + +option(WITH_PYTHON3 "Enables Python 3 bindings" ON) +if (WITH_PYTHON3) + add_subdirectory(python/python3) endif() option(WITH_DOTNET "Enables C# bindings" OFF) diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt deleted file mode 100644 index aca852f..0000000 --- a/bindings/python/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -find_package(PythonInterp) - -if(PYTHONINTERP_FOUND) - set(PYTHON_SITEPKG_DIR "${PYTHON_SITEPKG_DIR}" CACHE PATH "Python site-package directory.") - - if(NOT PYTHON_SITEPKG_DIR) - execute_process(COMMAND - ${PYTHON_EXECUTABLE} - -c "import sys; print sys.version[0:3]" - OUTPUT_VARIABLE PYTHON_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - - message(STATUS "Found python version ${PYTHON_VERSION}") - - execute_process(COMMAND - ${PYTHON_EXECUTABLE} - -c "import distutils.sysconfig ; print distutils.sysconfig.get_python_lib(plat_specific=0)" - OUTPUT_VARIABLE PYTHON_SITEPKG_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) - endif() - - message(STATUS "Using PYTHON_SITEPKG_DIR=${PYTHON_SITEPKG_DIR}") - - install(FILES libproxy.py DESTINATION ${PYTHON_SITEPKG_DIR}) -endif() diff --git a/bindings/python/python2/CMakeLists.txt b/bindings/python/python2/CMakeLists.txt new file mode 100644 index 0000000..00df551 --- /dev/null +++ b/bindings/python/python2/CMakeLists.txt @@ -0,0 +1,25 @@ +find_package(Python2Interp) + +if(PYTHON2INTERP_FOUND) + set(PYTHON2_SITEPKG_DIR "${PYTHON2_SITEPKG_DIR}" CACHE PATH "Python 2 site-package directory.") + + if(NOT PYTHON2_SITEPKG_DIR) + execute_process(COMMAND + ${PYTHON2_EXECUTABLE} + -c "import sys; print (sys.version[0:3])" + OUTPUT_VARIABLE PYTHON2_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + message(STATUS "Found python 2 version ${PYTHON2_VERSION}") + + execute_process(COMMAND + ${PYTHON2_EXECUTABLE} + -c "import distutils.sysconfig ; print (distutils.sysconfig.get_python_lib(plat_specific=0))" + OUTPUT_VARIABLE PYTHON2_SITEPKG_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + + message(STATUS "Using PYTHON2_SITEPKG_DIR=${PYTHON2_SITEPKG_DIR}") + + install(FILES ../libproxy.py DESTINATION ${PYTHON2_SITEPKG_DIR}) +endif() diff --git a/bindings/python/python3/CMakeLists.txt b/bindings/python/python3/CMakeLists.txt new file mode 100644 index 0000000..bf87dfc --- /dev/null +++ b/bindings/python/python3/CMakeLists.txt @@ -0,0 +1,25 @@ +find_package(Python3Interp) + +if(PYTHON3INTERP_FOUND) + set(PYTHON3_SITEPKG_DIR "${PYTHON3_SITEPKG_DIR}" CACHE PATH "Python 3 site-package directory.") + + if(NOT PYTHON3_SITEPKG_DIR) + execute_process(COMMAND + ${PYTHON3_EXECUTABLE} + -c "import sys; print (sys.version[0:3])" + OUTPUT_VARIABLE PYTHON3_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + message(STATUS "Found python 3 version ${PYTHON3_VERSION}") + + execute_process(COMMAND + ${PYTHON3_EXECUTABLE} + -c "import distutils.sysconfig ; print (distutils.sysconfig.get_python_lib(plat_specific=0))" + OUTPUT_VARIABLE PYTHON3_SITEPKG_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + + message(STATUS "Using PYTHON3_SITEPKG_DIR=${PYTHON3_SITEPKG_DIR}") + + install(FILES ../libproxy.py DESTINATION ${PYTHON3_SITEPKG_DIR}) +endif() diff --git a/cmake/FindPython2Interp.cmake b/cmake/FindPython2Interp.cmake new file mode 100644 index 0000000..fbece44 --- /dev/null +++ b/cmake/FindPython2Interp.cmake @@ -0,0 +1,145 @@ +#.rst: +# FindPython2Interp +# ---------------- +# +# Find python 3 interpreter (based on original FindPythonInterp from cmake) +# +# This module finds if Python interpreter is installed and determines +# where the executables are. This code sets the following variables: +# +# :: +# +# PYTHON2INTERP_FOUND - Was the Python executable found +# PYTHON2_EXECUTABLE - path to the Python interpreter +# +# +# +# :: +# +# PYTHON2_VERSION_STRING - Python version found e.g. 2.5.1 +# PYTHON2_VERSION_MAJOR - Python major version found e.g. 1 +# PYTHON2_VERSION_MINOR - Python minor version found e.g. 5 +# PYTHON2_VERSION_PATCH - Python patch version found e.g. 1 +# +#============================================================================= +# Copyright 2005-2010 Kitware, Inc. +# Copyright 2011 Bjoern Ricks +# Copyright 2012 Rolf Eike Beer +# Copyright 2016 Dominique Leuenberger +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +unset(_Python2_NAMES) + +set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) + +if(Python2Interp_FIND_VERSION) + if(Python2Interp_FIND_VERSION_COUNT GREATER 1) + set(_PYTHON2_FIND_MAJ_MIN "${Python2Interp_FIND_VERSION_MAJOR}.${Python2Interp_FIND_VERSION_MINOR}") + list(APPEND _Python2_NAMES + python${_PYTHON2_FIND_MAJ_MIN} + python${Python2Interp_FIND_VERSION_MAJOR}) + unset(_PYTHON2_FIND_OTHER_VERSIONS) + if(NOT Python2Interp_FIND_VERSION_EXACT) + foreach(_PYTHON2_V ${_PYTHON${Python2Interp_FIND_VERSION_MAJOR}_VERSIONS}) + if(NOT _PYTHON2_V VERSION_LESS _PYTHON2_FIND_MAJ_MIN) + list(APPEND _PYTHON2_FIND_OTHER_VERSIONS ${_PYTHON2_V}) + endif() + endforeach() + endif() + unset(_PYTHON2_FIND_MAJ_MIN) + else() + list(APPEND _Python2_NAMES python${Python2Interp_FIND_VERSION_MAJOR}) + set(_PYTHON2_FIND_OTHER_VERSIONS ${_PYTHON${Python2Interp_FIND_VERSION_MAJOR}_VERSIONS}) + endif() +else() + set(_PYTHON2_FIND_OTHER_VERSIONS ${_PYTHON2_VERSIONS}) +endif() +find_program(PYTHON2_EXECUTABLE NAMES ${_Python2_NAMES}) + +# If FindPythonInterp has already found the major and minor version, +# insert that version next to get consistent versions of the interpreter and +# library. +if(DEFINED PYTHON2LIBS_VERSION_STRING) + string(REPLACE "." ";" _PYTHON2LIBS_VERSION "${PYTHON2LIBS_VERSION_STRING}") + list(GET _PYTHON2LIBS_VERSION 0 _PYTHON2LIBS_VERSION_MAJOR) + list(GET _PYTHON2LIBS_VERSION 1 _PYTHON2LIBS_VERSION_MINOR) + list(APPEND _Python2_VERSIONS ${_PYTHON2LIBS_VERSION_MAJOR}.${_PYTHON2LIBS_VERSION_MINOR}) +endif() +# Search for the current active python version first +list(APPEND _Python2_VERSIONS ";") + +unset(_PYTHON2_VERSIONS) + +# Search for newest python version if python executable isn't found +if(NOT PYTHON2_EXECUTABLE) + foreach(_CURRENT_VERSION IN LISTS _Python2_VERSIONS) + set(_Python2_NAMES python${_CURRENT_VERSION}) + if(WIN32) + list(APPEND _Python2_NAMES python) + endif() + find_program(PYTHON2_EXECUTABLE + NAMES ${_Python2_NAMES} + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath] + ) + endforeach() +endif() + +# determine python version string +if(PYTHON2_EXECUTABLE) + execute_process(COMMAND "${PYTHON2_EXECUTABLE}" -c + "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))" + OUTPUT_VARIABLE _VERSION + RESULT_VARIABLE _PYTHON2_VERSION_RESULT + ERROR_QUIET) + if(NOT _PYTHON2_VERSION_RESULT) + string(REPLACE ";" "." PYTHON2_VERSION_STRING "${_VERSION}") + list(GET _VERSION 0 PYTHON2_VERSION_MAJOR) + list(GET _VERSION 1 PYTHON2_VERSION_MINOR) + list(GET _VERSION 2 PYTHON2_VERSION_PATCH) + if(PYTHON2_VERSION_PATCH EQUAL 0) + # it's called "Python 3.1", not "3.1.0" + string(REGEX REPLACE "\\.0$" "" PYTHON2_VERSION_STRING "${PYTHON2_VERSION_STRING}") + endif() + else() + # sys.version predates sys.version_info, so use that + execute_process(COMMAND "${PYTHON2_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.version)" + OUTPUT_VARIABLE _VERSION + RESULT_VARIABLE _PYTHON2_VERSION_RESULT + ERROR_QUIET) + if(NOT _PYTHON2_VERSION_RESULT) + string(REGEX REPLACE " .*" "" PYTHON2_VERSION_STRING "${_VERSION}") + string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON2_VERSION_MAJOR "${PYTHON2_VERSION_STRING}") + string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON2_VERSION_MINOR "${PYTHON2_VERSION_STRING}") + if(PYTHON2_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.([0-9]+)") + set(PYTHON2_VERSION_PATCH "${CMAKE_MATCH_1}") + else() + set(PYTHON2_VERSION_PATCH "0") + endif() + else() + # sys.version was first documented for Python 1.5, so assume + # this is older. + set(PYTHON2_VERSION_STRING "1.4") + set(PYTHON2_VERSION_MAJOR "1") + set(PYTHON2_VERSION_MINOR "4") + set(PYTHON2_VERSION_PATCH "0") + endif() + endif() + unset(_PYTHON2_VERSION_RESULT) + unset(_VERSION) +endif() + +# handle the QUIETLY and REQUIRED arguments and set PYTHON2INTERP_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Python2Interp REQUIRED_VARS PYTHON2_EXECUTABLE VERSION_VAR PYTHON2_VERSION_STRING) + +mark_as_advanced(PYTHON2_EXECUTABLE) diff --git a/cmake/FindPython3Interp.cmake b/cmake/FindPython3Interp.cmake new file mode 100644 index 0000000..c6cbe3d --- /dev/null +++ b/cmake/FindPython3Interp.cmake @@ -0,0 +1,145 @@ +#.rst: +# FindPython3Interp +# ---------------- +# +# Find python 3 interpreter (based on original FindPythonInterp from cmake) +# +# This module finds if Python interpreter is installed and determines +# where the executables are. This code sets the following variables: +# +# :: +# +# PYTHON3INTERP_FOUND - Was the Python executable found +# PYTHON3_EXECUTABLE - path to the Python interpreter +# +# +# +# :: +# +# PYTHON3_VERSION_STRING - Python version found e.g. 3.5.1 +# PYTHON3_VERSION_MAJOR - Python major version found e.g. 3 +# PYTHON3_VERSION_MINOR - Python minor version found e.g. 5 +# PYTHON3_VERSION_PATCH - Python patch version found e.g. 1 +# +#============================================================================= +# Copyright 2005-2010 Kitware, Inc. +# Copyright 2011 Bjoern Ricks +# Copyright 2012 Rolf Eike Beer +# Copyright 2016 Dominique Leuenberger +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +unset(_Python3_NAMES) + +set(_Python3_VERSIONS 3.6 3.5 3.4 3.3 3.2 3.1 3.0) + +if(Python3Interp_FIND_VERSION) + if(Python3Interp_FIND_VERSION_COUNT GREATER 1) + set(_PYTHON3_FIND_MAJ_MIN "${Python3Interp_FIND_VERSION_MAJOR}.${Python3Interp_FIND_VERSION_MINOR}") + list(APPEND _Python3_NAMES + python${_PYTHON3_FIND_MAJ_MIN} + python${Python3Interp_FIND_VERSION_MAJOR}) + unset(_PYTHON3_FIND_OTHER_VERSIONS) + if(NOT Python3Interp_FIND_VERSION_EXACT) + foreach(_PYTHON3_V ${_PYTHON${Python3Interp_FIND_VERSION_MAJOR}_VERSIONS}) + if(NOT _PYTHON3_V VERSION_LESS _PYTHON3_FIND_MAJ_MIN) + list(APPEND _PYTHON3_FIND_OTHER_VERSIONS ${_PYTHON3_V}) + endif() + endforeach() + endif() + unset(_PYTHON3_FIND_MAJ_MIN) + else() + list(APPEND _Python3_NAMES python${Python3Interp_FIND_VERSION_MAJOR}) + set(_PYTHON3_FIND_OTHER_VERSIONS ${_PYTHON${Python3Interp_FIND_VERSION_MAJOR}_VERSIONS}) + endif() +else() + set(_PYTHON3_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS}) +endif() +find_program(PYTHON3_EXECUTABLE NAMES ${_Python3_NAMES}) + +# If FindPythonInterp has already found the major and minor version, +# insert that version next to get consistent versions of the interpreter and +# library. +if(DEFINED PYTHON3LIBS_VERSION_STRING) + string(REPLACE "." ";" _PYTHON3LIBS_VERSION "${PYTHON3LIBS_VERSION_STRING}") + list(GET _PYTHON3LIBS_VERSION 0 _PYTHON3LIBS_VERSION_MAJOR) + list(GET _PYTHON3LIBS_VERSION 1 _PYTHON3LIBS_VERSION_MINOR) + list(APPEND _Python3_VERSIONS ${_PYTHON3LIBS_VERSION_MAJOR}.${_PYTHON3LIBS_VERSION_MINOR}) +endif() +# Search for the current active python version first +list(APPEND _Python3_VERSIONS ";") + +unset(_PYTHON3_VERSIONS) + +# Search for newest python version if python executable isn't found +if(NOT PYTHON3_EXECUTABLE) + foreach(_CURRENT_VERSION IN LISTS _Python3_VERSIONS) + set(_Python3_NAMES python${_CURRENT_VERSION}) + if(WIN32) + list(APPEND _Python3_NAMES python3) + endif() + find_program(PYTHON3_EXECUTABLE + NAMES ${_Python3_NAMES} + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath] + ) + endforeach() +endif() + +# determine python version string +if(PYTHON3_EXECUTABLE) + execute_process(COMMAND "${PYTHON3_EXECUTABLE}" -c + "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))" + OUTPUT_VARIABLE _VERSION3 + RESULT_VARIABLE _PYTHON3_VERSION_RESULT + ERROR_QUIET) + if(NOT _PYTHON3_VERSION_RESULT) + string(REPLACE ";" "." PYTHON3_VERSION_STRING "${_VERSION3}") + list(GET _VERSION3 0 PYTHON3_VERSION_MAJOR) + list(GET _VERSION3 1 PYTHON3_VERSION_MINOR) + list(GET _VERSION3 2 PYTHON3_VERSION_PATCH) + if(PYTHON3_VERSION_PATCH EQUAL 0) + # it's called "Python 3.1", not "3.1.0" + string(REGEX REPLACE "\\.0$" "" PYTHON3_VERSION_STRING "${PYTHON3_VERSION_STRING}") + endif() + else() + # sys.version predates sys.version_info, so use that + execute_process(COMMAND "${PYTHON3_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.version)" + OUTPUT_VARIABLE _VERSION3 + RESULT_VARIABLE _PYTHON3_VERSION_RESULT + ERROR_QUIET) + if(NOT _PYTHON3_VERSION_RESULT) + string(REGEX REPLACE " .*" "" PYTHON3_VERSION_STRING "${_VERSION3}") + string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON3_VERSION_MAJOR "${PYTHON3_VERSION_STRING}") + string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON3_VERSION_MINOR "${PYTHON3_VERSION_STRING}") + if(PYTHON3_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.([0-9]+)") + set(PYTHON3_VERSION_PATCH "${CMAKE_MATCH_1}") + else() + set(PYTHON3_VERSION_PATCH "0") + endif() + else() + # sys.version was first documented for Python 1.5, so assume + # this is older. + set(PYTHON3_VERSION_STRING "1.4") + set(PYTHON3_VERSION_MAJOR "1") + set(PYTHON3_VERSION_MINOR "4") + set(PYTHON3_VERSION_PATCH "0") + endif() + endif() + unset(_PYTHON3_VERSION_RESULT) + unset(_VERSION3) +endif() + +# handle the QUIETLY and REQUIRED arguments and set PYTHON3INTERP_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Python3Interp REQUIRED_VARS PYTHON3_EXECUTABLE PYTHON3_VERSION_STRING) + +mark_as_advanced(PYTHON3_EXECUTABLE)