summary refs log tree commit diff
path: root/pkgs/stdenv
diff options
context:
space:
mode:
authorRandy Eckenrode <randy@largeandhighquality.com>2023-10-26 01:04:35 -0400
committerRandy Eckenrode <randy@largeandhighquality.com>2023-10-26 13:26:39 -0400
commitc2a623b52a1f10dfcda9642217eac39502ecbf26 (patch)
tree6e248dfce877892ed2f846d2a072df4fae269cc8 /pkgs/stdenv
parent08be9a9577c3dd88f0e782daedb152403c38d186 (diff)
downloadnixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.tar
nixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.tar.gz
nixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.tar.bz2
nixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.tar.lz
nixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.tar.xz
nixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.tar.zst
nixpkgs-c2a623b52a1f10dfcda9642217eac39502ecbf26.zip
stdenvAdapters: add overrideSDK
This is a replacement for using `darwin.apple_sdk_<ver>.callPackage`.
Instead of injecting the required packages, it provides a stdenv adapter
that modifies the derivation’s build inputs to use the requested SDK
versions. This modification extends to any build inputs propagated to it
as well. The `callPackage` approach is not deprecated yet, but it is
expected that it will be eventually.

Note that this is an MVP. It should work with most packages, but it only
handles build inputs and also only handles frameworks. Once more SDKs
are added (after #229210 is merged) and the SDK structure is normalized,
it can be extended to handle any package in the SDK namespace.

Cross-compilation may or may not work. Any cross-related issues can be
addressed after #256590 is merged.
Diffstat (limited to 'pkgs/stdenv')
-rw-r--r--pkgs/stdenv/adapters.nix99
1 files changed, 99 insertions, 0 deletions
diff --git a/pkgs/stdenv/adapters.nix b/pkgs/stdenv/adapters.nix
index 7c64fd7e392..a7985b474ed 100644
--- a/pkgs/stdenv/adapters.nix
+++ b/pkgs/stdenv/adapters.nix
@@ -246,4 +246,103 @@ rec {
         env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}"; };
       });
     });
+
+  # Overriding the SDK changes the Darwin SDK used to build the package, which:
+  # * Ensures that the compiler and bintools have the correct Libsystem version; and
+  # * Replaces any SDK references with those in the SDK corresponding to the requested SDK version.
+  #
+  # `sdkVersion` can be any of the following:
+  # * A version string indicating the requested SDK version; or
+  # * An attrset consisting of either or both of the following fields: darwinSdkVersion and darwinMinVersion.
+  overrideSDK = stdenv: sdkVersion:
+    let
+      inherit (
+        { inherit (stdenv.hostPlatform) darwinMinVersion darwinSdkVersion; }
+        // (if lib.isAttrs sdkVersion then sdkVersion else { darwinSdkVersion = sdkVersion; })
+      ) darwinMinVersion darwinSdkVersion;
+
+      sdk = pkgs.darwin."apple_sdk_${lib.replaceStrings [ "." ] [ "_" ] darwinSdkVersion}";
+
+      isSDKFramework = pkg: lib.hasPrefix "apple-framework-" (lib.getName pkg);
+
+      replacePropagatedFrameworks = pkg:
+        let
+          propagatedFrameworks = lib.filter isSDKFramework pkg.propagatedBuildInputs;
+          env = {
+            inherit (pkg) outputs;
+            # Map the old frameworks to new and the package’s outputs to their original outPaths.
+            # The mappings are rendered into tab-separated files to be read back with `read`.
+            frameworks = lib.concatMapStrings (pkg: "${pkg}\t${mapPackageToSDK pkg}\n") propagatedFrameworks;
+            pkgOutputs = lib.concatMapStrings (output: "${output}\t${(lib.getOutput output pkg).outPath}\n") pkg.outputs;
+            passAsFile = [ "frameworks" "pkgOutputs" ];
+          };
+        in
+        if lib.length propagatedFrameworks > 0
+          then pkgs.runCommand pkg.name env ''
+            # Iterate over the outputs in the package being replaced to make sure the proxy is
+            # a fully functional replacement. This is like `symlinkJoin` except for outputs and
+            # the contents of `nix-support`, which will be customized for the requested SDK.
+            while IFS=$'\t\n' read -r outputName pkgOutputPath; do
+              mkdir -p "''${!outputName}"
+
+              for targetPath in "$pkgOutputPath"/*; do
+                targetName=$(basename "$targetPath")
+
+                # `nix-support` is special-cased because any propagated inputs need their SDK
+                # frameworks replaced with those from the requested SDK.
+                if [ "$targetName" == "nix-support" ]; then
+                  mkdir "''${!outputName}/nix-support"
+
+                  for file in "$targetPath"/*; do
+                    fileName=$(basename "$file")
+
+                    if [ "$fileName" == "propagated-build-inputs" ]; then
+                      cp "$file" "''${!outputName}/nix-support/$fileName"
+
+                      while IFS=$'\t\n' read -r oldFramework newFramework; do
+                        substituteInPlace "''${!outputName}/nix-support/$fileName" \
+                          --replace "$oldFramework" "$newFramework"
+                      done < "$frameworksPath"
+                    fi
+                  done
+                else
+                  ln -s "$targetPath" "''${!outputName}/$targetName"
+                fi
+              done
+            done < "$pkgOutputsPath"
+          ''
+        else pkg;
+
+      # Remap a framework from one SDK version to another.
+      mapPackageToSDK = pkg:
+        let
+          name = lib.getName pkg;
+          framework = lib.removePrefix "apple-framework-" name;
+        in
+        if isSDKFramework pkg
+          then sdk.frameworks."${framework}"
+          else replacePropagatedFrameworks pkg;
+
+      mapInputsToSDK = inputs: args:
+        lib.genAttrs inputs (input: map mapPackageToSDK (args."${input}" or [ ]));
+
+      mkCC = cc: cc.override {
+        bintools = cc.bintools.override { libc = sdk.Libsystem; };
+        libc = sdk.Libsystem;
+      };
+    in
+    # TODO: make this work across all input types and not just propagatedBuildInputs
+    stdenv.override (old: {
+      buildPlatform = old.buildPlatform // { inherit darwinMinVersion darwinSdkVersion; };
+      hostPlatform = old.hostPlatform // { inherit darwinMinVersion darwinSdkVersion; };
+      targetPlatform = old.targetPlatform // { inherit darwinMinVersion darwinSdkVersion; };
+
+      allowedRequisites = null;
+      cc = mkCC old.cc;
+
+      extraBuildInputs = [sdk.frameworks.CoreFoundation ];
+      mkDerivationFromStdenv = extendMkDerivationArgs old (mapInputsToSDK [
+        "buildInputs"
+      ]);
+    });
 }