macOS BambuNetwork bridge: fix #13 and surrounding bring-up issues#18
macOS BambuNetwork bridge: fix #13 and surrounding bring-up issues#18stephanGarland wants to merge 9 commits into
Conversation
When the Linux host subprocess stops responding (or its stdout pipe does not propagate the child's terminate signal cleanly through limactl shell), the reader thread blocks in read_raw_frame() while stop() blocks in reader.join() — the deadlock described in issue FULU-Foundation#13. - stop(): close our ends of the stdio pipes before calling terminate() and join(). Closing the parent read fd forces the in-flight read to return with an error, which lets reader_loop drop out and stop() complete. - start_locked(): remove the m_state_mutex.unlock()/lock() block that raced with the caller's lock_guard (would unlock an already-unlocked mutex when the guard destructed). - ensure_started(): switch to unique_lock and drain a stale reader thread before attempting a new start, with the mutex temporarily released so the reader can finish its own state-mutex acquisition during exit. Investigation and patch by Claude Opus 4.7 (Anthropic); reviewed, tested, and landed by me. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On macOS the source module hosts the native BambuPlayer Objective-C class used by wxMediaCtrl2 to render the printer's camera feed. The network bridge dylib does not export that class — only libBambuSource.dylib does. Returning true from source_module_is_network_module() (the previous behavior on macOS when the bridge was enabled) caused get_bambu_source_entry() to hand wxMediaCtrl2 the bridge dylib, where dlsym for OBJC_CLASS_$_BambuPlayer returned null, m_error was set to -2, and the video panel stalled with no player created. Other platforms keep the original behavior — they don't have the same Obj-C-class-in-libBambuSource arrangement. Investigation and patch by Claude Opus 4.7 (Anthropic); reviewed, tested, and landed by me. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backport of PR FULU-Foundation#12 from upstream FULU-Foundation/OrcaSlicer-bambulab, authored by Claudio Jara <claudiojaraf@gmail.com>. Two build failures on macOS 15+ with current Xcode SDKs: 1. Autotools deps (GMP/MPFR) via ExternalProject_Add don't inherit CMAKE_OSX_DEPLOYMENT_TARGET. Fix: auto-export SDKROOT from `xcrun --show-sdk-path` when unset, so the configure step finds the active SDK. 2. Clang in SDK 26+ rejects the out-of-range enum cast in the constexpr initializer of MEDIASTATE_BUFFERING. Replace `static constexpr` with `static inline const`, mirroring the pattern already used elsewhere. Original PR: FULU-Foundation#12
- Add check_build_tools() that runs before option parsing and reports any missing Homebrew packages with an actionable `brew install ...` line. Covers cmake, ninja, autoconf, automake, libtool, pkg-config, and texinfo (for makeinfo, which the gettext / GMP / MPFR autotools deps need and which is *not* part of CLT). Also flags missing xcrun as needing Xcode Command Line Tools. Uses POSIX-portable iteration so it works under the macOS-shipped bash 3.2. - Run shfmt -i 4 -ci over the file so the case/option indentation is consistent (was a mix of 2- and 8-space). shellcheck -S style is clean afterward. - Flip the -x flag's meaning: default to Ninja, opt into Xcode with -x. Reverses the previous "Xcode by default, -x for Ninja". The Xcode generator requires a full Xcode.app install and fails on a CLT-only setup with "No CMAKE_C_COMPILER could be found"; Ninja works with CLT alone and parallelizes across all cores by default. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The host process dlopens libbambu_networking.so / libBambuSource.so at runtime; both .so libraries dynamically link the system libstdc++.so.6. With -static-libstdc++ -static-libgcc on the host, that's two libstdc++ instances in one process — and any function exported by the plugin .so that returns std::string (e.g. bambu_network_get_version) crosses the boundary and gets a libstdc++-A-constructed object passed into a libstdc++-B destructor/copy-constructor. SSO threshold, allocator hooks, and internal layout differ enough across gcc versions that the result is silent heap/stack corruption. Letting the host dynamically link against the same system libstdc++.so.6 the plugin uses removes the ABI surface entirely. Investigation and patch by Claude Opus 4.7 (Anthropic); reviewed and tested by me. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The upstream LinuxPluginHost::handle() only logs a hand-picked subset
of RPC methods (set_cert_file, set_extra_http_header, change_user,
bridge.runtime_info). That whitelist hides everything else that
actually flows through the bridge — login URL generation, MQTT cloud
connect status, camera-URL retrieval, FTP/cloud print upload — which
is exactly the surface area that needed visibility when debugging the
macOS bridge bring-up.
Add an env-gated tracer:
- Setting ORCA_LOG_ALL_RPC=1 logs every incoming RPC method + payload
to stderr at handle() entry.
- The same flag enables response logging for net.connect_server,
net.is_server_connected, net.build_login_cmd / build_logout_cmd /
build_login_info, net.get_camera_url / get_camera_url_for_golive,
and (when events are present) bridge.poll_events.
- Default is *off*: when the env var isn't set, the host behaves
exactly as before. The wrapper passes the variable through
(`ORCA_LOG_ALL_RPC="${ORCA_LOG_ALL_RPC:-}"`) so it's a one-shot
`ORCA_LOG_ALL_RPC=1 ./OrcaSlicer` from a terminal.
Investigation and patch by Claude Opus 4.7 (Anthropic); reviewed and
tested by me.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The upstream macOS install script provisions an arm64 Ubuntu guest with --vm-type=vz --rosetta and relies on Rosetta to translate the prebuilt x86_64 Linux host binary + libbambu_networking.so. In practice that combination crashes (SIGBUS BUS_ADRALN under Rosetta; std::bad_alloc / stack-canary trips under qemu-user). The plugin .so contains codegen patterns — likely around its TLS / atomic / openssl pin-checking paths — that only run correctly under a *native* x86_64 kernel. Fixes: * Provision a full-system x86_64 QEMU VM instead of arm64+Rosetta: --vm-type=qemu --arch=x86_64. Drops the maybe_install_rosetta() call. The binary now sees a native x86_64 environment and runs cleanly. ~10x CPU overhead vs Rosetta but the only path that actually works. * New ensure_qemu_installed(): Lima with qemu vmtype requires qemu-system-x86_64, which Lima doesn't bundle on macOS. Auto-installs via `brew install qemu` when missing. * New ensure_lima_x86_64_guestagent(): Lima's Homebrew formula only ships the host-arch guestagent. Cross-arch guests need lima-additional-guestagents (the bundled-tarball install path already grabs them; the brew path needs an explicit `brew install lima-additional-guestagents`). * Three-state Lima start logic: the old code had a two-way branch (`limactl shell ... true` failed → `limactl start --name=X ... template:default`). That fails with "instance already exists" whenever the VM exists but is just stopped — exactly the post-reboot case. Replace with: reachable → no-op; exists+stopped → `limactl start <name>`; absent → create+start from template. * REPLACE_EXISTING=1 now also `limactl delete`s after stop, otherwise the subsequent create still hits "instance already exists". * Auto-recreate on arch mismatch: if the instance exists but its arch isn't x86_64 (e.g. a prior arm64+rosetta install), force REPLACE_EXISTING=1. * Mount /var/folders: OrcaSlicer stages the 3MF for cloud/LAN print upload to its macOS per-user temp tree (TMPDIR == /var/folders/...). The bridge inside the guest reads the file by absolute path, so the path must be visible. Without this, "Send to Printer" hangs at "sending through cloud service" forever because the FTP upload thread can't open the .3mf. * provision_guest_amd64_userspace() is kept but now bails early when the guest itself is x86_64 (libs are already native; no multiarch setup needed). It still runs on arm64-guest setups, in case anyone forces that combination. Investigation and patch by Claude Opus 4.7 (Anthropic); reviewed and tested by me. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The shipped slicer_base64.cer was a 2-cert bundle pinned to the
*.bambulab.com leaf cert that expired 2022-07-13, plus the DigiCert
Global Root CA. Every TLS connection the bridge's plugin .so made was
returning CURLcode 60 (PEER_FAILED_VERIFICATION) — the user-visible
symptoms were:
- "Authentication failed" after Bambu Cloud login completed (the
ticket-exchange POST to api.bambulab.com fails)
- "Failed to connect to server" when the .so tries to bring up the
MQTT cloud connection to us.mqtt.bambulab.com (the broker uses
*.mqtt.bambulab.com, which the old leaf-pin doesn't cover anyway)
Replace with a 3-cert bundle:
1. Current *.bambulab.com leaf (valid through 2026-07-17), fetched
live from bambulab.com:443.
2. Current *.mqtt.bambulab.com leaf (valid through 2026-10-20),
fetched live from us.mqtt.bambulab.com:8883. The MQTT broker
hostname is two labels deep so the *.bambulab.com wildcard
doesn't match it; the .so needs its own leaf in the bundle.
3. DigiCert Global Root CA — preserved from the original bundle.
Both leafs chain to this root (via RapidSSL TLS RSA CA G1),
so chain validation continues to work even when leafs rotate.
All three are public server certificates / a public root CA. No
private keys, no client identifiers, no per-user data.
Investigation and patch by Claude Opus 4.7 (Anthropic); reviewed and
tested by me.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the outer <div align="center"> wrapping the whole file. Markdown bodies are conventionally left-aligned; centering the install instructions made the prose harder to scan and didn't actually render cleanly across viewers (GitHub honors it; many editors don't). - Keep a small <p align="center"> just around the logo image where centering is what you actually want. - Add a proper top-level title (# OrcaSlicer — BambuNetwork edition) instead of leaning on a level-2 heading for the intro. - Replace the macOS "Work in progress" placeholder with a description of the auto-install flow (Lima + qemu x86_64 Linux guest) and what the user has to do on first launch — essentially: confirm the install prompt and wait a few minutes the first time. - Mention that ./build_release_macos.sh now defaults to Ninja with -x as the Xcode opt-in, in case anyone has the inverse muscle memory from upstream. - Light prose tidy throughout (single-sentence platform notes, fewer hard line breaks). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
878330e to
11f60fa
Compare
|
Has anyone else successfully built this? I can not for the life of me get a successful build on my M1. |
What error[s] are you seeing? I might be able to figure it out. |
|
Thanks for responding. Just for context i am not very versed in compiling so it might be a fault on my end. I tried building it twice with the command using ninja. The first try it threw an error while compiling Orcaslicer code (after dep) Second try it threw an error while in deps
Edit: Third try and i got a new error, |
Can you post the output of |
|
|
|
I did a clean build with no issues. It's possible that you have some dangling env vars left from a previous attempt? In a new terminal, can you please run these from the repo root: ls build/ deps/build/ 2>&1
env | grep -iE 'cmake|png|homebrew|pkg_config|xcode|sdkroot'
brew list --versions | grep -iE 'libpng|cairo|freetype|fontconfig'
find build deps/build -name CMakeCache.txt 2>/dev/null | head -5For the latter, if you do find any |
|
Here is what i got PS; i deleted everything after my failed attempt, thats probably why there are no CMakeCache.txt files. |
I think this may be the problem. That's typically the prefix for x86_64 Homebrew; arm64 Homebrew is That matters because any tools installed with it are going to be running under the Rosetta 2 translation layer, and there are various checks in the script to determine the architecture. You might be able to run |
|
Yes i noticed that too so i switched to arm64 Homebrew but i ended up getting the same error as the third try.
and Edit:
Edit #2: After countless hours of troubleshooting with claude, i managed to compile the app and it launches! VM works too, handshake works etc. Root of the problem was a mixup between x86 and arm64 (entirely my systems fault). Problem is now i can't login, it logs in automatically when i first opened the app, but none of my printers showed up. I figured its a problem with the account since the printer is linked through the account so i tried to retry the login. Got forwarded to bambu's website where i logged in normally but i ended up getting a: |
Progress! I had the same error occur; it was due to an expired TLS cert. If you had Orcaslicer automatically download the network bridge, it may have overwritten the cert shipped with this PR. for f in \
~/Library/Application\ Support/OrcaSlicer/plugins/slicer_base64.cer \
~/Library/Application\ Support/OrcaSlicer/macos-bridge/runtime/slicer_base64.cer \
/Applications/OrcaSlicer.app/Contents/Resources/cert/slicer_base64.cer; do
printf '%6s %s\n' "$(wc -c < "$f" 2>/dev/null || echo MISSING)" "$f"
doneIf any of those are |
|
Hello, was wondering if anyone has uploaded a working macOS version. |
I second this, foolishly wiped the built app thinking i did something wrong and needed to retry (this was before i saw Stephan's reply), now i keep facing new errors while trying to rebuild. An app bundle would be nice hahaha. |
|
Hello, any updates on whether you've gotten a working macOS build? |
|
@3rdnfnlbst @hellonearth311 @MaximusL-sudo email me (my username at gmail) and I can send a working MacOS app image over to you. I'll see about uploading it to a fork/hosting it somewhere later but I need to double check if that's going to be problematic given the ongoing situation around this version of Orca. Didn't change any code behind the scenes, just used the contents of this PR and then spent a couple hours staring at the screen and learning a lot as I went. If more than a handful of people need this I'd prefer we all poke the powers that be to merge the PR and update the releases instead, but if its just a few of us I'll happily help out. |
|
I've emailed you :) |
|
Summary
Fixes #13 and a chain of follow-on bugs that surfaced once the deadlock
was out of the way. End-to-end result on Apple Silicon (tested) and
Intel (untested but should work): clean install via the in-app
"download and install" flow, login to Bambu Cloud succeeds, printer
shows up, MQTT cloud connect comes up, camera preview plays, and
Send-to-Printer (cloud and LAN) successfully uploads the .3mf.
Issue #13's stated symptom (deadlock in
RpcClient::stop()) was thefirst failure people hit, but it was a tiny part of the picture — once
the deadlock was fixed the app stopped freezing and surfaced a series
of further failures, each of which is addressed by one commit here.
Test plan
a state where the prior Lima VM was already broken.
on_server_connected: 0/0).architecture-agnostic, but I don't own one.
-x(Xcode generator) — not tested in this branchsince the user's machine only has Command Line Tools; covered by
a separate manual review of the script.
Commit-by-commit notes
This branch is structured so each commit is a single self-contained fix.
Fix RpcClient deadlock when the bridge host wedges — the
issue BambuNetwork bridge deadlocks on Apple Silicon (M1/M2/M3) — both ABI variants fail under Rosetta #13 fix itself.
stop()closes its end of the stdio pipesbefore calling
terminate()so the reader thread's blockingread_raw_frame()returns. Also unbreaks the brokenunlock/relock-while-caller-holds-lock_guard pattern in
start_locked().Keep BambuSource separate from bridge dylib on macOS —
source_module_is_network_module()returnsfalseon macOS sowxMediaCtrl2can load theBambuPlayerObj-C class fromlibBambuSource.dylib(which actually exports it), rather thangetting handed the bridge dylib (which doesn't). Without this the
video preview never instantiates a player.
fix(macos): support macOS Tahoe (15+) SDK build— this isa backport of @claudiojara's open PR fix(macos): support macOS Tahoe (15+) SDK build #12. Included here because
the rest of this branch can't build without it on macOS 15+ SDK
(autotools deps can't find the active SDK; clang in SDK 26+ rejects
the constexpr enum cast in
wxMediaCtrl2.h). If the maintainerprefers to merge fix(macos): support macOS Tahoe (15+) SDK build #12 via its original PR, this commit can be
dropped from this PR — the remaining commits still apply cleanly
on top.
Tidy
build_release_macos.sh: dep check, format, default toNinja — adds a
check_build_toolsfunction that reports anymissing Homebrew packages with an actionable
brew installline(covers
cmake,ninja,autoconf,automake,libtool,pkg-config,texinfo, and Xcode CLT). Runsshfmt -i 4 -ciandshellcheckclean. Flips the-xflag's meaning: default is nowNinja (works with just CLT),
-xopts into the Xcode generator(requires full Xcode.app).
Link the Linux host dynamically against libstdc++ — the host
process
dlopenslibbambu_networking.so/libBambuSource.so,both of which dynamically link the system
libstdc++.so.6. With-static-libstdc++on the host, that's two libstdc++ instancesin one process —
extern "C"functions returningstd::stringby value cross the boundary and corrupt memory. Removing the
static-link flag makes both sides share one libstdc++.
Add env-gated full-RPC tracing to the Linux host — set
ORCA_LOG_ALL_RPC=1in the environment and the bridge host logsevery incoming RPC method + the responses for connect/login/camera
handlers + any non-empty
bridge.poll_eventsbatch. Defaults tooff; no behavior or output change without the env var. This is
what made the rest of these fixes diagnosable.
Rework macOS Lima install: native x86_64 VM + multiple bug
fixes — the biggest commit in the branch. Switches the Lima
guest from arm64+Rosetta to a full-system x86_64 QEMU VM
(Rosetta and qemu-user both corrupt the plugin's
.socodegen;only a native x86_64 kernel runs it cleanly). Also fixes:
three-state Lima start (running / stopped / absent — the old
two-way branch failed on the common "exists but stopped" case);
REPLACE_EXISTING=1now actually deletes before recreating;auto-recreate when the existing VM is the wrong arch; auto-install
of
qemu-system-x86_64andlima-additional-guestagentsviaHomebrew;
/var/foldersmount so the bridge can read OrcaSlicer'sper-user TMPDIR (the .3mf staged for upload lives there).
Refresh bundled BambuLab pinned-cert bundle — the shipped
slicer_base64.cerwas pinned to BambuLab's leaf cert thatexpired in 2022. Every TLS connection the plugin made was
returning
CURLcode 60(PEER_FAILED_VERIFICATION). Bundle isnow 3 certs: current
*.bambulab.comleaf, current*.mqtt.bambulab.comleaf (the MQTT broker hostname is twolabels deep so the wildcard doesn't cover it), and the DigiCert
Global Root CA. All three are public server certs / a public
root CA — no private keys, no identifiers, no per-user data.
README: drop center alignment, document macOS — replaces the
macOS "Work in progress" placeholder with a description of the
auto-install flow + tightens the README's formatting (drop the
outer
<div align="center">, keep centering only around thelogo, proper top-level heading).
What's deliberately not in this PR
the BMCU section): not a build dependency, separately open as an
existing PR. Including it here would just step on that.
were a red herring (the actual fix is the QEMU x86_64 VM, not a
binary rebuild). The CI-provided host binaries in
tools/pjarczak_bambu_linux_host/runtime/linux-x86_64/work fineonce everything else in this branch is in place.
prefer_lantoggle for video preview — implemented andtested locally, but the printer (a P2S in cloud mode) refuses
port 6000 connections regardless of what the client tries, so
there's no LAN path to redirect to without flipping the printer's
LAN-Only-Mode toggle. Code reverted, not included here.
🤖 Generated with Claude Code