mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-29 16:22:53 +00:00
cmake - build without Python libraries on Unix
This commit is contained in:
+12
-47
@@ -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}"
|
||||||
|
|||||||
@@ -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}")
|
||||||
|
|||||||
@@ -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]}')"
|
||||||
|
|||||||
Reference in New Issue
Block a user