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 = stdenv: (import ./generic/make-derivation.nix { inherit lib config; } stdenv).mkDerivation;
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 {
36 allowedRequisites = null;
42 # Add some arbitrary packages to buildInputs for specific packages.
43 # Used to override packages in stdenv like Make. Should not be used
44 # for other dependencies.
45 overrideInStdenv = stdenv: pkgs:
46 stdenv.override (prev: { allowedRequisites = null; extraBuildInputs = (prev.extraBuildInputs or []) ++ pkgs; });
49 # Override the libc++ dynamic library used in the stdenv to use the one from the platform’s
50 # default stdenv. This allows building packages and linking dependencies with different
51 # compiler versions while still using the same libc++ implementation for compatibility.
53 # Note that this adapter still uses the headers from the new stdenv’s libc++. This is necessary
54 # because older compilers may not be able to parse the headers from the default stdenv’s libc++.
55 overrideLibcxx = stdenv:
56 assert stdenv.cc.libcxx != null;
57 assert pkgs.stdenv.cc.libcxx != null;
58 # only unified libcxx / libcxxabi stdenv's are supported
59 assert lib.versionAtLeast pkgs.stdenv.cc.libcxx.version "12";
60 assert lib.versionAtLeast stdenv.cc.libcxx.version "12";
62 llvmLibcxxVersion = lib.getVersion llvmLibcxx;
64 stdenvLibcxx = pkgs.stdenv.cc.libcxx;
65 llvmLibcxx = stdenv.cc.libcxx;
67 libcxx = pkgs.runCommand "${stdenvLibcxx.name}-${llvmLibcxxVersion}" {
68 outputs = [ "out" "dev" ];
71 mkdir -p "$dev/nix-support"
72 ln -s '${stdenvLibcxx}' "$out"
73 echo '${stdenvLibcxx}' > "$dev/nix-support/propagated-build-inputs"
74 ln -s '${lib.getDev llvmLibcxx}/include' "$dev/include"
77 overrideCC stdenv (stdenv.cc.override {
80 pkgs.buildPackages.targetPackages."llvmPackages_${lib.versions.major llvmLibcxxVersion}".compiler-rt
84 # Override the setup script of stdenv. Useful for testing new
85 # versions of the setup script without causing a rebuild of
89 # randomPkg = import ../bla { ...
90 # stdenv = overrideSetup stdenv ../stdenv/generic/setup-latest.sh;
92 overrideSetup = stdenv: setupScript: stdenv.override { inherit setupScript; };
95 # Return a modified stdenv that tries to build statically linked
97 makeStaticBinaries = stdenv0:
98 stdenv0.override (old: {
99 mkDerivationFromStdenv = withOldMkDerivation old (stdenv: mkDerivationSuper: args:
100 if stdenv.hostPlatform.isDarwin
101 then throw "Cannot build fully static binaries on Darwin/macOS"
102 else (mkDerivationSuper args).overrideAttrs (args: if args ? env.NIX_CFLAGS_LINK then {
104 NIX_CFLAGS_LINK = toString args.env.NIX_CFLAGS_LINK + " -static";
107 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -static";
108 } // lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
109 configureFlags = (args.configureFlags or []) ++ [
110 "--disable-shared" # brrr...
112 cmakeFlags = (args.cmakeFlags or []) ++ ["-DCMAKE_SKIP_INSTALL_RPATH=On"];
114 } // lib.optionalAttrs (stdenv0.hostPlatform.libc == "glibc") {
115 extraBuildInputs = (old.extraBuildInputs or []) ++ [
121 # Return a modified stdenv that builds static libraries instead of
123 makeStaticLibraries = stdenv:
124 stdenv.override (old: {
125 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
126 dontDisableStatic = true;
127 } // lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
128 configureFlags = (args.configureFlags or []) ++ [
132 cmakeFlags = (args.cmakeFlags or []) ++ [ "-DBUILD_SHARED_LIBS:BOOL=OFF" ];
133 mesonFlags = (args.mesonFlags or []) ++ [ "-Ddefault_library=static" ];
137 # Best effort static binaries. Will still be linked to libSystem,
138 # but more portable than Nix store binaries.
139 makeStaticDarwin = stdenv: stdenv.override (old: {
140 mkDerivationFromStdenv = withOldMkDerivation old (stdenv: mkDerivationSuper: args:
141 (mkDerivationSuper args).overrideAttrs (prevAttrs:
142 if prevAttrs ? env.NIX_CFLAGS_LINK then {
143 env = prevAttrs.env // {
144 NIX_CFLAGS_LINK = toString args.env.NIX_CFLAGS_LINK
145 + lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
148 NIX_CFLAGS_LINK = toString (prevAttrs.NIX_CFLAGS_LINK or "")
149 + lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
153 # Puts all the other ones together
154 makeStatic = stdenv: lib.foldl (lib.flip lib.id) stdenv (
155 lib.optional stdenv.hostPlatform.isDarwin makeStaticDarwin
157 ++ [ makeStaticLibraries propagateBuildInputs ]
159 # Apple does not provide a static version of libSystem or crt0.o
160 # So we can’t build static binaries without extensive hacks.
161 ++ lib.optional (!stdenv.hostPlatform.isDarwin) makeStaticBinaries
165 /* Modify a stdenv so that all buildInputs are implicitly propagated to
166 consuming derivations
168 propagateBuildInputs = stdenv:
169 stdenv.override (old: {
170 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
171 propagatedBuildInputs = (args.propagatedBuildInputs or []) ++ (args.buildInputs or []);
177 /* Modify a stdenv so that the specified attributes are added to
178 every derivation returned by its mkDerivation function.
183 { env.NIX_CFLAGS_COMPILE = "-O0"; }
186 addAttrsToDerivation = extraAttrs: stdenv: stdenv.override (old: {
187 mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
191 /* Use the trace output to report all processed derivations with their
194 traceDrvLicenses = stdenv:
195 stdenv.override (old: {
196 mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
198 printDrvPath = val: let
199 drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;
200 license = pkg.meta.license or null;
202 builtins.trace "@:drv:${toString drvPath}:${builtins.toString license}:@" val;
204 outPath = printDrvPath pkg.outPath;
205 drvPath = printDrvPath pkg.drvPath;
210 /* Modify a stdenv so that it produces debug builds; that is,
211 binaries have debug info, and compiler optimisations are
213 keepDebugInfo = stdenv:
214 stdenv.override (old: {
215 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
217 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og"; };
222 /* Modify a stdenv so that it uses the Gold linker. */
223 useGoldLinker = stdenv:
224 stdenv.override (old: {
225 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
226 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=gold";
230 /* Copy the libstdc++ from the model stdenv to the target stdenv.
232 * TODO(@connorbaker):
233 * This interface provides behavior which should be revisited prior to the
234 * release of 24.05. For a more detailed explanation and discussion, see
235 * https://github.com/NixOS/nixpkgs/issues/283517. */
236 useLibsFrom = modelStdenv: targetStdenv:
238 ccForLibs = modelStdenv.cc.cc;
239 /* NOTE(@connorbaker):
240 * This assumes targetStdenv.cc is a cc-wrapper. */
241 cc = targetStdenv.cc.override {
242 /* NOTE(originally by rrbutani):
243 * Normally the `useCcForLibs`/`gccForLibs` mechanism is used to get a
244 * clang based `cc` to use `libstdc++` (from gcc).
246 * Here we (ab)use it to use a `libstdc++` from a different `gcc` than our
249 * Note that this does not inhibit our `cc`'s lib dir from being added to
250 * cflags/ldflags (see `cc_solib` in `cc-wrapper`) but this is okay: our
251 * `gccForLibs`'s paths should take precedence. */
253 gccForLibs = ccForLibs;
256 overrideCC targetStdenv cc;
258 useMoldLinker = stdenv:
259 if stdenv.targetPlatform.isDarwin
260 then throw "Mold can't be used to emit Mach-O (Darwin) binaries"
262 bintools = stdenv.cc.bintools.override {
263 extraBuildCommands = ''
264 wrap ${stdenv.cc.bintools.targetPrefix}ld.mold ${../build-support/bintools-wrapper/ld-wrapper.sh} ${pkgs.mold}/bin/ld.mold
265 wrap ${stdenv.cc.bintools.targetPrefix}ld ${../build-support/bintools-wrapper/ld-wrapper.sh} ${pkgs.mold}/bin/ld.mold
268 in stdenv.override (old: {
269 allowedRequisites = null;
270 cc = stdenv.cc.override { inherit bintools; };
271 # gcc >12.1.0 supports '-fuse-ld=mold'
272 # the wrap ld above in bintools supports gcc <12.1.0 and shouldn't harm >12.1.0
273 # https://github.com/rui314/mold#how-to-use
274 } // lib.optionalAttrs (stdenv.cc.isClang || (stdenv.cc.isGNU && lib.versionAtLeast stdenv.cc.version "12")) {
275 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
276 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=mold";
280 /* Modify a stdenv so that it builds binaries optimized specifically
281 for the machine they are built on.
283 WARNING: this breaks purity! */
284 impureUseNativeOptimizations = stdenv:
285 stdenv.override (old: {
286 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
287 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -march=native"; };
289 NIX_ENFORCE_NO_NATIVE = false;
291 preferLocalBuild = true;
292 allowSubstitutes = false;
297 /* Modify a stdenv so that it builds binaries with the specified list of
298 compilerFlags appended and passed to the compiler.
300 This example would recompile every derivation on the system with
301 -funroll-loops and -O3 passed to each gcc invocation.
306 stdenv = super.withCFlags [ "-funroll-loops" "-O3" ] super.stdenv;
310 withCFlags = compilerFlags: stdenv:
311 stdenv.override (old: {
312 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
313 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}"; };
317 # Overriding the SDK changes the Darwin SDK used to build the package, which:
318 # * Ensures that the compiler and bintools have the correct Libsystem version; and
319 # * Replaces any SDK references with those in the SDK corresponding to the requested SDK version.
321 # `sdkVersion` can be any of the following:
322 # * A version string indicating the requested SDK version; or
323 # * An attrset consisting of either or both of the following fields: darwinSdkVersion and darwinMinVersion.
325 # Note: `overrideSDK` is deprecated. Add the versioned variants of `apple-sdk` to `buildInputs` change the SDK.
326 overrideSDK = pkgs.callPackage ./darwin/override-sdk.nix { inherit lib extendMkDerivationArgs; };
328 withDefaultHardeningFlags = defaultHardeningFlags: stdenv: let
330 bintools' = stdenv.cc.bintools;
331 in if bintools' ? override then (bintools'.override {
332 inherit defaultHardeningFlags;
335 stdenv.override (old: {
336 cc = if stdenv.cc == null then null else stdenv.cc.override {
339 allowedRequisites = lib.mapNullable (rs: rs ++ [ bintools ]) (stdenv.allowedRequisites or null);