diff --git a/pkgs/stdenv/adapters.nix b/pkgs/stdenv/adapters.nix index b566eb6291eb..c5815d483bde 100644 --- a/pkgs/stdenv/adapters.nix +++ b/pkgs/stdenv/adapters.nix @@ -321,17 +321,9 @@ rec { # `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 = import ./darwin/override-sdk.nix { - inherit lib extendMkDerivationArgs; - inherit (pkgs) - stdenvNoCC - pkgsBuildBuild - pkgsBuildHost - pkgsBuildTarget - pkgsHostHost - pkgsHostTarget - pkgsTargetTarget; - }; + # + # Note: `overrideSDK` is deprecated. Add the versioned variants of `apple-sdk` to `buildInputs` change the SDK. + overrideSDK = pkgs.callPackage ./darwin/override-sdk.nix { inherit lib extendMkDerivationArgs; }; withDefaultHardeningFlags = defaultHardeningFlags: stdenv: let bintools = let diff --git a/pkgs/stdenv/darwin/override-sdk.nix b/pkgs/stdenv/darwin/override-sdk.nix index 50ebb814522c..243b8e2633d7 100644 --- a/pkgs/stdenv/darwin/override-sdk.nix +++ b/pkgs/stdenv/darwin/override-sdk.nix @@ -1,445 +1,41 @@ -# The basic algorithm is to rewrite the propagated inputs of a package and any of its -# own propagated inputs recursively to replace references from the default SDK with -# those from the requested SDK version. This is done across all propagated inputs to -# avoid making assumptions about how those inputs are being used. -# -# For example, packages may propagate target-target dependencies with the expectation that -# they will be just build inputs when the package itself is used as a native build input. -# -# To support this use case and operate without regard to the original package set, -# `overrideSDK` creates a mapping from the default SDK in all package categories to the -# requested SDK. If the lookup fails, it is assumed the package is not part of the SDK. -# Non-SDK packages are processed per the algorithm described above. +# This is a compatibility shim with `overrideSDK`. +# Note: `overrideSDK` is deprecated. It will be added to `aliases.nix` after in-tree usage has been cleaned up. { lib, stdenvNoCC, extendMkDerivationArgs, - pkgsBuildBuild, - pkgsBuildHost, - pkgsBuildTarget, - pkgsHostHost, pkgsHostTarget, - pkgsTargetTarget, -}@args: +}: +stdenv: sdkVersion: let - # Takes a mapping from a package to its replacement and transforms it into a list of - # mappings by output (e.g., a package with three outputs produces a list of size 3). - expandOutputs = - mapping: - map (output: { - name = builtins.unsafeDiscardStringContext (lib.getOutput output mapping.original); - value = lib.getOutput output mapping.replacement; - }) mapping.original.outputs; + newVersion = { + inherit (stdenv.hostPlatform) darwinMinVersion darwinSdkVersion; + } // (if lib.isAttrs sdkVersion then sdkVersion else { darwinSdkVersion = sdkVersion; }); - # Produces a list of mappings from the default SDK to the new SDK (`sdk`). - # `attr` indicates which SDK path to remap (e.g., `libs` remaps `apple_sdk.libs`). - # - # TODO: Update once the SDKs have been refactored to a common pattern to better handle - # frameworks that are not present in both SDKs. Currently, they’re dropped. - mkMapping = - attr: pkgs: sdk: - lib.foldlAttrs ( - mappings: name: pkg: - let - # Avoid evaluation failures due to missing or throwing - # frameworks (such as QuickTime in the 11.0 SDK). - maybeReplacement = builtins.tryEval sdk.${attr}.${name} or { success = false; }; - in - if maybeReplacement.success then - mappings - ++ expandOutputs { - original = pkg; - replacement = maybeReplacement.value; - } - else - mappings - ) [ ] pkgs.darwin.apple_sdk.${attr}; + inherit (newVersion) darwinMinVersion darwinSdkVersion; - # Produces a list of overrides for the given package set, SDK, and version. - # If you want to manually specify a mapping, this is where you should do it. - mkOverrides = - pkgs: sdk: version: - lib.concatMap expandOutputs [ - # Libsystem needs to match the one used by the SDK or weird errors happen. - { - original = pkgs.darwin.apple_sdk.Libsystem; - replacement = sdk.Libsystem; - } - # This is different to `pkgs.darwin.apple_sdk.Libsystem` on `aarch64-darwin`. - # Isn’t that neat? I think that’s neat. Don’t do macOS SDKs like this. - { - original = pkgs.darwin.Libsystem; - replacement = sdk.Libsystem; - } - # Make sure darwin.CF is mapped to the correct version for the SDK. - { - original = pkgs.darwin.CF; - replacement = sdk.frameworks.CoreFoundation; - } - # libobjc needs to be handled specially because it’s not actually in the SDK. - { - original = pkgs.darwin.libobjc; - replacement = sdk.objc4; - } - # Unfortunately, this is not consistent between Darwin SDKs in nixpkgs, so - # try both versions to map between them. - { - original = pkgs.darwin.apple_sdk.sdk or pkgs.darwin.apple_sdk.MacOSX-SDK; - replacement = sdk.sdk or sdk.MacOSX-SDK; - } - # Remap the SDK root. This is used by clang to set the SDK version when - # linking. This behavior is automatic by clang and can’t be overriden. - # Otherwise, without the SDK root set, the SDK version will be inferred to - # be the same as the deployment target, which is not usually what you want. - { - original = pkgs.darwin.apple_sdk.sdkRoot; - replacement = sdk.sdkRoot; - } - # Override xcodebuild because it hardcodes the SDK version. - # TODO: Make xcodebuild defer to the SDK root set in the stdenv. - { - original = pkgs.xcodebuild; - replacement = pkgs.xcodebuild.override { - # Do the override manually to avoid an infinite recursion. - stdenv = pkgs.stdenv.override (old: { - buildPlatform = mkPlatform version old.buildPlatform; - hostPlatform = mkPlatform version old.hostPlatform; - targetPlatform = mkPlatform version old.targetPlatform; + sdkMapping = { + "11.0" = pkgsHostTarget.apple-sdk_11; + "12.3" = pkgsHostTarget.apple-sdk_12; + }; - allowedRequisites = null; - cc = mkCC sdk.Libsystem old.cc; - }); - }; - } - ]; + minVersionHook = pkgsHostTarget.darwinMinVersionHook darwinMinVersion; - mkBintools = - Libsystem: bintools: - if bintools ? override then - bintools.override { libc = Libsystem; } - else - let - # `override` isn’t available, so bintools has to be rewrapped with the new libc. - # Most of the required arguments can be recovered except for `postLinkSignHook` - # and `signingUtils`, which have to be scrapped from the original’s `postFixup`. - # This isn’t ideal, but it works. - postFixup = lib.splitString "\n" bintools.postFixup; + resolvedSdk = + sdkMapping.${darwinSdkVersion} or (lib.throw '' + `overrideSDK` and `darwin.apple_sdk_11_0.callPackage` are deprecated. + Only the 11.0 and 12.3 SDKs are supported using them. Please use + the versioned `apple-sdk` variants to use other SDK versions. - postLinkSignHook = lib.pipe postFixup [ - (lib.findFirst (lib.hasPrefix "echo 'source") null) - (builtins.match "^echo 'source (.*-post-link-sign-hook)' >> \\$out/nix-support/post-link-hook$") - lib.head - ]; - - signingUtils = lib.pipe postFixup [ - (lib.findFirst (lib.hasPrefix "export signingUtils") null) - (builtins.match "^export signingUtils=(.*)$") - lib.head - ]; - - newBintools = pkgsBuildTarget.wrapBintoolsWith { - inherit (bintools) name; - - buildPackages = { }; - libc = Libsystem; - - inherit lib; - - coreutils = bintools.coreutils_bin; - gnugrep = bintools.gnugrep_bin; - - inherit (bintools) bintools; - - inherit postLinkSignHook signingUtils; - }; - in - lib.getOutput bintools.outputName newBintools; - - mkCC = - Libsystem: cc: - if cc ? override then - cc.override { - bintools = mkBintools Libsystem cc.bintools; - libc = Libsystem; - } - else - builtins.throw "CC has no override: ${cc}"; - - mkPlatform = - version: platform: - platform - // lib.optionalAttrs platform.isDarwin { inherit (version) darwinMinVersion darwinSdkVersion; }; - - # Creates a stub package. Unchanged files from the original package are symlinked - # into the package. The contents of `nix-support` are updated to reference any - # replaced packages. - # - # Note: `env` is an attrset containing `outputs` and `dependencies`. - # `dependencies` is a regex passed to sed and must be `passAsFile`. - mkProxyPackage = - name: env: - stdenvNoCC.mkDerivation { - inherit name; - - inherit (env) outputs replacements sourceOutputs; - - # Take advantage of the fact that replacements and sourceOutputs will be passed - # via JSON and parsed into environment variables. - __structuredAttrs = true; - - buildCommand = '' - # Map 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. - function replacePropagatedInputs() { - local sourcePath=$1 - local targetPath=$2 - - mkdir -p "$targetPath" - - local sourceFile - for sourceFile in "$sourcePath"/*; do - local fileName=$(basename "$sourceFile") - local targetFile="$targetPath/$fileName" - - if [ -d "$sourceFile" ]; then - replacePropagatedInputs "$sourceFile" "$targetPath/$fileName" - # Check to see if any of the files in the folder were replaced. - # Otherwise, replace the folder with a symlink if none were changed. - if [ "$(find -maxdepth 1 "$targetPath/$fileName" -not -type l)" = "" ]; then - rm "$targetPath/$fileName"/* - ln -s "$sourceFile" "$targetPath/$fileName" - fi - else - cp "$sourceFile" "$targetFile" - local original - for original in "''${!replacements[@]}"; do - substituteInPlace "$targetFile" \ - --replace-quiet "$original" "''${replacements[$original]}" - done - if cmp -s "$sourceFile" "$targetFile"; then - rm "$targetFile" - ln -s "$sourceFile" "$targetFile" - fi - fi - done - } - - local outputName - for outputName in "''${!outputs[@]}"; do - local outPath=''${outputs[$outputName]} - mkdir -p "$outPath" - - local sourcePath - for sourcePath in "''${sourceOutputs[$outputName]}"/*; do - sourceName=$(basename "$sourcePath") - # `nix-support` is special-cased because any propagated inputs need their - # SDK frameworks replaced with those from the requested SDK. - if [ "$sourceName" == "nix-support" ]; then - replacePropagatedInputs "$sourcePath" "$outPath/nix-support" - else - ln -s "$sourcePath" "$outPath/$sourceName" - fi - done - done - ''; - }; - - # Gets all propagated inputs in a package. This does not recurse. - getPropagatedInputs = - pkg: - lib.optionals (lib.isDerivation pkg) ( - lib.concatMap (input: pkg.${input} or [ ]) [ - "depsBuildBuildPropagated" - "propagatedNativeBuildInputs" - "depsBuildTargetPropagated" - "depsHostHostPropagated" - "propagatedBuildInputs" - "depsTargetTargetPropagated" - ] - ); - - # Looks up the replacement for `pkg` in the `newPackages` mapping. If `pkg` is a - # compiler (meaning it has a `libc` attribute), the compiler will be overriden. - getReplacement = - newPackages: pkg: - let - pkgOrCC = - if pkg.libc or null != null then - # Heuristic to determine whether package is a compiler or bintools. - if pkg.wrapperName == "CC_WRAPPER" then - mkCC (getReplacement newPackages pkg.libc) pkg - else - mkBintools (getReplacement newPackages pkg.libc) pkg - else - pkg; - in - if lib.isDerivation pkg then - newPackages.${builtins.unsafeDiscardStringContext pkg} or pkgOrCC - else - pkg; - - # Replaces all packages propagated by `pkgs` using the `newPackages` mapping. - # It is assumed that all possible overrides have already been incorporated into - # the mapping. If any propagated packages are replaced, a proxy package will be - # created with references to the old packages replaced in `nix-support`. - replacePropagatedPackages = - newPackages: pkg: - let - propagatedInputs = getPropagatedInputs pkg; - env = { - inherit (pkg) outputs; - - replacements = lib.pipe propagatedInputs [ - (lib.filter (pkg: pkg != null)) - lib.flatten - (map (dep: { - name = builtins.unsafeDiscardStringContext dep; - value = getReplacement newPackages dep; - })) - (lib.filter (mapping: mapping.name != mapping.value)) - lib.listToAttrs - ]; - - sourceOutputs = lib.genAttrs pkg.outputs (output: lib.getOutput output pkg); - }; - in - # Only remap the package’s propagated inputs if there are any and if any of them - # had packages remapped (with frameworks or proxy packages). - if propagatedInputs != [ ] && env.replacements != { } then mkProxyPackage pkg.name env else pkg; - - # Gets all propagated dependencies in a package in reverse order sorted topologically. - # This takes advantage of the fact that items produced by `operator` are pushed to - # the end of the working set, ensuring that dependencies always appear after their - # parent in the list with leaf nodes at the end. - topologicallyOrderedPropagatedDependencies = - pkgs: - let - mapPackageDeps = lib.flip lib.pipe [ - (lib.filter (pkg: pkg != null)) - lib.flatten - (map (pkg: { - key = builtins.unsafeDiscardStringContext pkg; - package = pkg; - deps = getPropagatedInputs pkg; - })) - ]; - in - lib.genericClosure { - startSet = mapPackageDeps pkgs; - operator = { deps, ... }: mapPackageDeps deps; - }; - - # Returns a package mapping based on remapping all propagated packages. - getPackageMapping = - baseMapping: input: - let - dependencies = topologicallyOrderedPropagatedDependencies input; - in - lib.foldr ( - pkg: newPackages: - let - replacement = replacePropagatedPackages newPackages pkg.package; - outPath = pkg.key; - in - if pkg.key == null || newPackages ? ${outPath} then - newPackages - else - newPackages // { ${outPath} = replacement; } - ) baseMapping dependencies; - - overrideSDK = - stdenv: sdkVersion: - let - newVersion = { - inherit (stdenv.hostPlatform) darwinMinVersion darwinSdkVersion; - } // (if lib.isAttrs sdkVersion then sdkVersion else { darwinSdkVersion = sdkVersion; }); - - inherit (newVersion) darwinMinVersion darwinSdkVersion; - - # Used to get an SDK version corresponding to the requested `darwinSdkVersion`. - # TODO: Treat `darwinSdkVersion` as a constraint rather than as an exact version. - resolveSDK = pkgs: pkgs.darwin."apple_sdk_${lib.replaceStrings [ "." ] [ "_" ] darwinSdkVersion}"; - - # `newSdkPackages` is constructed based on the assumption that SDK packages only - # propagate versioned packages from that SDK -- that they neither propagate - # unversioned SDK packages nor propagate non-SDK packages (such as curl). - # - # Note: `builtins.unsafeDiscardStringContext` is used to allow the path from the - # original package output to be mapped to the replacement. This is safe because - # the value is not persisted anywhere and necessary because store paths are not - # allowed as attrset names otherwise. - baseSdkMapping = lib.pipe args [ - (lib.flip removeAttrs [ - "lib" - "stdenvNoCC" - "extendMkDerivationArgs" - ]) - (lib.filterAttrs (_: lib.hasAttr "darwin")) - lib.attrValues - (lib.concatMap ( - pkgs: - let - newSDK = resolveSDK pkgs; - - frameworks = mkMapping "frameworks" pkgs newSDK; - libs = mkMapping "libs" pkgs newSDK; - overrides = mkOverrides pkgs newSDK newVersion; - in - frameworks ++ libs ++ overrides - )) - lib.listToAttrs - ]; - - # Remaps all inputs given to the requested SDK version. The result is an attrset - # that can be passed to `extendMkDerivationArgs`. - mapInputsToSDK = - inputs: args: - lib.pipe inputs [ - (lib.filter (input: args ? ${input})) - (lib.flip lib.genAttrs ( - inputName: - let - input = args.${inputName}; - newPackages = getPackageMapping baseSdkMapping input; - in - map (getReplacement newPackages) input - )) - ]; - in - stdenv.override ( - old: - { - buildPlatform = mkPlatform newVersion stdenv.buildPlatform; - hostPlatform = mkPlatform newVersion stdenv.hostPlatform; - targetPlatform = mkPlatform newVersion stdenv.targetPlatform; - } - # Only perform replacements if the SDK version has changed. Changing only the - # deployment target does not require replacing the libc or SDK dependencies. - // lib.optionalAttrs (stdenv.hostPlatform.darwinSdkVersion != darwinSdkVersion) { - allowedRequisites = null; - - mkDerivationFromStdenv = extendMkDerivationArgs old (mapInputsToSDK [ - "depsBuildBuild" - "nativeBuildInputs" - "depsBuildTarget" - "depsHostHost" - "buildInputs" - "depsTargetTarget" - "depsBuildBuildPropagated" - "propagatedNativeBuildInputs" - "depsBuildTargetPropagated" - "depsHostHostPropagated" - "propagatedBuildInputs" - "depsTargetTargetPropagated" - ]); - - cc = getReplacement baseSdkMapping old.cc; - - extraBuildInputs = map (getReplacement baseSdkMapping) stdenv.extraBuildInputs; - extraNativeBuildInputs = map (getReplacement baseSdkMapping) stdenv.extraNativeBuildInputs; - } - ); + See the stdenv documentation for how to use `apple-sdk`. + ''); in -overrideSDK +stdenv.override (old: { + mkDerivationFromStdenv = extendMkDerivationArgs old (args: { + buildInputs = + args.buildInputs or [ ] + ++ lib.optional (stdenv.hostPlatform.darwinMinVersion != darwinMinVersion) minVersionHook + ++ lib.optional (stdenv.hostPlatform.darwinSdkVersion != darwinSdkVersion) resolvedSdk; + }); +})