diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index e4930c5471..a23f9bc0ff 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -212,6 +212,8 @@ if(NOT MINIMAL_BUILD) UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES) UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) + UNIFY_ENVVARS_AND_CACHE(PYTHON_INCLUDE_DIR) + UNIFY_ENVVARS_AND_CACHE(PYTHON_LIBRARY) UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR) diff --git a/src/ifcwrap/CMakeLists.txt b/src/ifcwrap/CMakeLists.txt index 71346ec27b..073b31d9d7 100644 --- a/src/ifcwrap/CMakeLists.txt +++ b/src/ifcwrap/CMakeLists.txt @@ -35,23 +35,25 @@ ENDIF() include(GNUInstallDirs) INCLUDE(${SWIG_USE_FILE}) -IF(NOT "$ENV{PYTHON_INCLUDE_DIR}" STREQUAL "") - SET(PYTHON_INCLUDE_DIR $ENV{PYTHON_INCLUDE_DIR} CACHE FILEPATH "Python header files") - MESSAGE(STATUS "Looking for Python header files in: ${PYTHON_INCLUDE_DIR}") +IF(NOT "${PYTHON_INCLUDE_DIR}" STREQUAL "") + # Hint for FindPython where to find Python_INCLUDE_DIRS. + set(Python_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") + MESSAGE(STATUS "Looking for Python header files in: ${Python_INCLUDE_DIR}") ENDIF() -IF(NOT "$ENV{PYTHON_LIBRARY}" STREQUAL "") - SET(PYTHON_LIBRARY $ENV{PYTHON_LIBRARY} CACHE FILEPATH "Python library file") - MESSAGE(STATUS "Looking for Python library file in: ${PYTHON_LIBRARY}") +IF(NOT "${PYTHON_LIBRARY}" STREQUAL "") + # Hint for FindPython where to find Python_LIBRARIES. + set(Python_LIBRARY "${PYTHON_LIBRARY}") + MESSAGE(STATUS "Looking for Python library file in: ${Python_LIBRARY}") ENDIF() # NOTE PYTHONLIBS_FOUND and PYTHONINTERP_FOUND cannot seem to be trusted so # we need further checks to see whether the packages were actually found or not. -FIND_PACKAGE(PythonLibs) -IF(NOT PYTHONLIBS_FOUND OR "$PYTHON_INCLUDE_DIRS}" STREQUAL "") +FIND_PACKAGE(Python COMPONENTS Development) +IF(NOT Python_Development_FOUND) MESSAGE(FATAL_ERROR "BUILD_IFCPYTHON enabled, but unable to find Python lib or header. Disable BUILD_IFCPYTHON or fix Python paths to proceed.") ENDIF() -INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${Python_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) SET(CMAKE_SWIG_FLAGS ${SWIG_DEFINES}) @@ -90,7 +92,7 @@ if("$ENV{LDFLAGS}" MATCHES ".undefined.suppress") # On osx there is some state in the python dylib. With `-Wl,undefined,suppress` we can ignore the missing symbols at compile time. SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${LIBSVGFILL}) else() -SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES} ${LIBSVGFILL}) +SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${Python_LIBRARIES} ${LIBSVGFILL}) endif() if ((NOT WIN32) AND BUILD_SHARED_LIBS) SET_INSTALL_RPATHS(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} "${IFCDIRS};${OCC_LIBRARY_DIR}") @@ -98,17 +100,21 @@ endif() # Try to find the Python interpreter to get the site-packages # directory in which the wrapper can be installed. -FIND_PACKAGE(PythonInterp) -IF((PYTHONINTERP_FOUND AND NOT "${PYTHON_EXECUTABLE}" STREQUAL "") OR PYTHON_MODULE_INSTALL_DIR) +if(NOT ${PYTHON_EXECUTABLE} STREQUAL "") + set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}") + MESSAGE(STATUS "Looking for Python interpreter in: ${PYTHON_EXECUTABLE}") +endif() +FIND_PACKAGE(Python COMPONENTS Interpreter) +IF(Python_Interpreter_FOUND OR PYTHON_MODULE_INSTALL_DIR) if (NOT WASM_BUILD) - # Find Python interpreter and get its version # Not on WASM because we're cross compiling in that case - EXECUTE_PROCESS( - COMMAND ${PYTHON_EXECUTABLE} -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))" - OUTPUT_VARIABLE PYTHON_EXTENSION_SUFFIX - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - + # + # Python_SOABI example value is 'cp311-win_amd64'. + if(WIN32) + set(PYTHON_EXTENSION_SUFFIX ".${Python_SOABI}.pyd") + else() + set(PYTHON_EXTENSION_SUFFIX ".${Python_SOABI}.so") + endif() # On Windows there is '_d' prefix for debug builds - e.g. `_d.cp311-win_amd64.pyd`. if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set_target_properties( @@ -133,10 +139,7 @@ IF((PYTHONINTERP_FOUND AND NOT "${PYTHON_EXECUTABLE}" STREQUAL "") OR PYTHON_MOD OUTPUT_VARIABLE python_package_dir ) ELSE () - EXECUTE_PROCESS( - COMMAND ${PYTHON_EXECUTABLE} -c "import sys; import sysconfig; sys.stdout.write(sysconfig.get_path('platlib'))" - OUTPUT_VARIABLE python_package_dir - ) + set(python_package_dir "${Python_SITEARCH}") ENDIF() if (BUILD_PACKAGE) set(python_package_dir ${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION_MAJOR}/dist-packages/) @@ -145,6 +148,7 @@ IF((PYTHONINTERP_FOUND AND NOT "${PYTHON_EXECUTABLE}" STREQUAL "") OR PYTHON_MOD IF("${python_package_dir}" STREQUAL "") MESSAGE(WARNING "Unable to locate Python site-package directory, unable to install the Python wrapper") ELSE() + message(STATUS "Python wrapper will be installed to '${python_package_dir}'.") FILE(GLOB_RECURSE sourcefiles "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/*" ) diff --git a/win/build-deps.cmd b/win/build-deps.cmd index 68801a4095..50b5b7dd6a 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -147,6 +147,8 @@ echo Defaults to Build if not specified. call cecho.cmd 0 13 "* IFCOS_INSTALL_PYTHON`t= %IFCOS_INSTALL_PYTHON%" echo - Download and install Python. echo Set to something other than TRUE if you wish to use an already installed version of Python. +echo But then you'll need to set PYTHONHOME env variable to your Python installation before running run-cmake.bat +echo to your Python installation path. call cecho.cmd 0 13 "* IFCOS_NUM_BUILD_PROCS`t= %IFCOS_NUM_BUILD_PROCS%" echo - How many MSBuild.exe processes may be run in parallel. echo Defaults to NUMBER_OF_PROCESSORS. Used also by other IfcOpenShell build scripts. @@ -174,7 +176,6 @@ cd "%DEPS_DIR%" :: Don't use HDF5 1.13.0, because it has a broken cmake package path. set HDF5_VERSION=1_13_1 set OCCT_VERSION=7.8.1 -:: NOTE If updating the default Python version, change PY_VER_MAJOR_MINOR accordingly in run-cmake.bat IF DEFINED PYTHON_VERSION ( echo Using overridden PYTHON_VERSION: '%PYTHON_VERSION%' ) else ( @@ -184,10 +185,6 @@ IF DEFINED PYTHON_VERSION ( :: VERSION DERIVATIONS set OCC_INCLUDE_DIR=%INSTALL_DIR%\opencascade-%OCCT_VERSION%\inc>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" set OCC_LIBRARY_DIR=%INSTALL_DIR%\opencascade-%OCCT_VERSION%\win%ARCH_BITS%\lib>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" -:: '3.11.7' -> '311' -for /f "tokens=1,2,3 delims=." %%a in ("%PYTHON_VERSION%") do ( - set PY_VER_MAJOR_MINOR=%%a%%b -) IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( set PYTHONHOME=%DEPS_DIR%\python.%PYTHON_VERSION%\tools ) @@ -200,7 +197,6 @@ echo HDF5_VERSION=%HDF5_VERSION%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" echo OCC_INCLUDE_DIR=%OCC_INCLUDE_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" echo OCC_LIBRARY_DIR=%OCC_LIBRARY_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( - echo PY_VER_MAJOR_MINOR=%PY_VER_MAJOR_MINOR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" echo PYTHONHOME=%PYTHONHOME%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" ) diff --git a/win/run-cmake.bat b/win/run-cmake.bat index 30eadd71f5..67de595de5 100755 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -91,13 +91,19 @@ set OPENCOLLADA_INSTALL_DIR=%INSTALL_DIR%\OpenCOLLADA set LIBXML2_INCLUDE_DIR=%DEPS_DIR%\OpenCOLLADA\Externals\LibXML\include set LIBXML2_LIBRARIES=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada\xml.lib set HDF5_INSTALL_DIR=%INSTALL_DIR%\HDF5-%HDF5_VERSION%-win%ARCH_BITS% -if not defined PY_VER_MAJOR_MINOR set PY_VER_MAJOR_MINOR=311 -if not defined PYTHONHOME set PYTHONHOME=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% + +:: Unfortunately we have to provide all 3 paths explicitly, +:: because if just prefix PATH, then FindPython will have an issue with newer versions of Python. +:: E.g. older FindPython that didn't s added explicit support for Python 3.14 will fail to find. +:: So setting paths expliicitly is more robust. +set PYTHON_EXECUTABLE=%PYTHONHOME%\python.exe +for /f "usebackq delims=" %%v in (` + call "%PYTHON_EXECUTABLE%" -c "import sys; print(f'{sys.version_info[0]}{sys.version_info[1]}')" +`) do set "PY_VER_MAJOR_MINOR=%%v" set PYTHON_INCLUDE_DIR=%PYTHONHOME%\include set PYTHON_LIBRARY=%PYTHONHOME%\libs\python%PY_VER_MAJOR_MINOR%.lib -set PYTHON_EXECUTABLE=%PYTHONHOME%\python.exe + set SWIG_INSTALL_DIR=%INSTALL_DIR%\swigwin -set PATH=%PATH%;%PYTHONHOME% set JSON_INCLUDE_DIR=%INSTALL_DIR%\json if not defined ADD_COMMIT_SHA set ADD_COMMIT_SHA=Off