Skip to content

Commit

Permalink
stdenvAdapters: add overrideSDK
Browse files Browse the repository at this point in the history
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 NixOS#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 NixOS#256590 is merged.
  • Loading branch information
reckenrode committed Oct 26, 2023
1 parent 08be9a9 commit 9834a56
Showing 1 changed file with 102 additions and 0 deletions.
102 changes: 102 additions & 0 deletions pkgs/stdenv/adapters.nix
Expand Up @@ -246,4 +246,106 @@ rec {
env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}"; };
});
});

# Override SDK changes the SDK used to build the package. It does two things:
# * It ensures that the compiler and bintools have the correct Libsystem version; and
# * It replaces any SDK references with those in the SDK corresponding to darwinSdkVersion.
#
# `sdkVersion` can be any of the following:
# * A version string indicating the requested SDK version.
# * The string `latest` indicating the latest SDK available in nixpkgs.
# * An attrset consisting of either or both of the following fields: darwinSdkVersion and darwinMinVersion;
overrideSDK = stdenv: sdkVersion:
let
sdkVersionAttrs = {
inherit (stdenv.hostPlatform) darwinMinVersion darwinSdkVersion;
} // (if lib.isAttrs sdkVersion then sdkVersion else { darwinSdkVersion = sdkVersion; });

inherit (sdkVersionAttrs) darwinMinVersion;
darwinSdkVersion = if sdkVersionAttrs.darwinSdkVersion == "latest"
then "11.0"
else sdkVersionAttrs.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;
frameworks = map (pkg: "${pkg}\t${mapPackageToSDK pkg}\n") propagatedFrameworks;
pkgOutputs = map (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 read -r outputName pkgOutputPath; do
mkdir -p "''${!outputName}"
for targetPath in "$pkgOutputPath"/*; do
targetName=$(basename "$targetPath")
# `nix-support` is special-cased because any propgated 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 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"
]);
});
}

0 comments on commit 9834a56

Please sign in to comment.