I’m trying to build a trivial Rust program on Darwin with nix-shell and cargo. It uses the notify crate. I created a minimal example here: https://github.com/bwolf/notify-nix-darwin.
Using cargo build I get the following error (truncated):
Undefined symbols for architecture x86_64:
"_CFURLResourceIsReachable", referenced from:
fsevent_sys::core_foundation::str_path_to_cfstring_ref::hb6fc1a8adf52fba2 in libfsevent_sys-64f7ee290c44ecde.rlib(fsevent_sys-64f7ee290c44ecde.fsevent_sys.aaucxc5j-cgu.6.rcgu.o)
ld: symbol(s) not found for architecture x86_64
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)
That symbol doesn’t seem to exist in Nix’s version of CoreFoundation.framework.
> nm /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation | grep _CFURLResourceIsReachable
000000000008e2ad T _CFURLResourceIsReachable
> nm /nix/store/imvxk8636h9vj8hq8zh8wfh10x67w771-swift-corefoundation/Library/Frameworks/CoreFoundation.framework/Versions/Current/CoreFoundation | grep _CFURLResourceIsReachable
# no output
The function itself is documented as macOS 10.6+ and the CoreFoundation library includes other CFURL symbols, but not that one. It’s also present in CFURL.h, so I have no idea why the symbol is missing. It’s not the only one too, the other resource-related functions seem to be missing as well.
I looked up reverse dependencies of the notify crate and saw mdbook, which we have a package for, so I checked what mdbook is doing and found
# Because CoreServices needs to be updated,
# but Apple won't release the source.
broken = stdenv.isDarwin;
I’m guessing it’s due to this same issue, though I can’t say for certain.
Then I checked another crate that depends on it, watchexec, and found this:
# FIXME: Use impure version of CoreFoundation because of missing symbols.
# Undefined symbols for architecture x86_64: "_CFURLResourceIsReachable"
preConfigure = stdenv.lib.optionalString stdenv.isDarwin ''
export NIX_LDFLAGS="-F${CoreFoundation}/Library/Frameworks -framework CoreFoundation $NIX_LDFLAGS"
'';
So that looks like a fix for your issue right there, though it’s definitely impure. Still, seems like the best approach for the time being.
EDIT: After looking into this some more, darwin.cf-private is supposed to contain the Nix-built CoreFoundation, but it includes a setup hook that adds the system CoreFoundation to NIX_LDFLAGS. I don’t know how setup hooks interact with nix-shell, but at the very least it works when actually using Nix to build a derivation. If you can figure out how to make setup hooks from dependencies work then you should be good.
I think I know why the symbols are missing from Nix’s CoreFoundation. Nix must have built CoreFoundation from source (of which macOS 10.10.5 is the last version where source was published). I just checked, and the CFURL.c from the public source doesn’t implement those functions. They’re in the header, but not the implementation.
Thanks @lilyball for your well structured analysis and sharp deductions. I learned a lot from it. In the meantime I came to the same conclusion that nix-build is working with cf-private, but nix-shell is not. I have too little understanding about the whole system currently to investigate further into the setup-hooks you mentioned. Hopefully this will be fixed some day.
@bwolf My best guess is that nix-shell leaves a setup hook script in your PATH that you need to run to actually apply the NIX_LDFLAGS changes, but I don’t know for sure.