Skip to content

Simplify macOS linking by using clang as linker driver - #70

Closed
TBird2001 wants to merge 1 commit into
OpenVAF-Reloaded:masterfrom
TBird2001:macos-support
Closed

Simplify macOS linking by using clang as linker driver#70
TBird2001 wants to merge 1 commit into
OpenVAF-Reloaded:masterfrom
TBird2001:macos-support

Conversation

@TBird2001

Copy link
Copy Markdown
Contributor

I ran into linking issues building OpenVAF on macOS (Apple Silicon, MacPorts LLVM 18). The current approach passes raw ld64 flags like -syslibroot, -platform_version, and -arch directly, which breaks in some configurations.

This PR uses clang as the linker driver on macOS instead. Clang already handles SDK detection, system library linking, and architecture selection, so the manual flag handling becomes unnecessary.

Changes

Linker selection (linker/src/lib.rs):

  • Use clang on macOS instead of ld64.lld / ld
  • Use -dynamiclib instead of -dylib (clang syntax)
  • Remove manual SDK sysroot detection (clang handles this)

Target specs (target/src/spec/*_apple_darwin.rs):

  • Remove -arch, -platform_version, and -lSystem flags
  • Keep only -Wl,-undefined,dynamic_lookup
  • Clang infers the rest from the target triple

Runtime linking (openvaf-driver/build.rs):

  • Query llvm-config --libdir at build time and embed the result as an rpath
  • Eliminates the need to set DYLD_LIBRARY_PATH at runtime

Documentation (configure):

  • Added MacPorts installation instructions alongside Homebrew

Testing

  • macOS, Apple Silicon (M2), MacPorts LLVM 18 and LLVM 21
  • Built openvaf, compiled Verilog-A models to .osdi, loaded them in ngspice

The existing macOS linker configuration passed raw ld64 flags that don't
work when using clang as the linker driver. This simplifies macOS linking
by using clang, which automatically handles SDK detection, system library
linking, and architecture flags.

Changes:
- Use clang instead of ld/ld64.lld on macOS
- Change -dylib to -dynamiclib (clang syntax)
- Remove manual -syslibroot and -platform_version flags (clang handles these)
- Simplify target specs to only pass -Wl,-undefined,dynamic_lookup
- Add build.rs to embed LLVM library rpath for runtime linking
- Add MacPorts installation instructions to configure script

Tested on macOS with MacPorts LLVM 18 and 21 on Apple Silicon (M1).
@TBird2001

TBird2001 commented Feb 5, 2026

Copy link
Copy Markdown
Contributor Author

Also, I'm not sure about Homebrew, but with MacPorts I don't have to set LLVM_SYS_211_PREFIX or modify my PATH, as long as I use the port select command to make the installed llvm and clang the defaults. I also used the MacPorts rust. So, with the pull request changes, it's as simple as

sudo port install llvm-21 clang-21 rust cargo
sudo port select --set llvm mp-llvm-21
sudo port select --set clang mp-clang-21

Then

git clone git@github.com:arpadbuermen/OpenVAF.git
cd OpenVAF
./configure
./build.sh --release

@arpadbuermen

arpadbuermen commented Feb 24, 2026

Copy link
Copy Markdown
Collaborator

Hi Jason,

Welcome to the small community of OpenVAF hackers.

I did a 'cargo fmt', moved your PR into the verley-macos branch, and set up PR #72. CI passes.

I develop on Intel and lack experience with MACs so I have a question: If I build for mac and move the binary to some other mac where the libraries are at some other location that the one baked into the binary (i.e. the one based on the 'llvm-config --libdir' output you collect at compile time) will the binary work if I set the DYLD_LIBRARY_PATH?

Best regards,
Arpad

P.S.: Always do a 'cargo machete' followed by 'cargo fmt' before you submit. CI checks these two and fails if they are not flawless.

@TBird2001

Copy link
Copy Markdown
Contributor Author

Thanks for the "cargo" instructions. I'm not familiar with Rust at all.

Regarding Macs, macOS is inconsistent in how it handles the DYLD_* variables. For security reasons (SIP), it strips DYLD_LIBRARY_PATH and friends for system binaries and in some launcher contexts, and I’ve seen that break setups that should have worked on paper. In practice, for a user‑installed binary like OpenVAF, DYLD_LIBRARY_PATH or DYLD_FALLBACK_LIBRARY_PATH will generally work as long as LLVM on the second system lives in a non‑system location. But it’s not something I’d rely on long‑term; Apple has changed this behavior before and may do so again.

Using rpath is the recommended macOS mechanism for finding non‑system libraries at runtime. The rpath derived from llvm-config --libdir makes the “build and run on the same machine” case work without any environment tweaks, which is the common scenario. For distribution, package managers like Homebrew and MacPorts could use the same approach and ship OpenVAF prelinked against their own LLVM (ngspice is already available via both), but that would require someone to maintain the packaging. In practice, they will sometimes add a package if there is clear demand from users.

@arpadbuermen

Copy link
Copy Markdown
Collaborator

Closing, moved to PR #72.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants