Compare commits

...

20 Commits

Author SHA1 Message Date
Andrej730 ccd123d4c6 build_rocky: try --occt-shared 2026-08-27 19:20:39 +05:00
Andrej730 3a67602bd2 IfcParseExamples: fix gcc warning about not covered enum cases 2026-08-27 19:19:11 +05:00
Andrej730 2a9786bac2 package-zip-archives: --occt-shared
Packing OCCT shared libraries, seems to work. Though still got to do a test in CI before implementing `--shared`.
2026-08-27 18:48:58 +05:00
Andrej730 df31069743 package-zip-archives: target patching and checking more precisely
E.g. to ensure patching of qt libraries is not covering up issues with other runtime libraries.
2026-08-27 18:48:58 +05:00
Andrej730 48eddeec01 package-zip-archives: patch rpath for all runtime libs, not just qt
Unsure if it's required, but just to be safe and to avoid warnings showing up during `check_runtime_dependencies`.
2026-08-27 18:48:58 +05:00
Andrej730 453bf9b8e8 package-zip-archives: add libs to ignore during check_runtime_dependencies 2026-08-27 18:48:58 +05:00
Andrej730 705aacf659 package-zip-archives: check runtime deps for python wrapper too 2026-08-27 18:48:58 +05:00
Andrej730 94fa2dea42 package-zip-archives: make python wrapper packaging rerunnable
Now we have temporary staging area and each run works exactly the same, without affecting actuall installation.
2026-08-27 17:56:15 +05:00
Andrej730 57f0f89993 remove_tr1.patch: add a note 2026-08-27 17:07:35 +05:00
Andrej730 ab8567fdca build-deps: point to the existing remove_tr1.patch
Tested that it applies cleanly even though commit is outdated.
2026-08-27 17:07:21 +05:00
Andrej730 57eb5f474e build-all: always apply tr1 removal patch
Just to use consistent patches between the builds. It was previously guarded by `WASM`, but it was a dead code - `OpenCOLLADA` is skipped on wasm, so it was never exercised.

Regarding the "specializing std::hash outside of the std:: namespace" issue on gcc - it was caused by patch missing fixes for `COLLADABU_HASH_NAMESPACE_OPEN` and `COLLADABU_HASH_NAMESPACE_CLOSE`. So in theory it should have also result in an error in clang or in an invalid code/ub. Either way, now it's fixed.
2026-08-27 17:07:11 +05:00
Andrej730 ec0e0ab3ff run-cmake.bat: revert special handling for USE_CCACHE
Since it's part of normal cmake options and no need to alter PATH to disable ccache.
2026-08-27 16:54:01 +05:00
Andrej730 25ffdc3943 cmake: adjust ccache messages given ut's now optional 2026-08-27 16:54:01 +05:00
Andrej730 147c87a7be cmake: move USE_CCACHE closer to other options 2026-08-27 16:54:01 +05:00
Andrej730 3251c1b225 Enable ccache explicitly for builds #9359
Since it's now off by default
2026-08-27 16:54:01 +05:00
Andrej730 d2da2988a4 cmake: fix buidling using rocksdb built as RelWithDebInfo #9359
See logs below for example issue I've met locally when I had just `RocksDBTargets-relwithdebinfo.cmake`.
Providing a list of configs makes it try to use matching config first and only then try `Release` as a fallback, otherwise it was now requiring `Release` builds.

```
CMake Error in CMakeLists.txt:
  IMPORTED_LOCATION not set for imported target "RocksDB::rocksdb"
  configuration "RelWithDebInfo".
```
2026-08-27 16:54:01 +05:00
Andrej730 5903c3c895 Normalize whitespaces in yml files 2026-08-27 16:54:01 +05:00
Andrej730 028497d4c0 package-zip-archives: use logger to control logs verbosity 2026-08-27 10:26:06 +05:00
Andrej730 b6b8d27f53 package-zip-archives: fix using wrong pattern for detecting SONAME
See example below - `Shared library` is used to declarate dependency, `Library soname` is used to declare `SONAME`.
```
 0x0000000000000001 (NEEDED)             Shared library: [libifcopenshell.plugin.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x000000000000000e (SONAME)             Library soname: [libifcopenshell.parse.so]
```
2026-08-27 10:26:06 +05:00
Richard Brice 3b908aff79 Guard get_style() against non-IfcMaterial material sets lacking HasRepresentation 2026-08-26 09:14:44 -07:00
20 changed files with 214 additions and 137 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ body:
label: Bug Description
placeholder: |
Describe what problem occurred and what you expected to happen instead.
1. To reproduce this, open file '...'
2. Click on '....'
3. See error
+1
View File
@@ -286,6 +286,7 @@ PATTERNS = (
"*.i",
"*.cmake",
"*/CMakeLists.txt",
"*.yml",
)
REPO_ROOT = Path(subprocess.check_output(["git", "rev-parse", "--show-toplevel"], text=True).strip())
+2 -2
View File
@@ -80,7 +80,7 @@ jobs:
set -o pipefail
CXXFLAGS="-O3" CFLAGS="-O3" ADD_COMMIT_SHA=1 BUILD_CFG=Release BUILD_BONSAIVIEWER=ON \
uv run --with aqtinstall ./nix/build-all.py \
-v --diskcleanup --ifcopenshell-shared 2>&1 \
-v --diskcleanup --ifcopenshell-shared --occt-shared 2>&1 \
| tee build.log
- name: Upload Build Logs
@@ -110,7 +110,7 @@ jobs:
- name: Package .zip archives
shell: bash
run: |
uv run nix/package-zip-archives.py linux64
uv run nix/package-zip-archives.py linux64 --occt-shared
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
@@ -34,21 +34,21 @@ jobs:
- name: Run conda cleaner
run: |
python - << EOF
import os
from datetime import datetime, timedelta
from binstar_client.utils import get_server_api
from binstar_client.errors import BinstarError
# Configuration
api_token = os.environ.get('ANACONDA_TOKEN')
pkg_name = 'ifcopenshell'
channel_name = 'ifcopenshell'
# Authenticate with Anaconda
aserver_api = get_server_api(token=api_token)
# Get the list of packages in the channel
def get_package(filter_package_name: str = None):
try:
@@ -59,12 +59,12 @@ jobs:
print(f"No packages found for {filter_package_name}.")
if len(user_packages) > 1:
raise ValueError(f"Found {len(user_packages)} package for {filter_package_name}. Will only support 1 package.")
return user_packages[0]
except BinstarError as err:
raise ValueError(f"Failed to fetch packages: {err}")
# Delete a package version
def delete_package(package_name, version):
try:
@@ -72,33 +72,33 @@ jobs:
print(f"Deleted {package_name} version {version}")
except BinstarError as err:
print(f"Failed to delete {package_name} version {version}: {err}")
# Main logic
def main():
package = get_package(pkg_name)
if not package:
print("No packages found.")
return
number_of_supported_versions = ${{ env.NUM_SUPPORTED_VERSIONS }}
package_name = package['name']
versions = package["versions"]
if len(versions) <= number_of_supported_versions:
print(f"Number of versions {len(versions)} is less than or equal to {number_of_supported_versions}.")
return
# sort the versions in descending order
print(f"Before reversal: {versions=}")
versions.reverse()
print(f"After reversal: {versions=}")
releases = versions[number_of_supported_versions:]
for release in releases:
delete_package(package_name, release)
main()
EOF
@@ -24,13 +24,13 @@ jobs:
- uses: actions/checkout@v7
- name: Set env
run: echo ok go
- name: Get current version
id: version
# Strip any trailing prerelease label and number; the dated alpha
# suffix is added below.
run: echo "version=$(sed -E 's/[[:alpha:]]+[0-9]+$//' VERSION)" >> $GITHUB_OUTPUT
- name: Get current date
id: date
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
@@ -39,7 +39,7 @@ jobs:
id: verdate
run: echo "verdate=${{ steps.version.outputs.version }}alpha${{ steps.date.outputs.date }}" >> $GITHUB_OUTPUT
test:
name: ${{ matrix.platform.distver }}-${{ matrix.pyver.name }}
needs: activate
@@ -64,7 +64,7 @@ jobs:
uses: pierotofy/set-swap-space@master
with:
swap-size-gb: 10
- name: set ARTIFACTS ENV vars
shell: bash
run: |
@@ -76,7 +76,7 @@ jobs:
elif [[ "$RUNNER_OS" == "Linux" ]]; then
echo "ARTIFACTS_DIR=/home/runner/work/artifacts" >> $GITHUB_ENV
fi
- uses: actions/checkout@v7
with:
submodules: recursive
+12 -11
View File
@@ -1,6 +1,6 @@
name: ci-ifcopenshell-docker
on:
on:
workflow_dispatch:
push:
tags:
@@ -37,13 +37,14 @@ jobs:
name: ccache
uses: hendrikmuhs/ccache-action@v1.2.23
-
-
name: Build ifcopenshell
run: |
mkdir build && cd build
cmake \
-DCMAKE_INSTALL_PREFIX=$PWD/install/ \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_CCACHE=ON \
-DCMAKE_PREFIX_PATH=/usr \
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
-DBUILD_PACKAGE=On \
@@ -66,12 +67,12 @@ jobs:
../cmake
make -j $(nproc)
make install
-
-
name: Package
run: |
make package
working-directory: build
- name: Upload
- name: Upload
uses: actions/upload-artifact@v7
with:
# Artifact name
@@ -88,8 +89,8 @@ jobs:
- uses: actions/checkout@v7
with:
lfs: true
- name: Download
- name: Download
uses: actions/download-artifact@v8.0.1
with:
# Artifact name
@@ -100,17 +101,17 @@ jobs:
uses: docker/setup-qemu-action@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
-
uses: docker/setup-buildx-action@v4
-
name: Login to Dockerhub
uses: docker/login-action@v4
uses: docker/login-action@v4
with:
username: aecgeeks
password: ${{ secrets.DOCKER_HUB_TOKEN }}
-
-
name: Build container image
uses: docker/build-push-action@v7
with:
with:
context: artifacts
repository: aecgeeks/ifcopenshell
# Since the dispatch is set to `tag`, `github.ref_name` should evaluate to the pushed tag
+4 -3
View File
@@ -84,7 +84,7 @@ jobs:
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
${OCCT_CMAKE_DEPS} \
libcgal-dev libeigen3-dev
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.23
with:
@@ -176,7 +176,7 @@ jobs:
run: |
echo $Python3_ROOT_DIR
echo ${{ env.pythonLocation }}
mkdir build && cd build
cmake \
-DCMAKE_BUILD_TYPE=Release \
@@ -185,6 +185,7 @@ jobs:
-DPYTHON_EXECUTABLE:FILEPATH=${{ env.pythonLocation }}/bin/python \
-DPYTHON_INCLUDE_DIR:PATH=${{ env.pythonLocation }}/include/python3.11 \
-DUSE_MMAP=On \
-DUSE_CCACHE=ON \
-DBUILD_SHARED_LIBS=${{ matrix.build_shared_libs }} \
"-DSCHEMA_VERSIONS=2x3;4;4x3_add2" \
-DGLTF_SUPPORT=On \
@@ -223,7 +224,7 @@ jobs:
cmake --build .
./IfcOpenHouse && test -f IfcOpenHouse.ifc
./IfcParseExamples IfcOpenHouse.ifc
./IfcAdvancedHouse && test -f IfcAdvancedHouse.ifc
./IfcAdvancedHouse && test -f IfcAdvancedHouse.ifc
./IfcAlignment && test -f FHWA_Bridge_Geometry_Alignment_Example.ifc
./IfcSimplifiedAlignment && test -f FHWA_Bridge_Geometry_Alignment_Example_Simplified.ifc
@@ -35,4 +35,4 @@ jobs:
external_repository: IfcOpenShell/bonsaibim_org_docs_unstable # Target repository
publish_branch: main # Branch to deploy to
cname: docs-unstable.bonsaibim.org # Custom domain for unstable docs
publish_dir: src/bonsai/docs/_build/html # Directory containing built docs
publish_dir: src/bonsai/docs/_build/html # Directory containing built docs
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Set env
run: echo ok go
build:
needs: activate
runs-on: ubuntu-latest
+4 -4
View File
@@ -37,7 +37,7 @@ jobs:
libtbb-dev nlohmann-json3-dev \
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
libcgal-dev opencollada-dev
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -77,7 +77,7 @@ jobs:
echo ::set-output name=deb::$( ls assets/*.deb | head -n 1 | xargs basename )
working-directory: build
env:
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release
id: release
uses: actions/create-release@v1
@@ -101,7 +101,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/assets/${{ steps.package.outputs.tgz }}
asset_name: ${{ steps.package.outputs.tgz }}
asset_content_type: application/x-gzip
@@ -111,7 +111,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/assets/${{ steps.package.outputs.deb }}
asset_name: ${{ steps.package.outputs.deb }}
asset_content_type: application/vnd.debian.binary-package
+5 -5
View File
@@ -134,6 +134,7 @@ option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only ins
option(USE_DEBUG_PYTHON "Use debug binaries when building Debug IfcPython on Windows." OFF)
option(ADD_COMMIT_SHA "Add commit sha and branch in version number, requires git" OFF)
option(VERSION_OVERRIDE "Use VERSION as the branch label when commit information is embedded" OFF)
option(USE_CCACHE "Use ccache as a compiler launcher if it is found" OFF)
set(
PYTHON_MODULE_INSTALL_DIR
@@ -178,11 +179,10 @@ if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM)
set(BUILD_IFCGEOM ON)
endif()
option(USE_CCACHE "Use ccache as a compiler launcher if it is found" OFF)
if(USE_CCACHE)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
message(STATUS "`ccache` is found, using it as a compiler launcher.")
message(STATUS "`USE_CCACHE` is enabled and `ccache` is found, using it as a compiler launcher.")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
if(MSVC)
# By default Visual Studio generators will use /Zi which is not compatible
@@ -202,7 +202,7 @@ if(USE_CCACHE)
endif()
endif()
else()
message(STATUS "ccache usage disabled via USE_CCACHE=OFF")
message(STATUS "ccache usage is disabled, set `USE_CCACHE=ON` to enable it.")
endif()
if(MSVC AND MSVC_PARALLEL_BUILD)
@@ -331,8 +331,8 @@ if (WITH_ROCKSDB)
# /MDd-flavored rocksdb_d.lib into an /MD (NDEBUG) binary, causing a CRT/runtime-library
# mismatch that depends on nothing but that alphabetical ordering.
set_target_properties(${IFCOPENSHELL_ROCKSDB_IMPORTED_TARGET} PROPERTIES
MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE
MAP_IMPORTED_CONFIG_MINSIZEREL RELEASE
MAP_IMPORTED_CONFIG_RELWITHDEBINFO "RELWITHDEBINFO;RELEASE"
MAP_IMPORTED_CONFIG_MINSIZEREL "MINSIZEREL;RELEASE"
)
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE ${IFCOPENSHELL_ROCKSDB_IMPORTED_TARGET})
+2 -7
View File
@@ -1285,13 +1285,7 @@ if "OpenCOLLADA" in targets:
# OpenCOLLADAConfig.cmake.in hardcodes shared-lib targets on Unix regardless of
# whether shared libs were actually built. We make it follow `USE_SHARED` instead.
patches.append("./patches/opencollada/config_select_libs_by_use_shared.patch")
if WASM:
# This is necessary for the WASM build, because recent versions of
# clang don't have the tr1:: namespace anymore. However, it breaks
# some versions of gcc (9.4.0 at least) due to specializing std::hash
# outside of the std:: namespace.
patches.append("./patches/opencollada/remove_tr1.patch")
patches.append("./patches/opencollada/remove_tr1.patch")
build_dependency(
"OpenCOLLADA",
@@ -1701,6 +1695,7 @@ ifcos_build_args = [
f"-DBUILD_CONVERT={OFF_ON['IfcConvert' in targets]}",
f"-DBUILD_BONSAIVIEWER={OFF_ON['BonsaiViewer' in targets]}",
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell",
"-DUSE_CCACHE=ON",
]
if not WASM and (
+131 -37
View File
@@ -3,6 +3,7 @@
# ///
import argparse
import logging
import os
import platform
import re
@@ -10,22 +11,41 @@ import shlex
import shutil
import subprocess
from pathlib import Path
from typing import Literal
from typing import Literal, NamedTuple
class C:
GREY = "\033[90m"
YELLOW = "\033[33m"
RED = "\033[31m"
RESET = "\033[0m"
class ColorFormatter(logging.Formatter):
COLORS = {
logging.DEBUG: C.GREY,
logging.WARNING: C.YELLOW,
logging.ERROR: C.RED,
}
def format(self, record: logging.LogRecord) -> str:
color = self.COLORS.get(record.levelno, C.RESET)
return f"{color}{super().format(record)}{C.RESET}"
handler = logging.StreamHandler()
handler.setFormatter(ColorFormatter("%(message)s"))
logging.basicConfig(level=logging.INFO, handlers=[handler])
logger = logging.getLogger(__name__)
def run(
*cmd: str,
cwd: Path | None = None,
env: dict[str, str] | None = None,
stderr: int | None = None,
) -> str:
print(f"{C.GREY}$ {shlex.join(cmd)}{C.RESET}")
logger.debug(f"$ {shlex.join(cmd)}")
return subprocess.check_output(cmd, cwd=cwd, env=env, stderr=stderr, text=True)
@@ -63,21 +83,27 @@ def find_qt_dir(install_root: Path, qt6_version: str) -> Path | None:
return None
def ensure_soname_links(dest: Path) -> None:
"""Ensure that all shared libraries in `dest` are present using their SONAMEs (at least as symlinks)."""
for shared_object in dest.glob("*.so*"):
def find_occt_dir(install_root: Path) -> Path:
candidates = [candidate for candidate in install_root.glob("occt-shared-*") if candidate.is_dir()]
if len(candidates) != 1:
raise Exception(f"Expected exactly one OCCT shared candidate, found: {candidates}")
return candidates[0]
def ensure_soname_links(paths: list[Path]) -> None:
"""Ensure that all shared libraries in `paths` are present using their SONAMEs (at least as symlinks)."""
for shared_object in paths:
if not shared_object.is_file():
continue
try:
readelf_output = run("readelf", "-d", str(shared_object))
except subprocess.CalledProcessError:
continue
# TODO: actual pattern is "Library soname" instead of "Shared library"?
match = re.search(r"\(SONAME\).*Shared library: \[(.*)\]", readelf_output)
match = re.search(r"\(SONAME\).*Library soname: \[(.*)\]", readelf_output)
if not match:
continue
soname = match.group(1)
soname_path = dest / soname
soname_path = shared_object.parent / soname
if soname_path.exists():
continue
soname_path.symlink_to(shared_object.name)
@@ -88,10 +114,11 @@ def is_shared_library(path: Path) -> bool:
return name.endswith((".so", ".dylib", ".dll")) or ".so." in name
def stage_runtime_payload(ifcopenshell_install_dir: Path, dest: Path, *, include_geometry_writers: bool = True) -> None:
"""Copy all libs from `ifcopenshell_install_dir/{bin,lib,lib64}` into `dest`."""
def stage_runtime_payload(install_dir: Path, dest: Path, *, include_geometry_writers: bool = True) -> None:
"""Copy all libs from `install_dir/{bin,lib,lib64}` into `dest`."""
runtime_files = []
for runtime_dir_name in ("bin", "lib", "lib64"):
runtime_dir = ifcopenshell_install_dir / runtime_dir_name
runtime_dir = install_dir / runtime_dir_name
if not runtime_dir.is_dir():
continue
for runtime_file in runtime_dir.rglob("*"):
@@ -101,9 +128,15 @@ def stage_runtime_payload(ifcopenshell_install_dir: Path, dest: Path, *, include
continue
if not include_geometry_writers and runtime_file.name.startswith("ifcopenshell.geometry.writer."):
continue
shutil.copy(runtime_file, dest / runtime_file.name, follow_symlinks=False)
dest_file = dest / runtime_file.name
shutil.copy(runtime_file, dest_file, follow_symlinks=False)
runtime_files.append(dest_file)
if not is_platform("MAC"):
ensure_soname_links(dest)
ensure_soname_links(runtime_files)
for lib_so in runtime_files:
if lib_so.is_file():
run("patchelf", "--set-rpath", "$ORIGIN", str(lib_so))
def stage_qt_runtime_payload(exe_path: Path, dest: Path, qt_dir: Path | None) -> None:
@@ -126,16 +159,18 @@ def stage_qt_runtime_payload(exe_path: Path, dest: Path, qt_dir: Path | None) ->
return
# Copy all QT libs to `dest`.
qt_lib_files = []
for lib_file in (qt_dir / "lib").iterdir():
if is_so_file(lib_file):
dest_file = dest / lib_file.name
qt_lib_files.append(dest_file)
# Currently we install some qt libs to `install/ifcopenshell/lib` too,
# so there's a bit of overlap beteen stage_runtime and stage_qt_runtime,
# hence the skip.
if dest_file.exists():
continue
shutil.copy(lib_file, dest_file, follow_symlinks=False)
ensure_soname_links(dest)
ensure_soname_links(qt_lib_files)
# Copy QT plugins.
plugins_dir = qt_dir / "plugins"
@@ -155,7 +190,7 @@ def stage_qt_runtime_payload(exe_path: Path, dest: Path, qt_dir: Path | None) ->
run("patchelf", "--set-rpath", "$ORIGIN/../..:$ORIGIN", str(plugin_so))
# Non-recursive, set rpath only for top-level libs.
for lib_so in dest.glob("*.so*"):
for lib_so in qt_lib_files:
if lib_so.is_file():
run("patchelf", "--set-rpath", "$ORIGIN", str(lib_so))
@@ -163,6 +198,17 @@ def stage_qt_runtime_payload(exe_path: Path, dest: Path, qt_dir: Path | None) ->
qt_conf_path.write_text("[Paths]\nPrefix = .\n")
KNOWN_EXCEPTIONS = frozenset(
(
# Optional Qt SQL driver plugins we don't ship the client libs for.
"libqsqlpsql.so",
"libqsqlmysql.so",
"libqsqlmimer.so",
"libqsqlodbc.so",
)
)
def check_runtime_dependencies(package_dir: Path) -> None:
"""Check all binaries in `package_dir` and report if they're still missing dependencies or are static."""
@@ -187,21 +233,24 @@ def check_runtime_dependencies(package_dir: Path) -> None:
try:
ldd_output = run("ldd", str(binary_file), env=env, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print(f"ldd failed for {binary_file}")
print(e.output, end="")
logger.error(f"ldd failed for {binary_file}")
logger.error(e.output)
missing = True
continue
if "not found" in ldd_output:
print(f"{C.YELLOW}Missing runtime dependencies for {binary_file}{C.RESET}")
is_known = binary_file.name in KNOWN_EXCEPTIONS
log = logger.debug if is_known else logger.warning
log(f"Missing runtime dependencies for {binary_file}")
for line in ldd_output.splitlines():
if "not found" in line:
print(f"{C.YELLOW}{line}{C.RESET}")
missing = True
log(line)
if not is_known:
missing = True
# TODO: should error?
if missing:
print(f"{C.YELLOW}Runtime dependency check found issues; continuing packaging.{C.RESET}")
logger.warning("Runtime dependency check found issues; continuing packaging.")
def package_python_wrapper(
@@ -210,8 +259,9 @@ def package_python_wrapper(
github_sha: str,
output_dir: Path,
arch_suffix: str,
occt_dir: Path | None,
) -> None:
print(f"Packaging python wrapper '{py_dir.name}'")
logger.info(f"Packaging python wrapper '{py_dir.name}'")
py_version = py_dir.name
postfix = "" if py_version[-1].isdigit() else py_version[-1]
# Match and convert `x.y` -> `xy`.
@@ -220,12 +270,25 @@ def package_python_wrapper(
numbers = "".join(version_match.group().split("."))
py_version_major = f"python-{numbers}{postfix}"
ifcopenshell_dir = py_dir / "ifcopenshell"
staging_dir = py_dir.parent / "ifcopenshell_"
staging_dir.mkdir()
for item in list(py_dir.iterdir()):
shutil.move(str(item), str(staging_dir))
staging_dir.rename(ifcopenshell_dir)
package_dir = ifcopenshell_install_dir / f".package-{py_version_major}"
if package_dir.exists():
# Clean up previous local runs.
shutil.rmtree(package_dir)
package_dir.mkdir(parents=True)
ifcopenshell_dir = package_dir / "ifcopenshell"
ifcopenshell_dir.mkdir()
for item in py_dir.iterdir():
dest = ifcopenshell_dir / item.name
if item.is_dir():
shutil.copytree(item, dest, symlinks=True)
else:
shutil.copy(item, dest, follow_symlinks=False)
if not is_platform("MAC"):
for lib_so in ifcopenshell_dir.glob("*.so*"):
if lib_so.is_file():
run("patchelf", "--set-rpath", "$ORIGIN", str(lib_so))
# Cache from test run during build.
pycache_dir = ifcopenshell_dir / "__pycache__"
@@ -237,9 +300,15 @@ def package_python_wrapper(
# TODO: packs qt libs also?
stage_runtime_payload(ifcopenshell_install_dir, ifcopenshell_dir)
zip_name = f"ifcopenshell-{py_version_major}-{VERSION}-{github_sha}-{arch_suffix}.zip"
run("zip", "-y", "-r", "-qq", zip_name, "ifcopenshell", cwd=py_dir)
shutil.move(str(py_dir / zip_name), str(output_dir / zip_name))
if occt_dir:
stage_runtime_payload(occt_dir, ifcopenshell_dir)
if not is_platform("MAC"):
check_runtime_dependencies(ifcopenshell_dir)
zip_path = output_dir / f"ifcopenshell-{py_version_major}-{VERSION}-{github_sha}-{arch_suffix}.zip"
run("zip", "-y", "-r", "-qq", "-1", str(zip_path), "ifcopenshell", cwd=package_dir)
shutil.rmtree(package_dir)
def is_packageable_executable(path: Path) -> bool:
@@ -255,10 +324,11 @@ def package_executable(
output_dir: Path,
autodesk_connector_dir: Path,
qt_dir: Path | None,
occt_dir: Path | None,
arch_suffix: str,
) -> None:
exe = exe_path.name
print(f"Packaging executable '{exe}'")
logger.info(f"Packaging executable '{exe}'")
package_dir = ifcopenshell_install_dir / f".package-{exe}"
if package_dir.exists():
# Clean up previous local runs.
@@ -270,6 +340,9 @@ def package_executable(
# but is this guard needed or it should be always False?
stage_runtime_payload(ifcopenshell_install_dir, package_dir, include_geometry_writers=is_platform("MAC"))
if occt_dir:
stage_runtime_payload(occt_dir, package_dir)
# On macOS, rpath is already set at build time via CMake's INSTALL_RPATH, and
# QT apps are packaged as .app bundles (`package_app_bundle`) instead.
if not is_platform("MAC"):
@@ -304,7 +377,7 @@ def package_app_bundle(
is the connector.
"""
app = app_path.stem
print(f"Packaging app bundle '{app}'")
logger.info(f"Packaging app bundle '{app}'")
if app == "BonsaiViewer":
# ConnectorDiscovery looks in applicationDirPath()/connectors,
@@ -318,13 +391,31 @@ def package_app_bundle(
ARCH_SUFFIXES = ("linux64", "linuxarm64", "macosm164")
LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR")
class Args(NamedTuple):
arch_suffix: str
log_level: str
occt_shared: bool
ARGS: Args
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("arch_suffix", choices=ARCH_SUFFIXES, help="Zip filename suffix.")
# TODO: relax default to INFO once things get more stable.
parser.add_argument("--log-level", default="DEBUG", choices=LOG_LEVELS, help="Logging verbosity.")
# TODO: add `--shared`.
parser.add_argument("--occt-shared", action="store_true", help="OCCT was built as shared libraries.")
args = parser.parse_args()
global ARGS
ARGS = Args(arch_suffix=args.arch_suffix, log_level=args.log_level, occt_shared=args.occt_shared)
logger.setLevel(ARGS.log_level)
# bonsaiviewer-autodesk is now a Rust connector. packaging/build.py
# invokes `cargo build --release` and stages the binary +
# connector.json into dist/autodesk/. Same on-disk shape as the
@@ -335,7 +426,7 @@ def main() -> None:
assert autodesk_connector_dir.is_dir()
# Locate the ifcopenshell install dir and stage QT6 alongside the zip output.
install_root = get_install_dir(args.arch_suffix)
install_root = get_install_dir(ARGS.arch_suffix)
ifcopenshell_install_dir = install_root / "ifcopenshell"
output_dir = Path.home() / "output"
@@ -345,11 +436,13 @@ def main() -> None:
qt_dir_env = os.getenv("QT_DIR")
qt_dir = Path(qt_dir_env) if qt_dir_env else find_qt_dir(install_root, qt6_version)
occt_dir = find_occt_dir(install_root) if ARGS.occt_shared else None
# Iterate over all built Python wrappers in `install/ifcopenshell/python-x.y.z`
# and zip them, bundling all dynamic libs from `lib`.
github_sha = get_git_sha()
for py_dir in sorted(ifcopenshell_install_dir.glob("python-*")):
package_python_wrapper(py_dir, ifcopenshell_install_dir, github_sha, output_dir, args.arch_suffix)
package_python_wrapper(py_dir, ifcopenshell_install_dir, github_sha, output_dir, ARGS.arch_suffix, occt_dir)
# Iterate over all executables in `install/ifcopenshell/bin` and zip them.
# Each zip bundles dynamic libs from `lib` and also qt libs.
@@ -363,12 +456,13 @@ def main() -> None:
output_dir,
autodesk_connector_dir,
qt_dir,
args.arch_suffix,
occt_dir,
ARGS.arch_suffix,
)
if is_platform("MAC"):
for app_path in sorted(install_root.glob("*.app")):
package_app_bundle(app_path, install_root, github_sha, output_dir, autodesk_connector_dir, args.arch_suffix)
package_app_bundle(app_path, install_root, github_sha, output_dir, autodesk_connector_dir, ARGS.arch_suffix)
if __name__ == "__main__":
+18 -4
View File
@@ -1,3 +1,13 @@
# Removing use of `tr1` namespace that might not be available on some systems.
#
# Current status on different systems:
# - msvc - removed `tr1` namespace in 14.51 (`_MSC_VER == 1951`)
# - gcc (with libstdc++) - currently neither deprecated nor removed, though there are plans to
# - clang (with libc++) - never had it
#
# One of the hunks in the patch is patching `_MSC_VER == 1500`, so it's not stricly needed,
# but kept it just so it will be easy to check the absense of any `tr1` use.
diff --git a/COLLADABaseUtils/include/COLLADABUhash_map.h b/COLLADABaseUtils/include/COLLADABUhash_map.h
index 8ab0fb9b..12503bfb 100644
--- a/COLLADABaseUtils/include/COLLADABUhash_map.h
@@ -27,11 +37,13 @@ index 8ab0fb9b..12503bfb 100644
- #define COLLADABU_HASH_MAP std::tr1::unordered_map
- #define COLLADABU_HASH_MULTIMAP std::tr1::unordered_multimap
- #define COLLADABU_HASH_SET std::tr1::unordered_set
- #define COLLADABU_HASH_NAMESPACE_OPEN std { namespace tr1
- #define COLLADABU_HASH_NAMESPACE_CLOSE }
+ #define COLLADABU_HASH_MAP std::unordered_map
+ #define COLLADABU_HASH_MULTIMAP std::unordered_multimap
+ #define COLLADABU_HASH_SET std::unordered_set
#define COLLADABU_HASH_NAMESPACE_OPEN std { namespace tr1
#define COLLADABU_HASH_NAMESPACE_CLOSE }
+ #define COLLADABU_HASH_NAMESPACE_OPEN std
+ #define COLLADABU_HASH_NAMESPACE_CLOSE
#define COLLADABU_HASH_FUN hash
@@ -107,12 +107,12 @@
#define COLLADABU_HASH_NAMESPACE_CLOSE
@@ -45,11 +57,13 @@ index 8ab0fb9b..12503bfb 100644
- #define COLLADABU_HASH_MAP std::tr1::unordered_map
- #define COLLADABU_HASH_MULTIMAP std::tr1::unordered_multimap
- #define COLLADABU_HASH_SET std::tr1::unordered_set
- #define COLLADABU_HASH_NAMESPACE_OPEN std { namespace tr1
- #define COLLADABU_HASH_NAMESPACE_CLOSE }
+ #define COLLADABU_HASH_MAP std::unordered_map
+ #define COLLADABU_HASH_MULTIMAP std::unordered_multimap
+ #define COLLADABU_HASH_SET std::unordered_set
#define COLLADABU_HASH_NAMESPACE_OPEN std { namespace tr1
#define COLLADABU_HASH_NAMESPACE_CLOSE }
+ #define COLLADABU_HASH_NAMESPACE_OPEN std
+ #define COLLADABU_HASH_NAMESPACE_CLOSE
#define COLLADABU_HASH_FUN hash
diff --git a/common/libBuffer/include/CommonFWriteBufferFlusher.h b/common/libBuffer/include/CommonFWriteBufferFlusher.h
index c7af45b2..fac4f133 100644
+4
View File
@@ -331,6 +331,10 @@ class Material(bonsai.core.tool.Material):
@classmethod
def get_style(cls, material: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
if not material.is_a("IfcMaterial"):
# material may also be an IfcMaterialConstituentSet / IfcMaterialLayerSet /
# IfcMaterialProfileSet / IfcMaterialList, none of which have HasRepresentation.
return None
for material_representation in material.HasRepresentation:
for representation in material_representation.Representations:
for item in representation.Items:
+2
View File
@@ -99,6 +99,8 @@ std::string format_string(const ifcopenshell::attribute_value& argument) {
stream << v;
return stream.str();
break; }
default:
break;
}
return "?";
}
+1
View File
@@ -210,6 +210,7 @@ def build() -> None:
"-DGLTF_SUPPORT=ON",
"-DBUILD_EXAMPLES=OFF",
"-DBUILD_BONSAIVIEWER=ON",
"-DUSE_CCACHE=ON",
]
)
restore_env(*OLD_ADD_COMMIT_SHA)
+3 -1
View File
@@ -42,6 +42,7 @@ echo.
setlocal EnableDelayedExpansion
set SCRIPT_DIR=%~dp0
for %%I in ("%SCRIPT_DIR%..") do set "REPO_ROOT=%%~fI"
:: Make sure vcvarsall.bat is called and dev env set is up.
IF "%VSINSTALLDIR%"=="" (
@@ -453,6 +454,7 @@ set DEPENDENCY_INSTALL_NAME=OpenCOLLADA
set NEXT_DEPENDENCY_LABEL=OCCT
:: Always clone it, even if it's installed, because it contains xml headers we need.
:: Use a fixed revision in order to prevent introducing breaking changes
:: TODO: commit is almost 3 years behind the latest version used in nix/build-all.py, need to test and bump.
call :GitCloneAndCheckoutRevision https://github.com/KhronosGroup/OpenCOLLADA.git "%DEPENDENCY_DIR%" 064a60b65c2c31b94f013820856bc84fb1937cc6
call :CheckInstallation
@@ -467,7 +469,7 @@ IF NOT %ERRORLEVEL%==0 git apply --reject --whitespace=fix "%~dp0patches\OpenCOL
:: std::tr1::unordered_map was a legacy MSVC compatibility shim kept around through VS2022's STL, but newer
:: toolsets (e.g. VS2026/v145) no longer provide it, breaking the build with error C2039: 'tr1' is not a member of 'std'.
findstr /C:"typedef std::unordered_map<MarkId, FilePosType > MarkIdToFilePos;" common\libBuffer\include\CommonFWriteBufferFlusher.h>NUL
IF NOT %ERRORLEVEL%==0 git apply --reject --whitespace=fix "%~dp0patches\OpenCOLLADA_CommonFWriteBufferFlusher_tr1.patch" --ignore-whitespace
IF NOT %ERRORLEVEL%==0 git apply --reject --whitespace=fix "%REPO_ROOT%\nix\patches\opencollada\remove_tr1.patch" --ignore-whitespace
:: NOTE OpenCOLLADA has been observed to have problems with switching between debug and release builds so
:: uncomment to following line in order to delete the CMakeCache.txt always if experiencing problems.
REM IF EXIST "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt". del "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt"
@@ -1,13 +0,0 @@
diff --git a/common/libBuffer/include/CommonFWriteBufferFlusher.h b/common/libBuffer/include/CommonFWriteBufferFlusher.h
index c7af45b2..62b0f991 100644
--- a/common/libBuffer/include/CommonFWriteBufferFlusher.h
+++ b/common/libBuffer/include/CommonFWriteBufferFlusher.h
@@ -58,7 +58,7 @@ namespace Common
#else
typedef __int64 FilePosType;
#endif
- typedef std::tr1::unordered_map<MarkId, FilePosType > MarkIdToFilePos;
+ typedef std::unordered_map<MarkId, FilePosType > MarkIdToFilePos;
public:
static const size_t DEFAUL_BUFFER_SIZE = 64*1024;
-25
View File
@@ -20,14 +20,10 @@
:: Example usage:
:: run-cmake.bat vs2022-x64
:: run-cmake.bat vs2022-x64 -DGLTF_SUPPORT=ON
:: run-cmake.bat vs2022-x64 -DUSE_CCACHE=OFF
::
:: Used environment variables:
:: - `ADD_COMMIT_SHA` - if defined then `ADD_COMMIT_SHA` and `VERSION_OVERRIDE` cmake args will be set to `ON`.
:: - `USE_NINJA` - if defined then the Ninja generator will be used instead of the Visual Studio.
::
:: -DUSE_CCACHE=OFF (also accepts 0/FALSE/NO/N) disables ccache: the bundled ccache
:: install dir is kept out of CMAKE_PREFIX_PATH, and CMakeLists.txt skips detecting it.
@if not defined ECHO_ON ( echo off )
@@ -85,27 +81,6 @@ if not (%1)==() (
call set ARGUMENTS=%%ARGUMENTS:%1=%%
)
:: Honor -DUSE_CCACHE=OFF (also accepts 0/FALSE/NO/N, case-insensitive) by keeping
:: the bundled ccache out of CMAKE_PREFIX_PATH so it can't be auto-detected below.
set USE_CCACHE_VALUE=
for %%A in (%*) do (
set "ARG=%%~A"
if not "!ARG:-DUSE_CCACHE=!"=="!ARG!" (
for /f "tokens=2 delims==" %%V in ("!ARG!") do set "USE_CCACHE_VALUE=%%V"
)
)
if defined USE_CCACHE_VALUE (
if /I "!USE_CCACHE_VALUE!"=="OFF" set DISABLE_CCACHE=1
if /I "!USE_CCACHE_VALUE!"=="0" set DISABLE_CCACHE=1
if /I "!USE_CCACHE_VALUE!"=="FALSE" set DISABLE_CCACHE=1
if /I "!USE_CCACHE_VALUE!"=="NO" set DISABLE_CCACHE=1
if /I "!USE_CCACHE_VALUE!"=="N" set DISABLE_CCACHE=1
)
if defined DISABLE_CCACHE (
echo USE_CCACHE=%USE_CCACHE_VALUE% passed, disabling ccache.
set "CCACHE_INSTALL_DIR="
)
pushd ..
set CMAKE_INSTALL_PREFIX=%CD%\_installed-%GEN_SHORTHAND%
popd