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 # extraBuildInputs are dropped in cross.nix, but darwin still needs them
141 extraBuildInputs = [ pkgs.buildPackages.darwin.CF ];
142 mkDerivationFromStdenv = withOldMkDerivation old (stdenv: mkDerivationSuper: args:
143 (mkDerivationSuper args).overrideAttrs (prevAttrs: {
144 NIX_CFLAGS_LINK = toString (prevAttrs.NIX_CFLAGS_LINK or "")
145 + lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
146 nativeBuildInputs = (prevAttrs.nativeBuildInputs or [])
147 ++ lib.optionals stdenv.hasCC [
148 (pkgs.buildPackages.makeSetupHook {
149 name = "darwin-portable-libSystem-hook";
151 libsystem = "${stdenv.cc.libc}/lib/libSystem.B.dylib";
152 targetPrefix = stdenv.cc.bintools.targetPrefix;
154 } ./darwin/portable-libsystem.sh)
159 # Puts all the other ones together
160 makeStatic = stdenv: lib.foldl (lib.flip lib.id) stdenv (
161 lib.optional stdenv.hostPlatform.isDarwin makeStaticDarwin
163 ++ [ makeStaticLibraries propagateBuildInputs ]
165 # Apple does not provide a static version of libSystem or crt0.o
166 # So we can’t build static binaries without extensive hacks.
167 ++ lib.optional (!stdenv.hostPlatform.isDarwin) makeStaticBinaries
171 /* Modify a stdenv so that all buildInputs are implicitly propagated to
172 consuming derivations
174 propagateBuildInputs = stdenv:
175 stdenv.override (old: {
176 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
177 propagatedBuildInputs = (args.propagatedBuildInputs or []) ++ (args.buildInputs or []);
183 /* Modify a stdenv so that the specified attributes are added to
184 every derivation returned by its mkDerivation function.
189 { env.NIX_CFLAGS_COMPILE = "-O0"; }
192 addAttrsToDerivation = extraAttrs: stdenv: stdenv.override (old: {
193 mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
197 /* Use the trace output to report all processed derivations with their
200 traceDrvLicenses = stdenv:
201 stdenv.override (old: {
202 mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
204 printDrvPath = val: let
205 drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;
206 license = pkg.meta.license or null;
208 builtins.trace "@:drv:${toString drvPath}:${builtins.toString license}:@" val;
210 outPath = printDrvPath pkg.outPath;
211 drvPath = printDrvPath pkg.drvPath;
216 /* Modify a stdenv so that it produces debug builds; that is,
217 binaries have debug info, and compiler optimisations are
219 keepDebugInfo = stdenv:
220 stdenv.override (old: {
221 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
223 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og"; };
228 /* Modify a stdenv so that it uses the Gold linker. */
229 useGoldLinker = stdenv:
230 stdenv.override (old: {
231 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
232 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=gold";
236 /* Copy the libstdc++ from the model stdenv to the target stdenv.
238 * TODO(@connorbaker):
239 * This interface provides behavior which should be revisited prior to the
240 * release of 24.05. For a more detailed explanation and discussion, see
241 * https://github.com/NixOS/nixpkgs/issues/283517. */
242 useLibsFrom = modelStdenv: targetStdenv:
244 ccForLibs = modelStdenv.cc.cc;
245 /* NOTE(@connorbaker):
246 * This assumes targetStdenv.cc is a cc-wrapper. */
247 cc = targetStdenv.cc.override {
248 /* NOTE(originally by rrbutani):
249 * Normally the `useCcForLibs`/`gccForLibs` mechanism is used to get a
250 * clang based `cc` to use `libstdc++` (from gcc).
252 * Here we (ab)use it to use a `libstdc++` from a different `gcc` than our
255 * Note that this does not inhibit our `cc`'s lib dir from being added to
256 * cflags/ldflags (see `cc_solib` in `cc-wrapper`) but this is okay: our
257 * `gccForLibs`'s paths should take precedence. */
259 gccForLibs = ccForLibs;
262 overrideCC targetStdenv cc;
264 useMoldLinker = stdenv:
265 if stdenv.targetPlatform.isDarwin
266 then throw "Mold can't be used to emit Mach-O (Darwin) binaries"
268 bintools = stdenv.cc.bintools.override {
269 extraBuildCommands = ''
270 wrap ${stdenv.cc.bintools.targetPrefix}ld.mold ${../build-support/bintools-wrapper/ld-wrapper.sh} ${pkgs.mold}/bin/ld.mold
271 wrap ${stdenv.cc.bintools.targetPrefix}ld ${../build-support/bintools-wrapper/ld-wrapper.sh} ${pkgs.mold}/bin/ld.mold
274 in stdenv.override (old: {
275 allowedRequisites = null;
276 cc = stdenv.cc.override { inherit bintools; };
277 # gcc >12.1.0 supports '-fuse-ld=mold'
278 # the wrap ld above in bintools supports gcc <12.1.0 and shouldn't harm >12.1.0
279 # https://github.com/rui314/mold#how-to-use
280 } // lib.optionalAttrs (stdenv.cc.isClang || (stdenv.cc.isGNU && lib.versionAtLeast stdenv.cc.version "12")) {
281 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
282 NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=mold";
286 /* Modify a stdenv so that it builds binaries optimized specifically
287 for the machine they are built on.
289 WARNING: this breaks purity! */
290 impureUseNativeOptimizations = stdenv:
291 stdenv.override (old: {
292 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
293 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -march=native"; };
295 NIX_ENFORCE_NO_NATIVE = false;
297 preferLocalBuild = true;
298 allowSubstitutes = false;
303 /* Modify a stdenv so that it builds binaries with the specified list of
304 compilerFlags appended and passed to the compiler.
306 This example would recompile every derivation on the system with
307 -funroll-loops and -O3 passed to each gcc invocation.
312 stdenv = super.withCFlags [ "-funroll-loops" "-O3" ] super.stdenv;
316 withCFlags = compilerFlags: stdenv:
317 stdenv.override (old: {
318 mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
319 env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}"; };
323 # Overriding the SDK changes the Darwin SDK used to build the package, which:
324 # * Ensures that the compiler and bintools have the correct Libsystem version; and
325 # * Replaces any SDK references with those in the SDK corresponding to the requested SDK version.
327 # `sdkVersion` can be any of the following:
328 # * A version string indicating the requested SDK version; or
329 # * An attrset consisting of either or both of the following fields: darwinSdkVersion and darwinMinVersion.
330 overrideSDK = import ./darwin/override-sdk.nix {
331 inherit lib extendMkDerivationArgs;
342 withDefaultHardeningFlags = defaultHardeningFlags: stdenv: let
344 bintools' = stdenv.cc.bintools;
345 in if bintools' ? override then (bintools'.override {
346 inherit defaultHardeningFlags;
349 stdenv.override (old: {
350 cc = if stdenv.cc == null then null else stdenv.cc.override {
353 allowedRequisites = lib.mapNullable (rs: rs ++ [ bintools ]) (stdenv.allowedRequisites or null);