diff options
author | Randy Eckenrode <randy@largeandhighquality.com> | 2023-10-26 01:04:35 -0400 |
---|---|---|
committer | Randy Eckenrode <randy@largeandhighquality.com> | 2023-10-26 13:26:39 -0400 |
commit | c2a623b52a1f10dfcda9642217eac39502ecbf26 (patch) | |
tree | 6e248dfce877892ed2f846d2a072df4fae269cc8 | |
parent | 08be9a9577c3dd88f0e782daedb152403c38d186 (diff) |
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.
-rw-r--r-- | pkgs/stdenv/adapters.nix | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/pkgs/stdenv/adapters.nix b/pkgs/stdenv/adapters.nix index 7c64fd7e39284..a7985b474ed78 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" + ]); + }); } |