How can I make macOS frameworks available to clang in a Nix environment?
Asked Answered
U

1

13

I'm on macOS 10.13.5, learning to program Rust, and I use Nix to control my development environment.

Some actions, such as including the jsonwebtoken library or installing the cargo-watch module, cause a build that requires a macOS framework that appears to not be installed. I get this error message:

  = note: ld: framework not found CoreServices
          clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)

error: aborting due to previous error

error: failed to compile `cargo-watch v6.0.0`, intermediate artifacts can be found at `/var/folders/13/84dj8yr54_1c_pn0s8n7444h0000gn/T/cargo-install.lYPZaEduUBdu`

Caused by:
  Could not compile `cargo-watch`.

This is an abbreviated version of the clang command that fails:

error: linking with `/nix/store/9j864incgjx7kqggbpisdi3nmssy4qm5-clang-wrapper-5.0.2/bin/cc` failed: exit code: 1
  |
  = note: "/nix/store/9j864incgjx7kqggbpisdi3nmssy4qm5-clang-wrapper-5.0.2/bin/cc" "-m64" "-L" ... "/nix/store/rfp87664xzhl6zv7dx5c1hixasqfxkp4-rustc-1.24.0/lib/rustlib/x86_64-apple-darwin/lib/libcompiler_builtins-ba331b20e371c580.rlib" "-framework" "CoreServices" "-framework" "CoreServices" "-l" "System" "-l" "resolv" "-l" "pthread" "-l" "c" "-l" "m"

The only thing that I have found to try was to add frameworks to my PATH, but either that answer is wrong or the PATH environment variable isn't able to go through cargo all the way to where I'm doing the build in question.

How do I tell clang where to look for the frameworks? Does it involve a change to my working environment, or do I need to be looking into changing the build process for the crates that I want to install?

More information

I discovered the clang -Xlinker -v command, and the output is quite interesting:

@(#)PROGRAM:ld  PROJECT:ld64-274.2
configured to support archs: armv6 armv7 armv7s arm64 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em (tvOS)
Library search paths:
    /nix/store/ql6xbmdplca4sjpk0pz647p7djzri03c-libc++-5.0.2/lib
    /nix/store/rfp87664xzhl6zv7dx5c1hixasqfxkp4-rustc-1.24.0/lib
    /nix/store/ql6xbmdplca4sjpk0pz647p7djzri03c-libc++-5.0.2/lib
    /nix/store/rfp87664xzhl6zv7dx5c1hixasqfxkp4-rustc-1.24.0/lib
    /nix/store/8ykfqv6jx9jvfhnc4cdygdzg0piy8253-Libsystem-osx-10.11.6/lib
    /nix/store/4papfih2r9xlsl9m7hlisparij8k9zaq-clang-5.0.2-lib/lib
Framework search paths:
    /nix/store/hc6d711vwlwnn9swmkdpi9nbswbqg6h0-CF-osx-10.10.5/Library/Frameworks
    /nix/store/hc6d711vwlwnn9swmkdpi9nbswbqg6h0-CF-osx-10.10.5/Library/Frameworks
Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
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)

This seems to point to things missing from my Nix shell and not the operating system or even clang itself.

Understrapper answered 3/7, 2018 at 18:50 Comment(0)
U
17

Apparently Nix both provides packages for standard Apple frameworks and sandboxes the environment enough that standard frameworks are unavailable.

Most of what I discovered for this solution came from Use proper SDK and command-line tools on OS X 10.11 and then from examining vim-plugins nix derivation.

First step is to actually install the frameworks that my project needs. They all live in nixpkgs.darwin.apple_sdk.frameworks.

Doing that gets most of the link working, but then _CFURLResourceIsReachable is an undefined symbol on my platform. I solve that with an updated NIX_LDFLAGS variable (as suggested in the vim-plugins nix derivation). The end result for my project is this shell.nix file:

let
    pkgs = import <stable> {};
    frameworks = pkgs.darwin.apple_sdk.frameworks;
in pkgs.stdenv.mkDerivation {
    name = "orizentic";

    buildInputs = [ pkgs.rustc
                    pkgs.cargo
                    frameworks.Security
                    frameworks.CoreFoundation
                    frameworks.CoreServices
                  ];

    shellHook = ''
        export PS1="[$name] \[$txtgrn\]\u@\h\[$txtwht\]:\[$bldpur\]\w \[$txtcyn\]\$git_branch\[$txtred\]\$git_dirty \[$bldylw\]\$aws_env\[$txtrst\]\$ "
        export NIX_LDFLAGS="-F${frameworks.CoreFoundation}/Library/Frameworks -framework CoreFoundation $NIX_LDFLAGS";
    '';
}

This gives me the cargo-watch package (which depends on CoreServices and CoreFoundation). It also apparently resolves the dependency jsonwebtoken has on Security though I have not managed to validate that yet.

Understrapper answered 3/7, 2018 at 19:47 Comment(3)
I actually have the same issue, but I can't run nix-env -i nixpkgs.drawin.apple_sdk.frameworks as neither darwin, apple_sdk, nor frameworks appear to exist. Is there a step you have to do to get them to show up, or are they tied to your OS X version?Effete
I find nix-env to be particularly tricky when it comes to actually finding packages. But as you would be installing by path instead of by name, it would need to be something more like nix-env -i -A nixpkgs.darwin.apple_sdk.frameworks.... And you would need to specify the framework, not the entire frameworks attribute.Dolomites
you could also install nixpkgs.darwin.apple_sdk which gives you the entire SDK with all the frameworksBurnett

© 2022 - 2024 — McMap. All rights reserved.