diff --git a/pylegu/CMakeLists.txt b/pylegu/CMakeLists.txt index 77b0171..7c46b9b 100644 --- a/pylegu/CMakeLists.txt +++ b/pylegu/CMakeLists.txt @@ -28,7 +28,7 @@ if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) endif() -set(PYBIND11_VERSION 2.4.3) +set(PYBIND11_VERSION 2.10.4) set(PYBIND11_URL "${THIRD_PARTY_DIRECTORY}/pybind11-${PYBIND11_VERSION}.zip" CACHE STRING "URL to the Pybind11 repo") ExternalProject_Add(pybind11 URL ${PYBIND11_URL} @@ -42,11 +42,12 @@ set(UCL_VERSION 1.03) set(UCL_URL "${THIRD_PARTY_DIRECTORY}/ucl-${UCL_VERSION}.tar.gz" CACHE STRING "URL to the UCL") set(UCL_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/UCL) set(UCL_PREFIX_DIR ${UCL_INSTALL_DIR}) +set(UCL_CFLAGS "${CMAKE_C_FLAGS} -std=c89 -Wno-implicit-function-declaration") ExternalProject_Add(ucl URL ${UCL_URL} PREFIX ${UCL_PREFIX_DIR} - CONFIGURE_COMMAND ${UCL_PREFIX_DIR}/src/ucl/configure --prefix=${UCL_INSTALL_DIR} --with-pic + CONFIGURE_COMMAND ${UCL_PREFIX_DIR}/src/ucl/configure --prefix=${UCL_INSTALL_DIR} --with-pic CFLAGS=${UCL_CFLAGS} BUILD_COMMAND ${MAKE} BUILD_IN_SOURCE 1 UPDATE_COMMAND "" @@ -54,7 +55,7 @@ ExternalProject_Add(ucl ) include_directories("${UCL_INSTALL_DIR}/include") -set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4) +find_package(Python REQUIRED Development) find_package(PythonLibsNew REQUIRED) add_library(pylegu SHARED pyLegu.cpp) @@ -69,7 +70,7 @@ target_include_directories(pylegu PUBLIC "${UCL_INSTALL_DIR}/include" ) -target_link_libraries(pylegu ${UCL_INSTALL_DIR}/lib/libucl.a) +target_link_libraries(pylegu ${UCL_INSTALL_DIR}/lib/libucl.a Python::Python) add_dependencies(pylegu pybind11 ucl) diff --git a/pylegu/cmake/FindPythonLibsNew.cmake b/pylegu/cmake/FindPythonLibsNew.cmake index 919a384..9d3d8ea 100644 --- a/pylegu/cmake/FindPythonLibsNew.cmake +++ b/pylegu/cmake/FindPythonLibsNew.cmake @@ -52,82 +52,148 @@ # Checking for the extension makes sure that `LibsNew` was found and not just `Libs`. if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION) - return() + return() endif() -# Use the Python interpreter to find the libs. -if(PythonLibsNew_FIND_REQUIRED) - find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} REQUIRED) +if(PythonLibsNew_FIND_QUIETLY) + set(_pythonlibs_quiet QUIET) else() - find_package(PythonInterp ${PythonLibsNew_FIND_VERSION}) + set(_pythonlibs_quiet "") endif() +if(PythonLibsNew_FIND_REQUIRED) + set(_pythonlibs_required REQUIRED) +endif() + +# Check to see if the `python` command is present and from a virtual +# environment, conda, or GHA activation - if it is, try to use that. + +if(NOT DEFINED PYTHON_EXECUTABLE) + if(DEFINED ENV{VIRTUAL_ENV}) + find_program( + PYTHON_EXECUTABLE python + PATHS "$ENV{VIRTUAL_ENV}" "$ENV{VIRTUAL_ENV}/bin" + NO_DEFAULT_PATH) + elseif(DEFINED ENV{CONDA_PREFIX}) + find_program( + PYTHON_EXECUTABLE python + PATHS "$ENV{CONDA_PREFIX}" "$ENV{CONDA_PREFIX}/bin" + NO_DEFAULT_PATH) + elseif(DEFINED ENV{pythonLocation}) + find_program( + PYTHON_EXECUTABLE python + PATHS "$ENV{pythonLocation}" "$ENV{pythonLocation}/bin" + NO_DEFAULT_PATH) + endif() + if(NOT PYTHON_EXECUTABLE) + unset(PYTHON_EXECUTABLE) + endif() +endif() + +# Use the Python interpreter to find the libs. +if(NOT PythonLibsNew_FIND_VERSION) + set(PythonLibsNew_FIND_VERSION "3.6") +endif() + +find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required} + ${_pythonlibs_quiet}) + if(NOT PYTHONINTERP_FOUND) - set(PYTHONLIBS_FOUND FALSE) - return() + set(PYTHONLIBS_FOUND FALSE) + set(PythonLibsNew_FOUND FALSE) + return() endif() -# According to http://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter +# According to https://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter # testing whether sys has the gettotalrefcount function is a reliable, cross-platform # way to detect a CPython debug interpreter. # # The library suffix is from the config var LDVERSION sometimes, otherwise # VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows. -execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" - "from distutils import sysconfig as s;import sys;import struct; +execute_process( + COMMAND + "${PYTHON_EXECUTABLE}" "-c" " +import sys;import struct; +import sysconfig as s +USE_SYSCONFIG = sys.version_info >= (3, 10) +if not USE_SYSCONFIG: + from distutils import sysconfig as ds print('.'.join(str(v) for v in sys.version_info)); print(sys.prefix); -print(s.get_python_inc(plat_specific=True)); -print(s.get_python_lib(plat_specific=True)); -print(s.get_config_var('SO')); +if USE_SYSCONFIG: + scheme = s.get_default_scheme() + if scheme == 'posix_local': + # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/ + scheme = 'posix_prefix' + print(s.get_path('platinclude', scheme)) + print(s.get_path('platlib')) + print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO')) +else: + print(ds.get_python_inc(plat_specific=True)); + print(ds.get_python_lib(plat_specific=True)); + print(ds.get_config_var('EXT_SUFFIX') or ds.get_config_var('SO')); print(hasattr(sys, 'gettotalrefcount')+0); print(struct.calcsize('@P')); print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION')); print(s.get_config_var('LIBDIR') or ''); print(s.get_config_var('MULTIARCH') or ''); " - RESULT_VARIABLE _PYTHON_SUCCESS - OUTPUT_VARIABLE _PYTHON_VALUES - ERROR_VARIABLE _PYTHON_ERROR_VALUE) + RESULT_VARIABLE _PYTHON_SUCCESS + OUTPUT_VARIABLE _PYTHON_VALUES + ERROR_VARIABLE _PYTHON_ERROR_VALUE) if(NOT _PYTHON_SUCCESS MATCHES 0) - if(PythonLibsNew_FIND_REQUIRED) - message(FATAL_ERROR - "Python config failure:\n${_PYTHON_ERROR_VALUE}") - endif() - set(PYTHONLIBS_FOUND FALSE) - return() + if(PythonLibsNew_FIND_REQUIRED) + message(FATAL_ERROR "Python config failure:\n${_PYTHON_ERROR_VALUE}") + endif() + set(PYTHONLIBS_FOUND FALSE) + set(PythonLibsNew_FOUND FALSE) + return() endif() +option( + PYBIND11_PYTHONLIBS_OVERWRITE + "Overwrite cached values read from Python library (classic search). Turn off if cross-compiling and manually setting these values." + ON) +# Can manually set values when cross-compiling +macro(_PYBIND11_GET_IF_UNDEF lst index name) + if(PYBIND11_PYTHONLIBS_OVERWRITE OR NOT DEFINED "${name}") + list(GET "${lst}" "${index}" "${name}") + endif() +endmacro() + # Convert the process output into a list if(WIN32) - string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES}) + string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES}) endif() string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES}) string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES}) -list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST) -list(GET _PYTHON_VALUES 1 PYTHON_PREFIX) -list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR) -list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES) -list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION) -list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG) -list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P) -list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX) -list(GET _PYTHON_VALUES 8 PYTHON_LIBDIR) -list(GET _PYTHON_VALUES 9 PYTHON_MULTIARCH) +_pybind11_get_if_undef(_PYTHON_VALUES 0 _PYTHON_VERSION_LIST) +_pybind11_get_if_undef(_PYTHON_VALUES 1 PYTHON_PREFIX) +_pybind11_get_if_undef(_PYTHON_VALUES 2 PYTHON_INCLUDE_DIR) +_pybind11_get_if_undef(_PYTHON_VALUES 3 PYTHON_SITE_PACKAGES) +_pybind11_get_if_undef(_PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION) +_pybind11_get_if_undef(_PYTHON_VALUES 5 PYTHON_IS_DEBUG) +_pybind11_get_if_undef(_PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P) +_pybind11_get_if_undef(_PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX) +_pybind11_get_if_undef(_PYTHON_VALUES 8 PYTHON_LIBDIR) +_pybind11_get_if_undef(_PYTHON_VALUES 9 PYTHON_MULTIARCH) # Make sure the Python has the same pointer-size as the chosen compiler # Skip if CMAKE_SIZEOF_VOID_P is not defined -if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}")) - if(PythonLibsNew_FIND_REQUIRED) - math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8") - math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8") - message(FATAL_ERROR - "Python config failure: Python is ${_PYTHON_BITS}-bit, " - "chosen compiler is ${_CMAKE_BITS}-bit") - endif() - set(PYTHONLIBS_FOUND FALSE) - return() +# This should be skipped for (non-Apple) cross-compiles (like EMSCRIPTEN) +if(NOT CMAKE_CROSSCOMPILING + AND CMAKE_SIZEOF_VOID_P + AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}")) + if(PythonLibsNew_FIND_REQUIRED) + math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8") + math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8") + message(FATAL_ERROR "Python config failure: Python is ${_PYTHON_BITS}-bit, " + "chosen compiler is ${_CMAKE_BITS}-bit") + endif() + set(PYTHONLIBS_FOUND FALSE) + set(PythonLibsNew_FOUND FALSE) + return() endif() # The built-in FindPython didn't always give the version numbers @@ -135,64 +201,87 @@ string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST}) list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR) list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR) list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH) +set(PYTHON_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}") # Make sure all directory separators are '/' -string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX ${PYTHON_PREFIX}) -string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR}) -string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES ${PYTHON_SITE_PACKAGES}) - -if(CMAKE_HOST_WIN32) - set(PYTHON_LIBRARY - "${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") - - # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the - # original python installation. They may be found relative to PYTHON_INCLUDE_DIR. - if(NOT EXISTS "${PYTHON_LIBRARY}") - get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY) - set(PYTHON_LIBRARY - "${_PYTHON_ROOT}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") - endif() +string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}") +string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") +string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") - # raise an error if the python libs are still not found. - if(NOT EXISTS "${PYTHON_LIBRARY}") - message(FATAL_ERROR "Python libraries not found") - endif() +if(DEFINED PYTHON_LIBRARY) + # Don't write to PYTHON_LIBRARY if it's already set +elseif(CMAKE_HOST_WIN32) + set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib") -else() + # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the + # original python installation. They may be found relative to PYTHON_INCLUDE_DIR. + if(NOT EXISTS "${PYTHON_LIBRARY}") + get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY) + set(PYTHON_LIBRARY "${_PYTHON_ROOT}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib") + endif() + + # if we are in MSYS & MINGW, and we didn't find windows python lib, look for system python lib + if(DEFINED ENV{MSYSTEM} + AND MINGW + AND NOT EXISTS "${PYTHON_LIBRARY}") if(PYTHON_MULTIARCH) - set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") else() - set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") - endif() - #message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}") - # Probably this needs to be more involved. It would be nice if the config - # information the python interpreter itself gave us were more complete. - find_library(PYTHON_LIBRARY - NAMES "python${PYTHON_LIBRARY_SUFFIX}" - PATHS ${_PYTHON_LIBS_SEARCH} - NO_DEFAULT_PATH) - - # If all else fails, just set the name/version and let the linker figure out the path. - if(NOT PYTHON_LIBRARY) - set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX}) + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") endif() + unset(PYTHON_LIBRARY) + find_library( + PYTHON_LIBRARY + NAMES "python${PYTHON_LIBRARY_SUFFIX}" + PATHS ${_PYTHON_LIBS_SEARCH} + NO_DEFAULT_PATH) + endif() + + # raise an error if the python libs are still not found. + if(NOT EXISTS "${PYTHON_LIBRARY}") + message(FATAL_ERROR "Python libraries not found") + endif() + +else() + if(PYTHON_MULTIARCH) + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") + else() + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") + endif() + #message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}") + # Probably this needs to be more involved. It would be nice if the config + # information the python interpreter itself gave us were more complete. + find_library( + PYTHON_LIBRARY + NAMES "python${PYTHON_LIBRARY_SUFFIX}" + PATHS ${_PYTHON_LIBS_SEARCH} + NO_DEFAULT_PATH) + + # If all else fails, just set the name/version and let the linker figure out the path. + if(NOT PYTHON_LIBRARY) + set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX}) + endif() endif() -MARK_AS_ADVANCED( - PYTHON_LIBRARY - PYTHON_INCLUDE_DIR -) +mark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_DIR) # We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the # cache entries because they are meant to specify the location of a single # library. We now set the variables listed by the documentation for this # module. -SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") -SET(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") -SET(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") +set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") +set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") +if(NOT PYTHON_DEBUG_LIBRARY) + set(PYTHON_DEBUG_LIBRARY "") +endif() +set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") -find_package_message(PYTHON - "Found PythonLibs: ${PYTHON_LIBRARY}" - "${PYTHON_EXECUTABLE}${PYTHON_VERSION}") +find_package_message(PYTHON "Found PythonLibs: ${PYTHON_LIBRARIES}" + "${PYTHON_EXECUTABLE}${PYTHON_VERSION_STRING}") set(PYTHONLIBS_FOUND TRUE) +set(PythonLibsNew_FOUND TRUE) + +if(NOT PYTHON_MODULE_PREFIX) + set(PYTHON_MODULE_PREFIX "") +endif() \ No newline at end of file diff --git a/pylegu/setup.py b/pylegu/setup.py index 912e5b0..ac41751 100644 --- a/pylegu/setup.py +++ b/pylegu/setup.py @@ -8,8 +8,9 @@ from pkg_resources import get_distribution from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext, copy_file +from setuptools.command.build_ext import build_ext +from distutils.file_util import copy_file from distutils.version import LooseVersion from distutils import log diff --git a/pylegu/third-party/pybind11-2.10.4.zip b/pylegu/third-party/pybind11-2.10.4.zip new file mode 100644 index 0000000..3bd245e Binary files /dev/null and b/pylegu/third-party/pybind11-2.10.4.zip differ diff --git a/pylegu/third-party/pybind11-2.4.3.zip b/pylegu/third-party/pybind11-2.4.3.zip deleted file mode 100644 index ab3cbd0..0000000 Binary files a/pylegu/third-party/pybind11-2.4.3.zip and /dev/null differ