Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

  • Clang(LLVM) compile with frameworks
  • How to specify framework in clang? - Apple Community

  • Rust: 1.24.0

  • Cargo: 0.25.0
  • jsonwebtoken: 0.4.0
  • cargo-watch: default version from cargo install cargo-watch

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.

like image 774
Savanni D'Gerinel Avatar asked Feb 03 '23 23:02

Savanni D'Gerinel


1 Answers

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.

like image 62
Savanni D'Gerinel Avatar answered Feb 06 '23 14:02

Savanni D'Gerinel