Merge pull request #274841 from r-ryantm/auto-update/miniaudio
[NixPkgs.git] / pkgs / stdenv / adapters.nix
blobdd29871907188eba7dd718ba9bfb44d79047b749
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
3    compiler. */
5 { lib, pkgs, config }:
7 let
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;
19   in
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));
31 rec {
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.
48   #
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;
53     let
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" ];
65         inherit cxxabi;
66         isLLVM = true;
67       } ''
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"
72       '';
74       cxxabi = pkgs.runCommand "${stdenvCxxabi.name}-${llvmLibcxxVersion}" {
75         outputs = [ "out" "dev" ];
76         inherit (stdenvCxxabi) libName;
77       } ''
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"
82       '';
83     in
84     overrideCC stdenv (stdenv.cc.override {
85       inherit libcxx;
86       extraPackages = [ cxxabi pkgs.pkgsTargetTarget."llvmPackages_${lib.versions.major llvmLibcxxVersion}".compiler-rt ];
87     });
89   # Override the setup script of stdenv.  Useful for testing new
90   # versions of the setup script without causing a rebuild of
91   # everything.
92   #
93   # Example:
94   #   randomPkg = import ../bla { ...
95   #     stdenv = overrideSetup stdenv ../stdenv/generic/setup-latest.sh;
96   #   };
97   overrideSetup = stdenv: setupScript: stdenv.override { inherit setupScript; };
100   # Return a modified stdenv that tries to build statically linked
101   # binaries.
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...
112         ];
113         cmakeFlags = (args.cmakeFlags or []) ++ ["-DCMAKE_SKIP_INSTALL_RPATH=On"];
114       }));
115     } // lib.optionalAttrs (stdenv0.hostPlatform.libc == "glibc") {
116       extraBuildInputs = (old.extraBuildInputs or []) ++ [
117         pkgs.glibc.static
118       ];
119     });
122   # Return a modified stdenv that builds static libraries instead of
123   # shared libraries.
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 []) ++ [
130           "--enable-static"
131           "--disable-shared"
132         ];
133         cmakeFlags = (args.cmakeFlags or []) ++ [ "-DBUILD_SHARED_LIBS:BOOL=OFF" ];
134         mesonFlags = (args.mesonFlags or []) ++ [ "-Ddefault_library=static" ];
135       });
136     });
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";
151             substitutions = {
152               libsystem = "${stdenv.cc.libc}/lib/libSystem.B.dylib";
153               targetPrefix = stdenv.cc.bintools.targetPrefix;
154             };
155           } ./darwin/portable-libsystem.sh)
156         ];
157     }));
158   });
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
169   );
172   /* Modify a stdenv so that all buildInputs are implicitly propagated to
173      consuming derivations
174   */
175   propagateBuildInputs = stdenv:
176     stdenv.override (old: {
177       mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
178         propagatedBuildInputs = (args.propagatedBuildInputs or []) ++ (args.buildInputs or []);
179         buildInputs = [];
180       });
181     });
184   /* Modify a stdenv so that the specified attributes are added to
185      every derivation returned by its mkDerivation function.
187      Example:
188        stdenvNoOptimise =
189          addAttrsToDerivation
190            { env.NIX_CFLAGS_COMPILE = "-O0"; }
191            stdenv;
192   */
193   addAttrsToDerivation = extraAttrs: stdenv: stdenv.override (old: {
194     mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
195   });
198   /* Use the trace output to report all processed derivations with their
199      license name.
200   */
201   traceDrvLicenses = stdenv:
202     stdenv.override (old: {
203       mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
204         let
205           printDrvPath = val: let
206             drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;
207             license = pkg.meta.license or null;
208           in
209             builtins.trace "@:drv:${toString drvPath}:${builtins.toString license}:@" val;
210         in pkg // {
211           outPath = printDrvPath pkg.outPath;
212           drvPath = printDrvPath pkg.drvPath;
213         });
214     });
217   /* Modify a stdenv so that it produces debug builds; that is,
218      binaries have debug info, and compiler optimisations are
219      disabled. */
220   keepDebugInfo = stdenv:
221     stdenv.override (old: {
222       mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
223         dontStrip = true;
224         env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og"; };
225       });
226     });
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";
234       });
235     });
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
242       '';
243     };
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";
253     });
254   });
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;
270       });
271     });
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.
280      Example:
281        nixpkgs.overlays = [
282          (self: super: {
283            stdenv = super.withCFlags [ "-funroll-loops" "-O3" ] super.stdenv;
284          })
285        ];
286   */
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}"; };
291       });
292     });
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.
297   #
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:
302     let
303       inherit (
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:
314         let
315           propagatedInputs = pkg.propagatedBuildInputs;
316           mappedInputs = map mapPackageToSDK propagatedInputs;
318           env = {
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" ];
327           };
328         in
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"
356                     fi
357                   done
358                 else
359                   ln -s "$targetPath" "''${!outputName}/$targetName"
360                 fi
361               done
362             done < "$pkgOutputsPath"
363           ''
364         else pkg;
366       # Remap a framework from one SDK version to another.
367       mapPackageToSDK = pkg:
368         let
369           name = lib.getName pkg;
370           framework = lib.removePrefix "apple-framework-" name;
371         in
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; }; }
380           else pkg;
382       mapInputsToSDK = inputs: args:
383         let
384           runsAtBuild = lib.flip lib.elem [
385             "depsBuildBuild"
386             "depsBuildBuildPropagated"
387             "nativeBuildInputs"
388             "propagatedNativeBuildInputs"
389             "depsBuildTarget"
390             "depsBuildTargetPropagated"
391           ];
392           atBuildInputs = lib.filter runsAtBuild inputs;
393           atRuntimeInputs = lib.subtractLists atBuildInputs inputs;
394         in
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; };
400         libc = Libsystem;
401       };
402     in
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;
410       cc = mkCC old.cc;
412       extraBuildInputs = [sdk.frameworks.CoreFoundation ];
413       mkDerivationFromStdenv = extendMkDerivationArgs old (mapInputsToSDK [
414         "buildInputs"
415         "nativeBuildInputs"
416         "propagatedNativeBuildInputs"
417         "propagatedBuildInputs"
418       ]);
419     });