Skip to content

Fix dyld libzstd/libunwind errors in distributed macOS binaries#105

Closed
jucasoliveira wants to merge 2 commits into
masterfrom
claude/friendly-blackwell
Closed

Fix dyld libzstd/libunwind errors in distributed macOS binaries#105
jucasoliveira wants to merge 2 commits into
masterfrom
claude/friendly-blackwell

Conversation

@jucasoliveira

@jucasoliveira jucasoliveira commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Users installing oitec on macOS without Homebrew hit dyld: Library not loaded: libzstd.1.dylib (and libunwind.1.dylib) at runtime
  • Root cause: release builds dynamically linked against Homebrew libraries at /opt/homebrew/opt/...
  • Fix: move .dylib files to a temp directory and set DYLD_LIBRARY_PATH so LLVM tools (llvm-config → libLLVM) still work during the build, while the linker only finds .a static archives

Why previous attempts failed

  1. Removing .dylib before build → broke llvm-config (it loads libLLVM.dylib which chains to libzstd.1.dylib)
  2. Copying .a to isolated dir → LLVM's own -L flags (from llvm-config --ldflags) still pointed the linker to the original dir containing the .dylib

What works now

Move the .dylib files out of linker search paths → DYLD_LIBRARY_PATH makes them available for process execution (build scripts) → linker only sees .a → static link

Changes

release.yml

  • aarch64-apple-darwin: Moves libzstd*.dylib and libunwind*.dylib to /tmp/dylib-runtime, exports DYLD_LIBRARY_PATH
  • x86_64-apple-darwin: Same approach for x86_64 zstd
  • Verification step: Now checks for ANY /opt/homebrew or /usr/local/opt references in the binary, not just libzstd

ci.yml

  • Replaced os-only matrix with named targets matching release: linux-x86_64, linux-aarch64, macos-aarch64
  • Removed x86_64-apple-darwin from CI (requires cross-compilation setup, tested only in release)
  • Added libzstd-dev to Linux CI (was missing vs release)
  • Added informational otool -L check on macOS CI builds

Test plan

  • CI passes on all three native targets
  • Release build otool -L verification passes (no /opt/homebrew, no /usr/local/opt, no libzstd)
  • Install built binary on a machine without Homebrew zstd — no dyld error

🤖 Generated with Claude Code

…ebrew refs

The previous approach (copying libzstd.a to an isolated dir) failed because
LLVM's own -L flags from llvm-config still pointed the linker to the original
directory containing the .dylib. And removing the .dylib broke llvm-config
itself since libLLVM dynamically links to libzstd.

New approach: move .dylib files to /tmp/dylib-runtime and set DYLD_LIBRARY_PATH
so LLVM tools still find them at runtime, while the linker only sees .a archives
in the original directories. Also moves LLVM's libunwind.dylib on aarch64.

Verification step now checks for ANY /opt/homebrew or /usr/local/opt references,
not just libzstd.

CI updated: removed x86_64-apple-darwin (needs cross-compilation, only tested
in release), added linux-aarch64 and macos dynamic-dep visibility check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collapse nested `if` conditions into match arm guards as suggested
by clippy::collapsible_match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AI fix caused build error

1 participant