cmake - build without Python libraries on Unix

This commit is contained in:
Andrej730
2025-10-23 12:21:11 +05:00
parent 5be1858767
commit c8a4f1bbd2
3 changed files with 23 additions and 58 deletions
+12 -47
View File
@@ -54,7 +54,7 @@ Used environment variables:
- ``USE_OCCT`` - whether to use official Open CASCADE instead of Community Edition - ``USE_OCCT`` - whether to use official Open CASCADE instead of Community Edition
(`true` by default, any other value is considered `false`) (`true` by default, any other value is considered `false`)
- ``WASM_PYTHON_PATH`` - path to WASM Python installation, - ``WASM_PYTHON_PATH`` - path to WASM Python installation,
used to deduce `PYMAJOR`, `PYMINOR`, `PYMICRO`, `TARGETINSTALLDIR`, `PYTHONINCLUDE`, used to deduce `PYVERSION` (e.g. '3.13.2'), `PYTHONINCLUDE`,
`SIDE_MODULE_CFLAGS`, `SIDE_MODULE_LDFLAGS`. `SIDE_MODULE_CFLAGS`, `SIDE_MODULE_LDFLAGS`.
Allows to build wasm without pyodide build environment, which can be useful for debugging build issues. Allows to build wasm without pyodide build environment, which can be useful for debugging build issues.
Example value: 'pyodide/cpython/installs/python-3.13.2' Example value: 'pyodide/cpython/installs/python-3.13.2'
@@ -216,14 +216,10 @@ if WASM:
wasm_python_path = os.environ["WASM_PYTHON_PATH"] wasm_python_path = os.environ["WASM_PYTHON_PATH"]
# Deduce version from path, assuming format .../python-X.Y.Z # Deduce version from path, assuming format .../python-X.Y.Z
version_match = re.search(r"python-(\d+)\.(\d+)\.(\d+)", wasm_python_path) version_match = re.search(r"python-(\d+)\.(\d+)\.(\d+)", wasm_python_path)
if version_match: assert version_match, f"Could not deduce python version from '{wasm_python_path}'"
os.environ["PYMAJOR"] = version_match.group(1) python_version = version_match.group(1)
os.environ["PYMINOR"] = version_match.group(2) os.environ["PYVERSION"] = python_version
os.environ["PYMICRO"] = version_match.group(3) os.environ["PYTHONINCLUDE"] = f"{wasm_python_path}/include/python{python_version.rpartition('.')[0]}"
os.environ["TARGETINSTALLDIR"] = wasm_python_path
os.environ["PYTHONINCLUDE"] = (
f"{wasm_python_path}/include/python{os.environ['PYMAJOR']}.{os.environ['PYMINOR']}"
)
os.environ["SIDE_MODULE_CFLAGS"] = "" os.environ["SIDE_MODULE_CFLAGS"] = ""
# Required, otherwise library will compile as .a, not .so. # Required, otherwise library will compile as .a, not .so.
os.environ["SIDE_MODULE_LDFLAGS"] = "-s SIDE_MODULE=1" os.environ["SIDE_MODULE_LDFLAGS"] = "-s SIDE_MODULE=1"
@@ -231,12 +227,8 @@ if WASM:
assert "WASM_TOOLCHAIN_FILE" in os.environ, "WASM_TOOLCHAIN_FILE must be set when WASM_PYTHON_PATH is provided" assert "WASM_TOOLCHAIN_FILE" in os.environ, "WASM_TOOLCHAIN_FILE must be set when WASM_PYTHON_PATH is provided"
WASM_DEBUG = True WASM_DEBUG = True
required_vars = ( required_vars = (
"PYMAJOR", # E.g. '3.13.2'.
"PYMINOR", "PYVERSION",
"PYMICRO",
# Folder where WASM-Python was installed.
# e.g '/pyodide/cpython/installs/python-3.13.2'.
"TARGETINSTALLDIR",
# 'include' folder in WASM-Python installation. # 'include' folder in WASM-Python installation.
# e.g. '/pyodide/cpython/installs/python-3.13.2/include/python3.13' # e.g. '/pyodide/cpython/installs/python-3.13.2/include/python3.13'
"PYTHONINCLUDE", "PYTHONINCLUDE",
@@ -1448,7 +1440,6 @@ if "IfcOpenShell-Python" in targets:
def compile_python_wrapper( def compile_python_wrapper(
python_version: str, python_version: str,
python_library: Union[str, None] = None,
python_include: Union[str, None] = None, python_include: Union[str, None] = None,
python_executable: Union[str, None] = None, python_executable: Union[str, None] = None,
python_path: Union[Path, None] = None, python_path: Union[Path, None] = None,
@@ -1456,7 +1447,7 @@ if "IfcOpenShell-Python" in targets:
""" """
:return: Path to module dir if ``python_executable`` was provided, otherwise ``None``. :return: Path to module dir if ``python_executable`` was provided, otherwise ``None``.
""" """
assert bool(python_path) ^ bool(python_library and python_include) assert bool(python_path) ^ bool(python_include)
logger.info(f"\rConfiguring python {python_version} wrapper...") logger.info(f"\rConfiguring python {python_version} wrapper...")
@@ -1469,7 +1460,7 @@ if "IfcOpenShell-Python" in targets:
prefix_paths.append(f"{DEPS_DIR}/install/swig") prefix_paths.append(f"{DEPS_DIR}/install/swig")
if python_path: if python_path:
# We couldn't just prefix PATH and have to provide all variables explicitly, # We couldn't just prefix PATH and have to provide all variables explicitly,
# see run-cmake.bat note for details. # see ifcwrap/cmake for the details.
python_executable = (Path(python_path) / "bin" / "python3").__str__() python_executable = (Path(python_path) / "bin" / "python3").__str__()
python_include = run( python_include = run(
[ [
@@ -1478,20 +1469,8 @@ if "IfcOpenShell-Python" in targets:
"import sysconfig; print(sysconfig.get_config_var('INCLUDEPY'))", "import sysconfig; print(sysconfig.get_config_var('INCLUDEPY'))",
] ]
) )
python_library = run(
[
python_executable,
"-c",
"import sysconfig, pathlib; "
"lib_dir = pathlib.Path(sysconfig.get_config_var('LIBDIR')); "
"print((lib_dir / sysconfig.get_config_var('LIBRARY')).__str__())",
]
)
if platform.system() == "Darwin":
# Oddly on Mac `LIBRARY` returns .a that doesn't even exists.
python_library = Path(python_library).with_suffix(".dylib").__str__()
assert python_library and python_include assert python_include
run_cmake( run_cmake(
"", "",
cmake_args cmake_args
@@ -1500,7 +1479,6 @@ if "IfcOpenShell-Python" in targets:
*([f"-DPYTHON_EXECUTABLE={python_executable}"] if python_executable else []), *([f"-DPYTHON_EXECUTABLE={python_executable}"] if python_executable else []),
# Needed because pyodide is expecting setup.py to be in the root. # Needed because pyodide is expecting setup.py to be in the root.
*([f"-DPYTHON_MODULE_INSTALL_DIR={REPO_PATH}"] * WASM), *([f"-DPYTHON_MODULE_INSTALL_DIR={REPO_PATH}"] * WASM),
f"-DPYTHON_LIBRARY={python_library}",
f"-DPYTHON_INCLUDE_DIR={python_include}", f"-DPYTHON_INCLUDE_DIR={python_include}",
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell/tmp", f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell/tmp",
"-DUSERSPACE_PYTHON_PREFIX=" "-DUSERSPACE_PYTHON_PREFIX="
@@ -1538,26 +1516,13 @@ if "IfcOpenShell-Python" in targets:
return module_dir return module_dir
if "wasm" in flags: if "wasm" in flags:
compile_python_wrapper( compile_python_wrapper(os.environ["PYVERSION"], os.environ["PYTHONINCLUDE"])
f"{os.environ['PYMAJOR']}.{os.environ['PYMINOR']}.{os.environ['PYMICRO']}",
f"{os.environ['TARGETINSTALLDIR']}/lib/libpython{os.environ['PYMAJOR']}.{os.environ['PYMINOR']}.a",
os.environ["PYTHONINCLUDE"],
None,
)
# Copy setup.py where pyodide build system expects it. # Copy setup.py where pyodide build system expects it.
shutil.copy(REPO_PATH / "pyodide" / "setup.py", REPO_PATH) shutil.copy(REPO_PATH / "pyodide" / "setup.py", REPO_PATH)
elif USE_CURRENT_PYTHON_VERSION: elif USE_CURRENT_PYTHON_VERSION:
python_info = sysconfig.get_paths() python_info = sysconfig.get_paths()
compile_python_wrapper(platform.python_version(), python_info["include"], sys.executable)
py_path_components = [sysconfig.get_config_var("LIBDIR"), sysconfig.get_config_var("INSTSONAME")]
if sysconfig.get_config_var("multiarchsubdir"):
py_path_components.insert(1, sysconfig.get_config_var("multiarchsubdir").replace("/", ""))
python_lib = os.path.join(*py_path_components)
compile_python_wrapper(platform.python_version(), python_lib, python_info["include"], sys.executable)
else: else:
for python_version in PYTHON_VERSIONS: for python_version in PYTHON_VERSIONS:
python_path = Path(DEPS_DIR) / "install" / f"python-{python_version}" python_path = Path(DEPS_DIR) / "install" / f"python-{python_version}"
+11 -7
View File
@@ -46,17 +46,20 @@ IF(NOT "${PYTHON_LIBRARY}" STREQUAL "")
MESSAGE(STATUS "Looking for Python library file in: ${Python_LIBRARY}") MESSAGE(STATUS "Looking for Python library file in: ${Python_LIBRARY}")
ENDIF() ENDIF()
# NOTE PYTHONLIBS_FOUND and PYTHONINTERP_FOUND cannot seem to be trusted so # Development.Module = headers on Unix, headers+libraries on Windows.
# we need further checks to see whether the packages were actually found or not. # Required variables:
FIND_PACKAGE(Python COMPONENTS Development) # - Windows - Python_INCLUDE_DIR, Python_LIBRARY (MSVC doesn't allow undefined symbols at link time)
IF(NOT Python_Development_FOUND) # - Unix - Python_INCLUDE_DIR
# Unfortunately all paths must be always provided explicitly, not by prefixing PATH.
# Otherwise FindPython will break on newer Python versions (list of supported versions is hardcoded).
find_package(Python COMPONENTS Development.Module)
IF(NOT Python_Development.Module_FOUND)
MESSAGE(FATAL_ERROR "BUILD_IFCPYTHON enabled, but unable to find Python lib or header. Disable BUILD_IFCPYTHON or fix Python paths to proceed.") MESSAGE(FATAL_ERROR "BUILD_IFCPYTHON enabled, but unable to find Python lib or header. Disable BUILD_IFCPYTHON or fix Python paths to proceed.")
ENDIF() ENDIF()
# Ensure version is saved here, from wasm libraries, # Ensure version is saved here, from wasm libraries,
# not from Python interpreter that might be unrelated to pyodide Python version. # not from Python interpreter that might be unrelated to pyodide Python version.
set(_python_libs_version "${Python_VERSION_MAJOR}${Python_VERSION_MINOR}") set(_python_libs_version "${Python_VERSION_MAJOR}${Python_VERSION_MINOR}")
INCLUDE_DIRECTORIES(${Python_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_SWIG_FLAGS ${SWIG_DEFINES}) SET(CMAKE_SWIG_FLAGS ${SWIG_DEFINES})
@@ -90,6 +93,7 @@ SET_PROPERTY(
set(SWIG_MODULE_ifcopenshell_wrapper_EXTRA_FLAGS "-interface" "_ifcopenshell_wrapper") set(SWIG_MODULE_ifcopenshell_wrapper_EXTRA_FLAGS "-interface" "_ifcopenshell_wrapper")
swig_add_library(ifcopenshell_wrapper LANGUAGE python SOURCES IfcPython.i) swig_add_library(ifcopenshell_wrapper LANGUAGE python SOURCES IfcPython.i)
swig_link_libraries(ifcopenshell_wrapper PRIVATE Python::Module)
SET_PROPERTY(TARGET ${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} PROPERTY SWIG_DEPENDS ${IFCOPENSHELL_LIBRARIES}) SET_PROPERTY(TARGET ${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} PROPERTY SWIG_DEPENDS ${IFCOPENSHELL_LIBRARIES})
if (WASM_BUILD) if (WASM_BUILD)
# SIDE_MODULE=1 - add to .so all symbols from linked archives (default used by pyodide). # SIDE_MODULE=1 - add to .so all symbols from linked archives (default used by pyodide).
@@ -113,9 +117,9 @@ if (WASM_BUILD)
endif() endif()
if("$ENV{LDFLAGS}" MATCHES ".undefined.suppress") 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. # 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}) swig_link_libraries(ifcopenshell_wrapper PRIVATE ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${LIBSVGFILL})
else() else()
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${Python_LIBRARIES} ${LIBSVGFILL}) swig_link_libraries(ifcopenshell_wrapper PRIVATE ${IFCOPENSHELL_LIBRARIES} ${LIBSVGFILL})
endif() endif()
if ((NOT WIN32) AND BUILD_SHARED_LIBS) if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} "${IFCDIRS};${OCC_LIBRARY_DIR}") SET_INSTALL_RPATHS(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} "${IFCDIRS};${OCC_LIBRARY_DIR}")
-4
View File
@@ -92,10 +92,6 @@ set LIBXML2_INCLUDE_DIR=%DEPS_DIR%\OpenCOLLADA\Externals\LibXML\include
set LIBXML2_LIBRARIES=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada\xml.lib set LIBXML2_LIBRARIES=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada\xml.lib
set HDF5_INSTALL_DIR=%INSTALL_DIR%\HDF5-%HDF5_VERSION%-win%ARCH_BITS% set HDF5_INSTALL_DIR=%INSTALL_DIR%\HDF5-%HDF5_VERSION%-win%ARCH_BITS%
:: 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 set PYTHON_EXECUTABLE=%PYTHONHOME%\python.exe
for /f "usebackq delims=" %%v in (` for /f "usebackq delims=" %%v in (`
call "%PYTHON_EXECUTABLE%" -c "import sys; print(f'{sys.version_info[0]}{sys.version_info[1]}')" call "%PYTHON_EXECUTABLE%" -c "import sys; print(f'{sys.version_info[0]}{sys.version_info[1]}')"