Rust doesn't compile openssl library on MacOSX
What happened?
I have a rust project which uses openssl. Now I would like to have a reproducible build using devbox. But when I use rustup from devbox, the compilation fails at linking time.
I tried the same repo with flox and a locally installed rust, which compiles and runs fine!
Steps to reproduce
Clone the repo, start the shell, and compile parts of it:
git clone https://github.com/ineiti/fledger
cd fledger
devbox shell
cd cli/fledger
cargo build
The final output of the linker is this:
= note: ld: framework not found Security
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
Command
shell
devbox.json
{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.10.7/.schema/devbox.schema.json",
"packages": [
"which@latest",
"rustup@latest",
"libiconv@latest",
"openssl@latest",
"vscode",
],
"shell": {
"init_hook": [
"if [ ! -d $RUSTUP_HOME/toolchains -o ! -d $RUSTUP_HOME/toolchains/stable ]; then rustup default stable; fi",
],
"scripts": {
"test": [
"make cargo_test",
],
},
},
}
Devbox version
0.11.1
Nix version
nix (Nix) 2.23.0
What system does this bug occur on?
macOS (Apple Silicon)
Debug logs
No response
@ineiti I'd suggest running devbox add "darwin.apple_sdk.frameworks.Security" --platform=x86_64-darwin,aarch64-darwin.
With that, I am able to run cargo build on my x86_64-darwin machine.
Let us know if that does, or does not, work for you?
@savil Thanks a lot, that solves the problem and it compiles fine now! I did not know about this package, and I did spend 30 minutes on Google with the error message before opening this issue. How could I have discovered this?
Some questions:
- Why does
floxmanage to compile this by default? Is it because it doesn't includeclang? I checkedwhich ar, andfloxgives the/usr/bin/ar, whiledevboxgives it's own ar in a clang subdirectory. - Should
devboxhave some of these packages as default? - Do you want me to close the issue? Or is it worth investigating this further?
Those are great questions. I think Devbox should do better here, and in particular since this is a bit of an FAQ for Rust with Macs, we should make it Just Work ™️ . Lets leave this task open for a bit. I'll look into it more this week.
There are some considerations in my mind:
- is it a good idea to use the nix packaged Security Framework instead of relying on the library in your MacOS? I'd like to look into how frequently and quickly that package is updated. I am wondering if there is a reproducibility versus security tradeoff here.
- can we modify Devbox's Rust plugin to guide users? Hopefully, this can have users avoid the experience you had.
To your questions:
- Not super familiar with the internals of
flox(they are a GPL project, so I'll have to tread carefully there), but it sounds like they are relying on the native MacOS environment. This can hurt reproducibility since a colleague of yours on Linux may get a different set of tools, but then again, at least it worked for you so that's better than your Devbox experience. - Yes IMO, see my second consideration above.
- Not yet :)
With a simple rust project I'm not able to run cargo build
{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.4/.schema/devbox.schema.json",
"packages": {
"cargo": "latest",
"libiconv": "latest",
"darwin.apple_sdk.frameworks.Security": {
"platforms": ["x86_64-darwin", "aarch64-darwin"]
}
},
"shell": {
"init_hook": ["echo 'Welcome to devbox!' > /dev/null"],
"scripts": {
"test": ["echo \"Error: no test specified\" && exit 1"]
}
}
}
(fresh new mac, very nice test :) )
With a simple rust project I'm not able to run
cargo build
What is the error message when it fails?
Also, did you actually install cargo? Because with your devbox.json you only install rustup - look at my init_hook from above.
{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.4/.schema/devbox.schema.json",
"packages": {
"cargo": "latest",
"libiconv": "latest",
"darwin.apple_sdk.frameworks.Security": {
"platforms": ["x86_64-darwin", "aarch64-darwin"],
},
"rustup": "latest",
},
"shell": {
"init_hook": [
"if [ ! -d $RUSTUP_HOME/toolchains -o ! -d $RUSTUP_HOME/toolchains/stable ]; then rustup default stable; fi",
],
"scripts": {
"test": [
"echo \"Error: no test specified\" && exit 1",
],
},
},
}
Error is
= note: ld: framework not found SystemConfiguration
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
Adding also
devbox add "darwin.apple_sdk.frameworks.SystemConfiguration" --platform=x86_64-darwin,aarch64-darwin
doesn't help
Ok now it is working, for some reasons I removed .devboxfolder and re-did everything from scratch and it is working :)
@savil - Is there a place this information should be added? The rustup default stable might be nice to echo when devbox add rustup is called. But the darwin.apple_sdk.frameworks information is really crucial! Do you think creating a PR against
https://github.com/NixOS/nixpkgs/blob/c858402c2a629211153137fb8d39be9fde4694ff/pkgs/development/tools/rust/rustup/default.nix#L69
is a good idea and will be included?
@ineiti
A few thoughts:
- A small update we could do is print a Notice in the Devbox rustup Plugin that one may encounter errors on MacOS pertaining to missing frameworks, such as
note: ld: framework not found SystemConfigurationand one solution is to add the package asdevbox add "darwin.apple_sdk.frameworks.SystemConfiguration" --platform=x86_64-darwin,aarch64-darwin. - We should also add this note to https://www.jetify.com/docs/devbox/devbox_examples/languages/rust/ and our FAQ.
- Circling back to a discussion point from earlier (above). Apple SDKs on nixpkgs should soon be up-to-date much more frequently. Previously, they had tended to lag behind. See https://discourse.nixos.org/t/on-the-future-of-darwin-sdks-or-how-you-can-stop-worrying-and-put-the-sdk-in-build-inputs/50574.
re: adding the apple frameworks by default to the nixpkgs definition of rustup in MacOS I'd suggest asking in the NixOS Discourse (https://discourse.nixos.org) if that would be welcome. I can imagine some arguments for and against it, but it seems like a good discussion to have. Maybe @reckenrode from the above NixOS Discourse post may have some thoughts.
After this staging-next cycle, the stdenv in master (and when 24.11 releases) will include a full SDK. It should have all the frameworks needed to build macOS applications and libraries (like OpenSSL). It also propagates libiconv, which should remove the need to conditionally add it for Rust applications.
I have some documentation I need to write for the release, but the gist of using a new SDK is you add it as a build input. The SDK uses setup hooks to set the latest one from your inputs plus propagated inputs, so there is no way to accidentally mix them.
Edit: for reference, the following SDKs will be available in 24.11: 10.12.2 (default on x86_64-darwin), 10.13.2, 10.14.6, 10.15.6, 11.3 (default on aarch64-darwin), 12.3, 13.3, 14.4, 15.0.
The default and minimum version for x86_64-darwin is being updated to match aarch64-darwin for 25.05. They will be updated more regularly to better match the platform’s supported versions. Additionally, Darwin will use clang-19 by default and will(probably) use darwin.ICU and darwin.libpcap by default for icu and libpcap respectively.
I also wanted to add that source release packages (like libiconv, ICU, and libpcap) have been updated to the source releases for macOS 15. They will be updated as new ones are made available.
@reckenrode thanks a lot for the update - so I guess I'll just wait for the 24.11 release and won't bother with adding the notes to the rustup nix package.
@savil "is it a good idea to use the nix packaged Security Framework instead of relying on the library in your MacOS"
As far as I know, the nix package essentially just wraps the library already on your system, so it can be exposed to Nix --- therefore, the corresponding nix package's "version" is exactly the same as the Framework on your system.
The old package exposed the framework from the SDK. For example, if you are running 15.5, the framework is 11.3, and your code needs a feature from 14.0; it will fail to compile. This is accomplished by using text-based stubs that have only the symbols available for that platform and version.
Note that as of 24.11, the framework packages are stubs that do nothing. The pattern was changed as described in the announcement and documentation. As of 25.05, the stub packages are aliases. Out of tree users can continue using them (although they still do nothing), but their use in nixpkgs is disallowed. They will be removed in 25.11 when the minimum supported version of macOS is bumped to 14.0.
Is there a way to install all frameworks at once instead of playing whack-a-mole? I tried apple-sdk_12, but while the actual files are in /nix/store, it seems like the proper "hooks" to add the right environment variables to the shell (I forgot the terminology Nix uses here) are not set with this package.
Make sure to add it to your shell’s buildInputs not packages. The latter maps to nativeBuildInputs, which is wrong for the SDK.
(Or whatever the equivalent is for devbox.)
I'm not sure there is an equivalent.
In the meantime, I was able to hack around it using this:
"env": {
"NIX_CFLAGS_COMPILE_aarch64_apple_darwin": "-iframework $DEVBOX_PACKAGES_DIR/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/ -idirafter $DEVBOX_PACKAGES_DIR/include -idirafter $DEVBOX_PACKAGES_DIR/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/",
"NIX_SSL_CERT_FILE": "\"$HOME/.config/home-manager/cert.pem\"", //security list-keychains | xargs -I{} sh -c 'security find-certificate -a -p "{}" >> ${keychainPath}; cat /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt >> ${keychainPath},
"LIBRARY_PATH": "$DEVBOX_PACKAGES_DIR/lib:$LIBRARY_PATH"
},