From 99841419abb16c9a75f72a5657b6ca10ce7674cd Mon Sep 17 00:00:00 2001 From: Brendan Le Foll Date: Thu, 26 May 2016 12:01:50 +0100 Subject: [PATCH] python: Support building of both python2 & python3 bindings Signed-off-by: Brendan Le Foll --- CMakeLists.txt | 8 +- cmake/modules/OpenCVDetectPython.cmake | 158 +++++++++++++++++++ docs/building.md | 4 - src/python/CMakeLists.txt | 53 +------ src/python/{mraa.i => mraapython.i} | 4 - src/python/python2/CMakeLists.txt | 39 +++++ src/python/{ => python2}/docs/CMakeLists.txt | 2 +- src/python/{ => python2}/docs/conf.py.in | 0 src/python/{ => python2}/docs/example.rst | 0 src/python/{ => python2}/docs/index.rst | 0 src/python/{ => python2}/docs/mraa.rst | 0 src/python/python2/mraa2.i | 5 + src/python/python3/CMakeLists.txt | 24 +++ src/python/python3/mraa3.i | 3 + 14 files changed, 235 insertions(+), 65 deletions(-) create mode 100644 cmake/modules/OpenCVDetectPython.cmake rename src/python/{mraa.i => mraapython.i} (98%) create mode 100644 src/python/python2/CMakeLists.txt rename src/python/{ => python2}/docs/CMakeLists.txt (93%) rename src/python/{ => python2}/docs/conf.py.in (100%) rename src/python/{ => python2}/docs/example.rst (100%) rename src/python/{ => python2}/docs/index.rst (100%) rename src/python/{ => python2}/docs/mraa.rst (100%) create mode 100644 src/python/python2/mraa2.i create mode 100644 src/python/python3/CMakeLists.txt create mode 100644 src/python/python3/mraa3.i diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cb96d9..02a17fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,6 @@ option (IMRAA "Add Imraa support to mraa." OFF) option (FTDI4222 "Build with FTDI FT4222 subplatform support." OFF) option (IPK "Generate IPK using CPack" OFF) option (RPM "Generate RPM using CPack" OFF) -option (BUILDPYTHON3 "Use python3 for building/installing/testing" OFF) option (ENABLEEXAMPLES "Disable building of examples" ON) option (INSTALLGPIOTOOL "Install gpio tool" OFF) option (INSTALLTOOLS "Install all tools" OFF) @@ -109,12 +108,7 @@ else () endif() if (BUILDSWIGPYTHON OR BUILDTESTS) - if (BUILDPYTHON3) - set (PYTHONBUILD_VERSION 3) - else () - set (PYTHONBUILD_VERSION 2.7) - endif () - find_package (PythonInterp ${PYTHONBUILD_VERSION} REQUIRED) + include (cmake/modules/OpenCVDetectPython.cmake) endif () if (BUILDDOC) diff --git a/cmake/modules/OpenCVDetectPython.cmake b/cmake/modules/OpenCVDetectPython.cmake new file mode 100644 index 0000000..7b846c9 --- /dev/null +++ b/cmake/modules/OpenCVDetectPython.cmake @@ -0,0 +1,158 @@ +# Find specified Python version +# Arguments: +# preferred_version (value): Version to check for first +# min_version (value): Minimum supported version +# library_env (value): Name of Python library ENV variable to check +# include_dir_env (value): Name of Python include directory ENV variable to check +# found (variable): Set if interpreter found +# executable (variable): Output of executable found +# version_string (variable): Output of found version +# version_major (variable): Output of found major version +# version_minor (variable): Output of found minor version +# libs_found (variable): Set if libs found +# libs_version_string (variable): Output of found libs version +# libraries (variable): Output of found Python libraries +# library (variable): Output of found Python library +# debug_libraries (variable): Output of found Python debug libraries +# debug_library (variable): Output of found Python debug library +# include_path (variable): Output of found Python include path +# include_dir (variable): Output of found Python include dir +# include_dir2 (variable): Output of found Python include dir2 +# packages_path (variable): Output of found Python packages path +function(find_python preferred_version min_version library_env include_dir_env + found executable version_string version_major version_minor + libs_found libs_version_string libraries library debug_libraries + debug_library include_path include_dir include_dir2 packages_path) +if(NOT ${found}) + if(${executable}) + set(PYTHON_EXECUTABLE "${${executable}}") + endif() + + find_package(PythonInterp "${preferred_version}") + if(NOT PYTHONINTERP_FOUND) + find_package(PythonInterp "${min_version}") + endif() + + if(PYTHONINTERP_FOUND) + # Copy outputs + set(_found ${PYTHONINTERP_FOUND}) + set(_executable ${PYTHON_EXECUTABLE}) + set(_version_string ${PYTHON_VERSION_STRING}) + set(_version_major ${PYTHON_VERSION_MAJOR}) + set(_version_minor ${PYTHON_VERSION_MINOR}) + set(_version_patch ${PYTHON_VERSION_PATCH}) + + # Clear find_host_package side effects + unset(PYTHONINTERP_FOUND) + unset(PYTHON_EXECUTABLE CACHE) + unset(PYTHON_VERSION_STRING) + unset(PYTHON_VERSION_MAJOR) + unset(PYTHON_VERSION_MINOR) + unset(PYTHON_VERSION_PATCH) + endif() + + if(_found) + set(_version_major_minor "${_version_major}.${_version_minor}") + + if(NOT ANDROID AND NOT APPLE_FRAMEWORK) + # not using _version_string here, because it might not conform to the CMake version format + if(CMAKE_CROSSCOMPILING) + # builder version can differ from target, matching base version (e.g. 2.7) + find_package(PythonLibs "${_version_major_minor}") + else() + find_package(PythonLibs "${_version_major_minor}.${_version_patch}" EXACT) + endif() + + if(PYTHONLIBS_FOUND) + # Copy outputs + set(_libs_found ${PYTHONLIBS_FOUND}) + set(_libraries ${PYTHON_LIBRARIES}) + set(_include_path ${PYTHON_INCLUDE_PATH}) + set(_include_dirs ${PYTHON_INCLUDE_DIRS}) + set(_debug_libraries ${PYTHON_DEBUG_LIBRARIES}) + set(_libs_version_string ${PYTHONLIBS_VERSION_STRING}) + set(_debug_library ${PYTHON_DEBUG_LIBRARY}) + set(_library ${PYTHON_LIBRARY}) + set(_library_debug ${PYTHON_LIBRARY_DEBUG}) + set(_library_release ${PYTHON_LIBRARY_RELEASE}) + set(_include_dir ${PYTHON_INCLUDE_DIR}) + set(_include_dir2 ${PYTHON_INCLUDE_DIR2}) + + # Clear find_package side effects + unset(PYTHONLIBS_FOUND) + unset(PYTHON_LIBRARIES) + unset(PYTHON_INCLUDE_PATH) + unset(PYTHON_INCLUDE_DIRS) + unset(PYTHON_DEBUG_LIBRARIES) + unset(PYTHONLIBS_VERSION_STRING) + unset(PYTHON_DEBUG_LIBRARY CACHE) + unset(PYTHON_LIBRARY) + unset(PYTHON_LIBRARY_DEBUG) + unset(PYTHON_LIBRARY_RELEASE) + unset(PYTHON_LIBRARY CACHE) + unset(PYTHON_LIBRARY_DEBUG CACHE) + unset(PYTHON_LIBRARY_RELEASE CACHE) + unset(PYTHON_INCLUDE_DIR CACHE) + unset(PYTHON_INCLUDE_DIR2 CACHE) + endif() + endif() + + execute_process(COMMAND ${_executable} -c "from distutils.sysconfig import *; print(get_python_lib())" + RESULT_VARIABLE _cvpy_process + OUTPUT_VARIABLE _std_packages_path + OUTPUT_STRIP_TRAILING_WHITESPACE) + if("${_std_packages_path}" MATCHES "site-packages") + set(_packages_path "python${_version_major_minor}/site-packages") + else() #debian based assumed, install to the dist-packages. + set(_packages_path "python${_version_major_minor}/dist-packages") + endif() + if(EXISTS "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/${${packages_path}}") + set(_packages_path "lib${LIB_SUFFIX}/${_packages_path}") + else() + set(_packages_path "lib/${_packages_path}") + endif() + endif() + + # Export return values + set(${found} "${_found}" CACHE INTERNAL "") + set(${executable} "${_executable}" CACHE FILEPATH "Path to Python interpretor") + set(${version_string} "${_version_string}" CACHE INTERNAL "") + set(${version_major} "${_version_major}" CACHE INTERNAL "") + set(${version_minor} "${_version_minor}" CACHE INTERNAL "") + set(${libs_found} "${_libs_found}" CACHE INTERNAL "") + set(${libs_version_string} "${_libs_version_string}" CACHE INTERNAL "") + set(${libraries} "${_libraries}" CACHE INTERNAL "Python libraries") + set(${library} "${_library}" CACHE FILEPATH "Path to Python library") + set(${debug_libraries} "${_debug_libraries}" CACHE INTERNAL "") + set(${debug_library} "${_debug_library}" CACHE FILEPATH "Path to Python debug") + set(${include_path} "${_include_path}" CACHE INTERNAL "") + set(${include_dir} "${_include_dir}" CACHE PATH "Python include dir") + set(${include_dir2} "${_include_dir2}" CACHE PATH "Python include dir 2") + set(${packages_path} "${_packages_path}" CACHE PATH "Where to install the python packages.") +endif() +endfunction(find_python) + +find_python(2.7 "${MIN_VER_PYTHON2}" PYTHON2_LIBRARY PYTHON2_INCLUDE_DIR + PYTHON2INTERP_FOUND PYTHON2_EXECUTABLE PYTHON2_VERSION_STRING + PYTHON2_VERSION_MAJOR PYTHON2_VERSION_MINOR PYTHON2LIBS_FOUND + PYTHON2LIBS_VERSION_STRING PYTHON2_LIBRARIES PYTHON2_LIBRARY + PYTHON2_DEBUG_LIBRARIES PYTHON2_LIBRARY_DEBUG PYTHON2_INCLUDE_PATH + PYTHON2_INCLUDE_DIR PYTHON2_INCLUDE_DIR2 PYTHON2_PACKAGES_PATH) + +find_python(3 "${MIN_VER_PYTHON3}" PYTHON3_LIBRARY PYTHON3_INCLUDE_DIR + PYTHON3INTERP_FOUND PYTHON3_EXECUTABLE PYTHON3_VERSION_STRING + PYTHON3_VERSION_MAJOR PYTHON3_VERSION_MINOR PYTHON3LIBS_FOUND + PYTHON3LIBS_VERSION_STRING PYTHON3_LIBRARIES PYTHON3_LIBRARY + PYTHON3_DEBUG_LIBRARIES PYTHON3_LIBRARY_DEBUG PYTHON3_INCLUDE_PATH + PYTHON3_INCLUDE_DIR PYTHON3_INCLUDE_DIR2 PYTHON3_PACKAGES_PATH) + + +if(PYTHON_DEFAULT_EXECUTABLE) + set(PYTHON_DEFAULT_AVAILABLE "TRUE") +elseif(PYTHON2INTERP_FOUND) # Use Python 2 as default Python interpreter + set(PYTHON_DEFAULT_AVAILABLE "TRUE") + set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}") +elseif(PYTHON3INTERP_FOUND) # Use Python 2 as fallback Python interpreter (if there is no Python 2) + set(PYTHON_DEFAULT_AVAILABLE "TRUE") + set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON3_EXECUTABLE}") +endif() diff --git a/docs/building.md b/docs/building.md index 628a6e5..172ccf3 100644 --- a/docs/building.md +++ b/docs/building.md @@ -92,10 +92,6 @@ Building doc, this will require [SPHINX](http://sphinx-doc.org) & [Doxygen](http://doxygen.org): `-DBUILDDOC=ON` -Building with Python 3 (careful you need to clear CMake cache between Python -version switches!) - `-DBUILDPYTHON3=ON` - Override build architecture (this is useful because on x86 ARM code is not compiled so use this flag to force the target arch) `-DBUILDARCH=arm` diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index c51ccd1..e014fad 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -1,50 +1,5 @@ -find_package (PythonLibs ${PYTHONBUILD_VERSION} REQUIRED) +set_source_files_properties (mraapython.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties (mraapython.i PROPERTIES SWIG_FLAGS "-I${CMAKE_BINARY_DIR}/src") -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/.. - ${PYTHON_INCLUDE_DIRS} -) - -set_source_files_properties (mraa.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties (mraa.i PROPERTIES SWIG_FLAGS "-I${CMAKE_BINARY_DIR}/src") -swig_add_module (python-mraa python mraa.i mraapy.c) -swig_link_libraries (python-mraa ${PYTHON_LIBRARIES} mraa) - -if (DOXYGEN_FOUND) - foreach (_file ${DOCCLASSES}) - add_dependencies (${SWIG_MODULE_python-mraa_REAL_NAME} ${_file}class_doc_i) - endforeach () - add_dependencies (${SWIG_MODULE_python-mraa_REAL_NAME} common_hpp_doc_i) - - add_custom_target (pydoc - pydoc -w ${CMAKE_CURRENT_BINARY_DIR}/mraa.py ${CMAKE_CURRENT_BINARY_DIR}/ - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with pydoc" VERBATIM - ) -endif () - -set_target_properties (${SWIG_MODULE_python-mraa_REAL_NAME} PROPERTIES - OUTPUT_NAME _mraa - COMPILE_FLAGS "${CMAKE_C_FLAGS} -DSWIGPYTHON=${SWIG_FOUND}" -) - -execute_process ( - COMMAND ${PYTHON_EXECUTABLE} -c - "import site, sys; sys.stdout.write(site.PREFIXES[-1])" - OUTPUT_VARIABLE PYTHON_PREFIX -) -file (TO_CMAKE_PATH "${PYTHON_PREFIX}" PYTHON_PREFIX) -execute_process ( - COMMAND ${PYTHON_EXECUTABLE} -c - "import site, sys; sys.stdout.write(site.getusersitepackages().replace(site.getuserbase(), site.PREFIXES[-1]))" - OUTPUT_VARIABLE PYTHON_SITE_DIR -) -file (TO_CMAKE_PATH "${PYTHON_SITE_DIR}" PYTHON_SITE_DIR) -string (REGEX REPLACE "^${PYTHON_PREFIX}/" "" - PYTHON_SITE_DIR "${PYTHON_SITE_DIR}") - -install (FILES ${CMAKE_CURRENT_BINARY_DIR}/_mraa.so - ${CMAKE_CURRENT_BINARY_DIR}/mraa.py - DESTINATION ${PYTHON_SITE_DIR}) - -add_subdirectory (docs) +add_subdirectory (python2) +add_subdirectory (python3) diff --git a/src/python/mraa.i b/src/python/mraapython.i similarity index 98% rename from src/python/mraa.i rename to src/python/mraapython.i index 0bfee9a..521ef53 100644 --- a/src/python/mraa.i +++ b/src/python/mraapython.i @@ -1,7 +1,3 @@ -%module(docstring="Python interface to libmraa") mraa - -%feature("autodoc", "3"); - %include typemaps.i %include carrays.i diff --git a/src/python/python2/CMakeLists.txt b/src/python/python2/CMakeLists.txt new file mode 100644 index 0000000..10d23c2 --- /dev/null +++ b/src/python/python2/CMakeLists.txt @@ -0,0 +1,39 @@ +set_source_files_properties (mraa2.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties (mraa2.i PROPERTIES SWIG_FLAGS "-I${CMAKE_BINARY_DIR}/src") + +if (PYTHON2_LIBRARY) + message ("PYTHON2 attempting to build!") + + swig_add_module (python2-mraa python mraa2.i ../mraapy.c) + swig_link_libraries (python2-mraa ${PYTHON2_LIBRARIES} mraa) + + target_include_directories(${SWIG_MODULE_python2-mraa_REAL_NAME} + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/../.." + "${PYTHON2_INCLUDE_DIR}" + ) + + if (DOXYGEN_FOUND AND PYTHON2_EXECUTABLE) + foreach (_file ${DOCCLASSES}) + add_dependencies (${SWIG_MODULE_python2-mraa_REAL_NAME} ${_file}class_doc_i) + endforeach () + add_dependencies (${SWIG_MODULE_python2-mraa_REAL_NAME} common_hpp_doc_i) + + add_custom_target (pydoc + pydoc -w ${CMAKE_CURRENT_BINARY_DIR}/mraa.py ${CMAKE_CURRENT_BINARY_DIR}/ + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with pydoc" VERBATIM + ) + endif () + + set_target_properties (${SWIG_MODULE_python2-mraa_REAL_NAME} PROPERTIES + OUTPUT_NAME _mraa + COMPILE_FLAGS "${CMAKE_C_FLAGS} -DSWIGPYTHON=${SWIG_FOUND}" + ) + + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/_mraa.so + ${CMAKE_CURRENT_BINARY_DIR}/mraa.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/${PYTHON2_PACKAGES_PATH}) +endif() + +add_subdirectory (docs) diff --git a/src/python/docs/CMakeLists.txt b/src/python/python2/docs/CMakeLists.txt similarity index 93% rename from src/python/docs/CMakeLists.txt rename to src/python/python2/docs/CMakeLists.txt index 9ce7880..c2a7c98 100644 --- a/src/python/docs/CMakeLists.txt +++ b/src/python/python2/docs/CMakeLists.txt @@ -36,6 +36,6 @@ if (DOXYGEN_FOUND) COMMENT "Building HTML documentation with Sphinx" ) - add_dependencies (sphinx ${SWIG_MODULE_python-mraa_REAL_NAME}) + add_dependencies (sphinx ${SWIG_MODULE_python2-mraa_REAL_NAME}) endif () endif () diff --git a/src/python/docs/conf.py.in b/src/python/python2/docs/conf.py.in similarity index 100% rename from src/python/docs/conf.py.in rename to src/python/python2/docs/conf.py.in diff --git a/src/python/docs/example.rst b/src/python/python2/docs/example.rst similarity index 100% rename from src/python/docs/example.rst rename to src/python/python2/docs/example.rst diff --git a/src/python/docs/index.rst b/src/python/python2/docs/index.rst similarity index 100% rename from src/python/docs/index.rst rename to src/python/python2/docs/index.rst diff --git a/src/python/docs/mraa.rst b/src/python/python2/docs/mraa.rst similarity index 100% rename from src/python/docs/mraa.rst rename to src/python/python2/docs/mraa.rst diff --git a/src/python/python2/mraa2.i b/src/python/python2/mraa2.i new file mode 100644 index 0000000..81f9158 --- /dev/null +++ b/src/python/python2/mraa2.i @@ -0,0 +1,5 @@ +%module(docstring="Python interface to libmraa") mraa + +%feature("autodoc", "3"); + +%include ../mraapython.i diff --git a/src/python/python3/CMakeLists.txt b/src/python/python3/CMakeLists.txt new file mode 100644 index 0000000..5fb8822 --- /dev/null +++ b/src/python/python3/CMakeLists.txt @@ -0,0 +1,24 @@ +set_source_files_properties (mraa3.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties (mraa3.i PROPERTIES SWIG_FLAGS "-I${CMAKE_BINARY_DIR}/src") + +if (PYTHON3_LIBRARY) + message ("PYTHON3 attempting to build!") + + swig_add_module (python3-mraa python mraa3.i ../mraapy.c) + swig_link_libraries (python3-mraa ${PYTHON3_LIBRARIES} mraa) + + target_include_directories(${SWIG_MODULE_python3-mraa_REAL_NAME} + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/../.." + "${PYTHON3_INCLUDE_DIR}" + ) + + set_target_properties (${SWIG_MODULE_python3-mraa_REAL_NAME} PROPERTIES + OUTPUT_NAME _mraa + COMPILE_FLAGS "${CMAKE_C_FLAGS} -DSWIGPYTHON=${SWIG_FOUND}" + ) + + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/_mraa.so + ${CMAKE_CURRENT_BINARY_DIR}/mraa.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/${PYTHON3_PACKAGES_PATH}) +endif () diff --git a/src/python/python3/mraa3.i b/src/python/python3/mraa3.i new file mode 100644 index 0000000..e3df17a --- /dev/null +++ b/src/python/python3/mraa3.i @@ -0,0 +1,3 @@ +%module(docstring="Python interface to libmraa") mraa + +%include ../mraapython.i