As we're not currently bundling dlls for all other external dependencies.
It seems `--shared`in CI previously worked sort of by accident - since it was relying on the cached build outputs that were previously built statically.
Three related cleanups to how the bonsaiviewer-autodesk connector is built
and shipped.
build-bonsaiviewer-autodesk.yml no longer builds a bundle. Its four-runner
matrix produced autodesk-<os>-<arch>.zip artifacts that nothing consumed —
shipping happens in the platform pipelines, which each invoke
packaging/build.py themselves. What is left is the crate's only lint and
test coverage, so the workflow is renamed to match what it does and a
header comment records where the shipped binary actually comes from.
build_osx.yml now builds and bundles the connector, which it never did:
macOS users have been getting a Bonsai Viewer with no Autodesk connector at
all. ConnectorDiscovery resolves applicationDirPath()/connectors, which
inside a bundle is Contents/MacOS, so that is where the folder lands.
The tkinter probes in the Windows and Linux workflows are dropped. They
guarded the old PyInstaller connector's Tk GUI (de7520418) and have been
dead since the Rust rewrite (9d9f4054f); python3.11-tkinter goes with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three coupled fixes that close the macOS bring-up loop:
## 1. ifcwrap: fix INSTALL_RPATH on Apple
The ifcopenshell_wrapper Python module had `INSTALL_RPATH "$ORIGIN"` set
for "NOT WIN32 AND NOT WASM_BUILD" — but `$ORIGIN` is a Linux ld.so
placeholder, not a macOS dyld one. macOS dyld doesn't expand it; it
bakes the literal string `$ORIGIN` into LC_RPATH, which resolves to
nothing at runtime. The wrapper's hard-link `@rpath/ifcopenshell
.document.rdb.dylib` then fails to load even though INSTALL(TARGETS …
LIBRARY DESTINATION "${python_package_dir}/ifcopenshell") above had
already dropped the plug-in dylib right next to the wrapper.
Split the rpath assignment: `@loader_path` on Apple (the dyld
equivalent of `$ORIGIN`), `$ORIGIN` elsewhere.
This is what b0ef47819 (the build_osx IFCOS_BUILD_PYTHON_WRAPPER=off
gate) was working around. The gate is removed below.
## 2. ifcviewer-minimal: stage IfcOpenShell + wgpu_native into the .app
IfcViewerMinimal.app was building on macOS via the cmake
`BUILD_BONSAIVIEWER → BUILD_BONSAIVIEWER_WGPU` promotion, but had no
bundle staging — Contents/Frameworks/ only contained the Qt
frameworks macdeployqt deposited, so the .app would refuse to start
("Library not loaded: @rpath/libwgpu_native.dylib").
Mirror what src/bonsaiviewer/CMakeLists.txt does for BonsaiViewer.app:
* Set INSTALL_RPATH to `@executable_path/../Frameworks` so the exe
knows where to look for @rpath/* deps.
* install(FILES) libwgpu_native.dylib into the bundle's Frameworks/
(globbed from WGPU_NATIVE_LIB_DIR rather than hard-coded so it
covers any future versioned name).
* install(CODE) staging block that copies every `*.dylib` from
<prefix>/lib/ into the bundle's Frameworks/, excluding the
geometry-writer plug-ins (same EXCLUDE regex as BonsaiViewer.app —
viewer doesn't need OBJ/glTF/DAE/STP/IGS/SVG/TTL export converters).
Same long-form rationale + caveats apply (macdeployqt doesn't follow
non-Qt @rpath deps, lib-prefixed core libs vs ifcopenshell.* plug-in
naming split, Linux's equivalent lives in build_rocky.yml workflow
bash via patchelf + stage_runtime_payload). See src/bonsaiviewer/
CMakeLists.txt for the full version.
## 3. build_osx.yml: drop IFCOS_BUILD_PYTHON_WRAPPER=off
With (1) fixed, the Python wrapper smoke test should pass again. The
gate goes away; the comment block in build_osx.yml is replaced with a
short note pointing at the ifcwrap rpath fix as the underlying change
that re-enables this.
Together, (1)+(2)+(3) close the standalone IfcViewerMinimal-on-macOS
gap (task #43) and re-enable IfcOpenShell-Python on the macOS arm64 CI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors the Rocky workflow's two-part size reduction (27249770e
"Reduce Rocky package size") on macOS:
1. Pass `--shared` to nix/build-all.py. The default builds
IfcOpenShell as static libs, which means every plug-in dylib
(schemas × 8, kernels × 3, mappings × 8, writers × 8, document
serializers × ~4, linework processing) statically embeds a full
copy of libIfcParse + libIfcGeom. With --shared the plug-ins
reference @rpath/libIfcParse.dylib + @rpath/libIfcGeom.dylib and
the per-plug-in dylib drops from ~30-50 MB to a few MB each.
Dominant size win.
2. Filter `ifcopenshell.geometry.writer.*.dylib` out of BonsaiViewer's
plug-in staging step in src/bonsaiviewer/CMakeLists.txt. These are
the per-schema OBJ / glTF / DAE / STP / IGS / SVG / TTL export
converters — heavy because each one inlines the full schema, and
BonsaiViewer is a viewer, never an exporter, so they're pure
deadweight inside the bundle. Additive on top of --shared.
Bundle went 300 MB → expected ~100 MB, in line with Linux (~100 MB)
and Windows (~80 MB).
The IFCOPENSHELL_BUILD_PYTHON_WRAPPER=off gate is unchanged for now
— once we confirm BonsaiViewer.app size + functionality look sane,
we can ungate the Python wrapper and see if shared-builds-on-macOS
shake out its install issues too.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The existing "Package .zip archives" step only sweeps
\`\$install_root/bin/\` for plain executable files (via \`find -type f
-perm /111\`). That captures \`IfcConvert\` and \`IfcGeomServer\` but
misses macOS app bundles entirely:
- BonsaiViewer.app installs at \`\$install_root/BonsaiViewer.app\`
(BUNDLE DESTINATION ".") — not under bin/, and it's a directory,
not a file.
So the prior bonsai macOS CI run got a green tick but the
ifcopenshell-builds S3 bucket only ended up with IfcConvert +
IfcGeomServer + the python wheel — no BonsaiViewer.
Add a second packaging pass that finds \`*.app\` directories at the
install-prefix root and zips each one as-is. macdeployqt has already
embedded the Qt frameworks inside the bundle during install/strip, so
no extra dependency staging is needed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
# Why this exists
The bonsai macOS CI (`build_osx.yml`, arm64) currently fails the
`IfcOpenShell-Python` smoke test with:
ImportError: dlopen(.../_ifcopenshell_wrapper.cpython-311-darwin.so,
0x0002):
Library not loaded: @rpath/ifcopenshell.document.rdb.dylib
Reason: tried: '$ORIGIN/ifcopenshell.document.rdb.dylib'
(no such file)
`_ifcopenshell_wrapper.cpython-311-darwin.so` has a hard `LC_LOAD_DYLIB`
of `@rpath/ifcopenshell.document.rdb.dylib` and its only `LC_RPATH` is
`$ORIGIN` (= `site-packages/ifcopenshell/`). The plug-in dylib is not
present at that path on macOS, so the wrapper fails to load and the
build smoke test (`build-all.py: compile_python_wrapper`) errors out.
BonsaiViewer.app builds, installs, and macdeployqt-deploys cleanly
before this point — the failure is downstream and unrelated to wgpu,
BonsaiViewer, or anything else on this branch.
# Where the regression came from
Two commits on the branch line that became `ifcviewer-wgpu`:
b599ee10 "More work on isolating into plug-ins" (2026-04-18, Thomas Krijnen)
b022ca7e7 "Some plug-in work" (2026-04-21, Thomas Krijnen)
`b599ee10` added a hard link dep:
target_link_libraries(ifcopenshell_wrapper PRIVATE document_serializer_rdb)
which bakes `@rpath/ifcopenshell.document.rdb.dylib` into the wrapper's
`LC_LOAD_DYLIB`. `b022ca7e7` added a `if(CREATE_BUNDLE) ...
install(TARGETS ${_ifcopenshell_python_runtime_targets}
LIBRARY DESTINATION "${python_package_dir}/ifcopenshell" ...)` block
that was *intended* to satisfy that link dep by copying plug-ins next
to the wrapper. On macOS arm64 the install rule does not actually
deposit `ifcopenshell.document.rdb.dylib` into
`site-packages/ifcopenshell/`, so the runtime dlopen fails.
# Why 227d85d worked
`227d85d` (2026-05-15) is on the `v0.8.0` line, not on the
`datamodel-v1.0 -> ifcviewer -> ifcviewer-wgpu` line. The merge-base
of `227d85d` and `ifcviewer-wgpu` is `e6258ab4` (2026-04-13). Both
b599ee10 and b022ca7e7 live on the wgpu side of that fork and are not
ancestors of `227d85d`:
$ git merge-base --is-ancestor b599ee10227d85d
[exit 1 — NOT an ancestor]
$ git merge-base --is-ancestor b599ee10 v0.8.0
[exit 1 — NOT an ancestor]
So the macOS Python wheel built fine on `v0.8.0` because that branch
never had the plug-in refactor; it has been broken on our branch line
since 2026-04-21. Nobody noticed because nobody had been firing
`build_osx.yml` against this branch line until this week's bonsai CI
work.
# What this commit does
Adds an `IFCOS_BUILD_PYTHON_WRAPPER` env var to `nix/build-all.py`.
Defaulting to `on` preserves existing behaviour everywhere; setting
it to `off` (or `0`/`false`/`no`) drops `IfcOpenShell-Python` from
the target set so `build-all.py` skips the wrapper build + smoke
test entirely.
`build_osx.yml` sets `IFCOS_BUILD_PYTHON_WRAPPER=off` so the bonsai
macOS CI can complete and upload `BonsaiViewer.app` while the plug-in
install rule is broken.
# What Thomas should do
Once the install rule in `src/ifcwrap/CMakeLists.txt` (the
`if(CREATE_BUNDLE) ... install(TARGETS ${_ifcopenshell_python_runtime_targets}
LIBRARY DESTINATION "${python_package_dir}/ifcopenshell" ...)` block,
added in b022ca7e7) is fixed to actually drop
`ifcopenshell.document.rdb.dylib` next to the wrapper in
site-packages on macOS — this commit can be reverted in its entirety:
the env-gate in `build-all.py` AND the `IFCOS_BUILD_PYTHON_WRAPPER=off`
in `build_osx.yml`. The bonsai macOS workflow will then build the
Python wrapper too.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bundles four portability fixes uncovered by manually firing the platform
workflows against this branch:
- WgpuOverlayRenderer.cpp: GCC 11 (Rocky manylinux runner) does not parse
a multi-line raw string inside `#define`. Converted
THICK_LINE_HELPERS_WGSL from a `#define` to a `static const char*` and
switched AXIS_WGSL / SECTION_WGSL / MARQUEE_WGSL to `std::string` so
they can concatenate at static-init time. Three call sites now pass
`.c_str()` to svFromCStr.
- bonsaiviewer/CMakeLists.txt: added BUNDLE DESTINATION to the install
rule (same fix already applied to IfcViewerWgpuMinimal). MACOSX_BUNDLE
targets fail at configure on macOS without it even when nobody runs
`make install`.
- build_osx.yml: dropped the x64 (Intel cross-compile) matrix row. The
runner is arm64 so `brew --prefix qt` returns the arm64 prefix; we'd
need a separate x86_64 Qt install under /usr/local to cross-build
BonsaiViewer. Revisit if Intel-Mac demand resurfaces.
- build_win.yml: dropped the ARM64 matrix row. wgpu-native does not ship
a Windows-ARM64 binary, so IfcViewerWgpu's link step fails with ~60
unresolved wgpu* externs. Re-enable when upstream publishes that
target.
Cherry-pick this commit to v0.8.0 so the workflow_dispatch buttons see
the dropped rows.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Linux (build_rocky.yml) and Windows (win/build-all-win.py) already pass
BUILD_BONSAIVIEWER=ON when building from source; macOS was the odd one
out. Three small changes to bring it up to parity:
1. .github/workflows/build_osx.yml — \`brew install qt\` (Qt6 with Svg)
in the Install Dependencies step, then set QT_DIR=\$(brew --prefix
qt) and BUILD_BONSAIVIEWER=ON in the Run Build Script env.
2. nix/build-all.py — install_qt6() now honours a pre-set QT_DIR.
Before this change get_qt6_aqt_config() raised on non-Linux,
blocking bonsai builds on macOS/Windows from ever using a
system-provided Qt6. We now validate that QT_DIR points at a real
Qt6 install (probes lib/cmake/Qt6/Qt6Config.cmake) and skip the aqt
download path if so. Linux flow is unchanged: when QT_DIR is unset
the function falls through to the existing aqtinstall path.
build_osx.yml stays workflow_dispatch-only — slow run (~1h with
ccache, longer cold), so manual fire when wanted. Cherry-pick this
file + nix/build-all.py to v0.8.0 to make the workflow dispatchable
against the ifcviewer-wgpu branch before the squash lands.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>