Using Darwin SDKs from nixpkgs.darwin.xcode

Hello,

thanks to the great work on nix-darwin, the SDKs are now nicely separated.

I’m trying to create a devShell for a fairly complex project that uses:

  1. pkgs.llvmPackages_16.stdenv to build a few C++ files
  2. Xcode’s (pkgs.darwin.xcode_16_2) clang (xcrun -sdk iphoneos... -find clang) to build a binary for iOS.

Getting the second part to work seems difficult, because xcodebuild doesn’t recognize darwin.xcode. Normally you’d set DEVELOPER_DIR and SDKROOT to point to darwin.xcode/.... But here it will break the standard env.

What I would like to get to work is that xcrun/xcodebuild -showsdks uses the SDKs from darwin.xcode while still leaving the CMake/stdenv environment intact. See the example (nix build -L github:pascalj/nix-darwin-example):

{
 # ...
  outputs =
    { nixpkgs, ... }:
    let
      system = "aarch64-darwin";
      pkgs = import nixpkgs { inherit system; };
      # Xcode version I'd like to use
      xcode = pkgs.darwin.xcode_16_2;
    in
    {

      packages."${system}".default = pkgs.llvmPackages_16.stdenv.mkDerivation {
        name = "hello-world";
        src = ./.;
        nativeBuildInputs = [ pkgs.cmake xcode ];

        preBuild = ''
          # DEVELOPER_DIR and SDKROOT point to pkgs.apple-sdk
          env
          # Lists only "macOS 11.3                      -sdk macosx11.3"
          ${pkgs.xcodebuild}/bin/xcodebuild -showsdks
        '';

      };
    };
}

In the example flake on GH I set CMAKE_OSX_SYSROOT to xcode_16_2’s SDKROOT, so you can see the failing build: /nix/store/j64i7nhzwx2gvbsi2glnzywlbvpriwvw-libcxx-16.0.6-dev/include/c++/v1/ratio:99:11: error: reference to unresolved using declaration. It also fails to look up files from the C++ stdlib.

If I understand it correctly, a proper solution would be to bootstrap using darwin.xcode, so that llvmPackages shares the same SDKROOT (basically introduce a custom pkgs.apple-sdk with all other SDKs). However, that seems like a larger undertaking and it would mean that there can only ever be one Xcode available.

Is there a simple alternative that I’m missing, e.g. just wrapping xcodebuild/xcrun? If not, do you have any hints for getting started with the custom version?

Any help is welcome - thank you!

As part of the SDK refactor, the Darwin toolchain in nixpkgs was changed to work more like a native toolchain. In particular, it expects to find the SDK from nixpkgs at SDKROOT. This was necessary to support language ecosystems that either try to invoke clang unwrapped (such as bindgen in Rust) or handle SDKs themselves (such as Zig).

Fortunately, there is a workaround when you need SDKROOT to point to a native toolchain’s SDK. When Clang finds SDKROOT in the environment, it uses that as an implicit sysroot. If you provide the sysroot explicitly, Clang will ignore SDKROOT.

Adding the following to your example flake’s derivation allowed me to build it:

env.NIX_CFLAGS_COMPILE = "-isysroot ${pkgs.apple-sdk.sdkroot}";

Thank you very much, this solves the problem perfectly!

For folks who have a similar scenario, here are some additional things I had to change for my specific project to build. Not best practice, but it may be a starting point to narrow down issues with large, existing code bases:

  • Alias xcrun to /usr/bin/xcrun. The xcbuild version of xcrun does not work well with absolute paths to SDKs, whereas the native one does. This is probably only an issue when cmake is selecting SDKs.
  • Alias some more binaries to /usr/bin/, since the GNU and coreutils versions differ in subtle ways from the native ones.
  • Raise the deployment target version using pkgs.darwinMinVersionHook as described in the documentation.
1 Like

FYI, if coreutils or other GNU tools are not compatible, many of the native commands are packaged. It’s likely you need either darwin.file_cmds or darwin.text_cmds.

1 Like