1 /* This file contains various functions that take a stdenv and return
2 a new stdenv with different behaviour, e.g. using a different C
8 # N.B. Keep in sync with default arg for stdenv/generic.
9 defaultMkDerivationFromStdenv = import ./generic/make-derivation.nix { inherit lib config; };
11 # Low level function to help with overriding `mkDerivationFromStdenv`. One
12 # gives it the old stdenv arguments and a "continuation" function, and
13 # underneath the final stdenv argument it yields to the continuation to do
14 # whatever it wants with old `mkDerivation` (old `mkDerivationFromStdenv`
15 # applied to the *new, final* stdenv) provided for convenience.
16 withOldMkDerivation = stdenvSuperArgs: k: stdenvSelf: let
17 mkDerivationFromStdenv-super = stdenvSuperArgs.mkDerivationFromStdenv or defaultMkDerivationFromStdenv;
18 mkDerivationSuper = mkDerivationFromStdenv-super stdenvSelf;
20 k stdenvSelf mkDerivationSuper;
22 # Wrap the original `mkDerivation` providing extra args to it.
23 extendMkDerivationArgs = old: f: withOldMkDerivation old (_: mkDerivationSuper: args:
24 (mkDerivationSuper args).overrideAttrs f);
26 # Wrap the original `mkDerivation` transforming the result.
27 overrideMkDerivationResult = old: f: withOldMkDerivation old (_: mkDerivationSuper: args:
28 f (mkDerivationSuper args));
34 # Override the compiler in stdenv for specific packages.
35 overrideCC = stdenv: cc: stdenv.override { allowedRequisites = null; cc = cc; };
38 # Add some arbitrary packages to buildInputs for specific packages.
39 # Used to override packages in stdenv like Make. Should not be used
40 # for other dependencies.
41 overrideInStdenv = stdenv: pkgs:
42 stdenv.override (prev: { allowedRequisites = null; extraBuildInputs = (prev.extraBuildInputs or []) ++ pkgs; });
45 # Override the libc++ dynamic library used in the stdenv to use the one from the platform’s
46 # default stdenv. This allows building packages and linking dependencies with different
47 # compiler versions while still using the same libc++ implementation for compatibility.
49 # Note that this adapter still uses the headers from the new stdenv’s libc++. This is necessary
50 # because older compilers may not be able to parse the headers from the default stdenv’s libc++.
51 overrideLibcxx = stdenv:
52 assert stdenv.cc.libcxx != null;
54 llvmLibcxxVersion = lib.getVersion llvmLibcxx;
55 stdenvLibcxxVersion = lib.getVersion stdenvLibcxx;
57 stdenvLibcxx = pkgs.stdenv.cc.libcxx;
58 stdenvCxxabi = pkgs.stdenv.cc.libcxx.cxxabi;
60 llvmLibcxx = stdenv.cc.libcxx;
61 llvmCxxabi = stdenv.cc.libcxx.cxxabi;
63 libcxx = pkgs.runCommand "${stdenvLibcxx.name}-${llvmLibcxxVersion}" {
64 outputs = [ "out" "dev" ];
68 mkdir -p "$dev/nix-support"
69 ln -s '${stdenvLibcxx}' "$out"
70 echo '${stdenvLibcxx}' > "$dev/nix-support/propagated-build-inputs"
71 ln -s '${lib.getDev llvmLibcxx}/include' "$dev/include"
74 cxxabi = pkgs.runCommand "${stdenvCxxabi.name}-${llvmLibcxxVersion}" {
75 outputs = [ "out" "dev" ];
76 inherit (stdenvCxxabi) libName;
78 mkdir -p "$dev/nix-support"
79 ln -s '${stdenvCxxabi}' "$out"
80 echo '${stdenvCxxabi}' > "$dev/nix-support/propagated-build-inputs"
81 ln -s '${lib.getDev llvmCxxabi}/include' "$dev/include"
84 overrideCC stdenv (stdenv.cc.override {
86 extraPackages = [ cxxabi pkgs.pkgsTargetTarget."llvmPackages_${lib.versions.major llvmLibcxxVersion}".compiler-rt ];
89 # Override the setup script of stdenv. Useful for testing new
90 # versions of the setup script without causing a rebuild of
94 # randomPkg = import ../bla { ...
95 # stdenv = overrideSetup stdenv ../stdenv/generic/setup-latest.sh;
97 overrideSetup = stdenv: setupScript: stdenv.override { inherit setupScript; };
100 # Return a modified stdenv that tries to build statically linked
102 makeStaticBinaries = stdenv0:
103 stdenv0.override (old: {
104 mkDerivationFromStdenv = withOldMkDerivation old (stdenv: mkDerivationSuper: args:
105 if stdenv.hostPlatform.isDarwin
106 then throw "Cannot build fully static binaries on Darwin/macOS"
107 else (mkDerivationSuper args).overrideAttrs (args: {
108 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -static";
109 } // lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
110 configureFlags = (args.configureFlags or []) ++ [
111 "--disable-shared" # brrr...
113 cmakeFlags = (args.cmakeFlags or []) ++ ["-DCMAKE_SKIP_INSTALL_RPATH=On"];
115 } // lib.optionalAttrs (stdenv0.hostPlatform.libc == "glibc") {
116 extraBuildInputs = (old.extraBuildInputs or []) ++ [
122 # Return a modified stdenv that builds static libraries instead of
124 makeStaticLibraries = stdenv:
125 stdenv.override (old: {
126 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
127 dontDisableStatic = true;
128 } // lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
129 configureFlags = (args.configureFlags or []) ++ [
133 cmakeFlags = (args.cmakeFlags or []) ++ [ "-DBUILD_SHARED_LIBS:BOOL=OFF" ];
134 mesonFlags = (args.mesonFlags or []) ++ [ "-Ddefault_library=static" ];
138 # Best effort static binaries. Will still be linked to libSystem,
139 # but more portable than Nix store binaries.
140 makeStaticDarwin = stdenv: stdenv.override (old: {
141 # extraBuildInputs are dropped in cross.nix, but darwin still needs them
142 extraBuildInputs = [ pkgs.buildPackages.darwin.CF ];
143 mkDerivationFromStdenv = withOldMkDerivation old (stdenv: mkDerivationSuper: args:
144 (mkDerivationSuper args).overrideAttrs (finalAttrs: {
145 NIX_CFLAGS_LINK = toString (finalAttrs.NIX_CFLAGS_LINK or "")
146 + lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
147 nativeBuildInputs = (finalAttrs.nativeBuildInputs or [])
148 ++ lib.optionals stdenv.hasCC [
149 (pkgs.buildPackages.makeSetupHook {
150 name = "darwin-portable-libSystem-hook";
152 libsystem = "${stdenv.cc.libc}/lib/libSystem.B.dylib";
153 targetPrefix = stdenv.cc.bintools.targetPrefix;
155 } ./darwin/portable-libsystem.sh)
160 # Puts all the other ones together
161 makeStatic = stdenv: lib.foldl (lib.flip lib.id) stdenv (
162 lib.optional stdenv.hostPlatform.isDarwin makeStaticDarwin
164 ++ [ makeStaticLibraries propagateBuildInputs ]
166 # Apple does not provide a static version of libSystem or crt0.o
167 # So we can’t build static binaries without extensive hacks.
168 ++ lib.optional (!stdenv.hostPlatform.isDarwin) makeStaticBinaries
172 /* Modify a stdenv so that all buildInputs are implicitly propagated to
173 consuming derivations
175 propagateBuildInputs = stdenv:
176 stdenv.override (old: {
177 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
178 propagatedBuildInputs = (args.propagatedBuildInputs or []) ++ (args.buildInputs or []);
184 /* Modify a stdenv so that the specified attributes are added to
185 every derivation returned by its mkDerivation function.
190 { env.NIX_CFLAGS_COMPILE = "-O0"; }
193 addAttrsToDerivation = extraAttrs: stdenv: stdenv.override (old: {
194 mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
198 /* Use the trace output to report all processed derivations with their
201 traceDrvLicenses = stdenv:
202 stdenv.override (old: {
203 mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
205 printDrvPath = val: let
206 drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;
207 license = pkg.meta.license or null;
209 builtins.trace "@:drv:${toString drvPath}:${builtins.toString license}:@" val;
211 outPath = printDrvPath pkg.outPath;
212 drvPath = printDrvPath pkg.drvPath;
217 /* Modify a stdenv so that it produces debug builds; that is,
218 binaries have debug info, and compiler optimisations are
220 keepDebugInfo = stdenv:
221 stdenv.override (old: {
222 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
224 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og"; };
229 /* Modify a stdenv so that it uses the Gold linker. */
230 useGoldLinker = stdenv:
231 stdenv.override (old: {
232 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
233 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=gold";
237 useMoldLinker = stdenv: let
238 bintools = stdenv.cc.bintools.override {
239 extraBuildCommands = ''
240 wrap ${stdenv.cc.bintools.targetPrefix}ld.mold ${../build-support/bintools-wrapper/ld-wrapper.sh} ${pkgs.mold}/bin/ld.mold
241 wrap ${stdenv.cc.bintools.targetPrefix}ld ${../build-support/bintools-wrapper/ld-wrapper.sh} ${pkgs.mold}/bin/ld.mold
244 in stdenv.override (old: {
245 allowedRequisites = null;
246 cc = stdenv.cc.override { inherit bintools; };
247 # gcc >12.1.0 supports '-fuse-ld=mold'
248 # the wrap ld above in bintools supports gcc <12.1.0 and shouldn't harm >12.1.0
249 # https://github.com/rui314/mold#how-to-use
250 } // lib.optionalAttrs (stdenv.cc.isClang || (stdenv.cc.isGNU && lib.versionAtLeast stdenv.cc.version "12")) {
251 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
252 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=mold";
257 /* Modify a stdenv so that it builds binaries optimized specifically
258 for the machine they are built on.
260 WARNING: this breaks purity! */
261 impureUseNativeOptimizations = stdenv:
262 stdenv.override (old: {
263 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
264 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -march=native"; };
266 NIX_ENFORCE_NO_NATIVE = false;
268 preferLocalBuild = true;
269 allowSubstitutes = false;
274 /* Modify a stdenv so that it builds binaries with the specified list of
275 compilerFlags appended and passed to the compiler.
277 This example would recompile every derivation on the system with
278 -funroll-loops and -O3 passed to each gcc invocation.
283 stdenv = super.withCFlags [ "-funroll-loops" "-O3" ] super.stdenv;
287 withCFlags = compilerFlags: stdenv:
288 stdenv.override (old: {
289 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
290 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}"; };
294 # Overriding the SDK changes the Darwin SDK used to build the package, which:
295 # * Ensures that the compiler and bintools have the correct Libsystem version; and
296 # * Replaces any SDK references with those in the SDK corresponding to the requested SDK version.
298 # `sdkVersion` can be any of the following:
299 # * A version string indicating the requested SDK version; or
300 # * An attrset consisting of either or both of the following fields: darwinSdkVersion and darwinMinVersion.
301 overrideSDK = stdenv: sdkVersion:
304 { inherit (stdenv.hostPlatform) darwinMinVersion darwinSdkVersion; }
305 // (if lib.isAttrs sdkVersion then sdkVersion else { darwinSdkVersion = sdkVersion; })
306 ) darwinMinVersion darwinSdkVersion;
308 sdk = pkgs.darwin."apple_sdk_${lib.replaceStrings [ "." ] [ "_" ] darwinSdkVersion}";
309 # TODO: Make this unconditional after #229210 has been merged,
310 # and the 10.12 SDK is updated to follow the new structure.
311 Libsystem = if darwinSdkVersion == "10.12" then pkgs.darwin.Libsystem else sdk.Libsystem;
313 replacePropagatedFrameworks = pkg:
315 propagatedInputs = pkg.propagatedBuildInputs;
316 mappedInputs = map mapPackageToSDK propagatedInputs;
319 inherit (pkg) outputs;
320 # Map old frameworks to new ones and the package’s outputs to their original outPaths.
321 # Also map any packages that have propagated frameworks to their proxy packages using
322 # the requested SDK version. These mappings are rendered into tab-separated files to be
323 # parsed and read back with `read`.
324 dependencies = lib.concatMapStrings (pair: "${pair.fst}\t${pair.snd}\n") (lib.zipLists propagatedInputs mappedInputs);
325 pkgOutputs = lib.concatMapStrings (output: "${output}\t${(lib.getOutput output pkg).outPath}\n") pkg.outputs;
326 passAsFile = [ "dependencies" "pkgOutputs" ];
329 # Only remap the package’s propagated inputs if there are any and if any of them were themselves remapped.
330 if lib.length propagatedInputs > 0 && propagatedInputs != mappedInputs
331 then pkgs.runCommand pkg.name env ''
332 # Iterate over the outputs in the package being replaced to make sure the proxy is
333 # a fully functional replacement. This is like `symlinkJoin` except for outputs and
334 # the contents of `nix-support`, which will be customized for the requested SDK.
335 while IFS=$'\t\n' read -r outputName pkgOutputPath; do
336 mkdir -p "''${!outputName}"
338 for targetPath in "$pkgOutputPath"/*; do
339 targetName=$(basename "$targetPath")
341 # `nix-support` is special-cased because any propagated inputs need their SDK
342 # frameworks replaced with those from the requested SDK.
343 if [ "$targetName" == "nix-support" ]; then
344 mkdir "''${!outputName}/nix-support"
346 for file in "$targetPath"/*; do
347 fileName=$(basename "$file")
349 if [ "$fileName" == "propagated-build-inputs" ]; then
350 cp "$file" "''${!outputName}/nix-support/$fileName"
352 while IFS=$'\t\n' read -r oldFramework newFramework; do
353 substituteInPlace "''${!outputName}/nix-support/$fileName" \
354 --replace "$oldFramework" "$newFramework"
355 done < "$dependenciesPath"
359 ln -s "$targetPath" "''${!outputName}/$targetName"
362 done < "$pkgOutputsPath"
366 # Remap a framework from one SDK version to another.
367 mapPackageToSDK = pkg:
369 name = lib.getName pkg;
370 framework = lib.removePrefix "apple-framework-" name;
372 /**/ if pkg == null then pkg
373 else if name != framework then sdk.frameworks."${framework}"
374 else replacePropagatedFrameworks pkg;
376 mapRuntimeToSDK = pkg:
377 # Only remap xcbuild for now, which exports the SDK used to build it.
378 if pkg != null && lib.isAttrs pkg && lib.getName pkg == "xcodebuild"
379 then pkg.override { stdenv = overrideSDK stdenv { inherit darwinMinVersion darwinSdkVersion; }; }
382 mapInputsToSDK = inputs: args:
384 runsAtBuild = lib.flip lib.elem [
386 "depsBuildBuildPropagated"
388 "propagatedNativeBuildInputs"
390 "depsBuildTargetPropagated"
392 atBuildInputs = lib.filter runsAtBuild inputs;
393 atRuntimeInputs = lib.subtractLists atBuildInputs inputs;
395 lib.genAttrs atRuntimeInputs (input: map mapPackageToSDK (args."${input}" or [ ]))
396 // lib.genAttrs atBuildInputs (input: map mapRuntimeToSDK (args."${input}" or [ ]));
398 mkCC = cc: cc.override {
399 bintools = cc.bintools.override { libc = Libsystem; };
403 # TODO: make this work across all input types and not just propagatedBuildInputs
404 stdenv.override (old: {
405 buildPlatform = old.buildPlatform // { inherit darwinMinVersion darwinSdkVersion; };
406 hostPlatform = old.hostPlatform // { inherit darwinMinVersion darwinSdkVersion; };
407 targetPlatform = old.targetPlatform // { inherit darwinMinVersion darwinSdkVersion; };
409 allowedRequisites = null;
412 extraBuildInputs = [sdk.frameworks.CoreFoundation ];
413 mkDerivationFromStdenv = extendMkDerivationArgs old (mapInputsToSDK [
416 "propagatedNativeBuildInputs"
417 "propagatedBuildInputs"