mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-27 02:34:53 +00:00
While bootstrapping stdenv, we'd prefer not to call the entire file the whole time on every single stage, since we have certain args ahead of time.
433 lines
13 KiB
Nix
433 lines
13 KiB
Nix
/*
|
||
This file contains various functions that take a stdenv and return
|
||
a new stdenv with different behaviour, e.g. using a different C
|
||
compiler.
|
||
*/
|
||
|
||
{
|
||
lib,
|
||
pkgs,
|
||
config,
|
||
}:
|
||
|
||
let
|
||
# N.B. Keep in sync with default arg for stdenv/generic.
|
||
defaultMkDerivationFromStdenv =
|
||
let
|
||
makeDerivationFile = import ./generic/make-derivation.nix lib config;
|
||
in
|
||
stdenv: (makeDerivationFile stdenv).mkDerivation;
|
||
|
||
# Low level function to help with overriding `mkDerivationFromStdenv`. One
|
||
# gives it the old stdenv arguments and a "continuation" function, and
|
||
# underneath the final stdenv argument it yields to the continuation to do
|
||
# whatever it wants with old `mkDerivation` (old `mkDerivationFromStdenv`
|
||
# applied to the *new, final* stdenv) provided for convenience.
|
||
withOldMkDerivation =
|
||
stdenvSuperArgs: k: stdenvSelf:
|
||
let
|
||
mkDerivationFromStdenv-super =
|
||
stdenvSuperArgs.mkDerivationFromStdenv or defaultMkDerivationFromStdenv;
|
||
mkDerivationSuper = mkDerivationFromStdenv-super stdenvSelf;
|
||
in
|
||
k stdenvSelf mkDerivationSuper;
|
||
|
||
# Wrap the original `mkDerivation` providing extra args to it.
|
||
extendMkDerivationArgs =
|
||
old: f:
|
||
withOldMkDerivation old (
|
||
_: mkDerivationSuper: args:
|
||
(mkDerivationSuper args).overrideAttrs f
|
||
);
|
||
|
||
# Wrap the original `mkDerivation` transforming the result.
|
||
overrideMkDerivationResult =
|
||
old: f:
|
||
withOldMkDerivation old (
|
||
_: mkDerivationSuper: args:
|
||
f (mkDerivationSuper args)
|
||
);
|
||
in
|
||
|
||
rec {
|
||
|
||
# Override the compiler in stdenv for specific packages.
|
||
overrideCC =
|
||
stdenv: cc:
|
||
stdenv.override {
|
||
allowedRequisites = null;
|
||
cc = cc;
|
||
hasCC = cc != null;
|
||
};
|
||
|
||
# Add some arbitrary packages to buildInputs for specific packages.
|
||
# Used to override packages in stdenv like Make. Should not be used
|
||
# for other dependencies.
|
||
overrideInStdenv =
|
||
stdenv: pkgs:
|
||
stdenv.override (prev: {
|
||
allowedRequisites = null;
|
||
extraBuildInputs = (prev.extraBuildInputs or [ ]) ++ pkgs;
|
||
});
|
||
|
||
# Override the setup script of stdenv. Useful for testing new
|
||
# versions of the setup script without causing a rebuild of
|
||
# everything.
|
||
#
|
||
# Example:
|
||
# randomPkg = import ../bla { ...
|
||
# stdenv = overrideSetup stdenv ../stdenv/generic/setup-latest.sh;
|
||
# };
|
||
overrideSetup = stdenv: setupScript: stdenv.override { inherit setupScript; };
|
||
|
||
# Return a modified stdenv that tries to build statically linked
|
||
# binaries.
|
||
makeStaticBinaries =
|
||
stdenv0:
|
||
stdenv0.override (
|
||
old:
|
||
{
|
||
mkDerivationFromStdenv = withOldMkDerivation old (
|
||
stdenv: mkDerivationSuper: args:
|
||
if stdenv.hostPlatform.isDarwin then
|
||
throw "Cannot build fully static binaries on Darwin/macOS"
|
||
else
|
||
(mkDerivationSuper args).overrideAttrs (
|
||
args:
|
||
(
|
||
if (args ? NIX_CFLAGS_LINK) then
|
||
lib.warn
|
||
(
|
||
"NIX_CFLAGS_LINK is an environment variable and should be defined inside `env`"
|
||
+ lib.optionalString (args ? pname) " for package ${args.pname}"
|
||
+ lib.optionalString (args ? version) "-${args.version}"
|
||
)
|
||
{
|
||
NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -static";
|
||
}
|
||
else
|
||
{
|
||
env = (args.env or { }) // {
|
||
NIX_CFLAGS_LINK = toString (args.env.NIX_CFLAGS_LINK or "") + " -static";
|
||
};
|
||
}
|
||
)
|
||
// lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
|
||
configureFlags = (args.configureFlags or [ ]) ++ [
|
||
"--disable-shared" # brrr...
|
||
];
|
||
cmakeFlags = (args.cmakeFlags or [ ]) ++ [ "-DCMAKE_SKIP_INSTALL_RPATH=On" ];
|
||
}
|
||
)
|
||
);
|
||
}
|
||
// lib.optionalAttrs (stdenv0.hostPlatform.libc == "glibc") {
|
||
extraBuildInputs = (old.extraBuildInputs or [ ]) ++ [
|
||
pkgs.glibc.static
|
||
];
|
||
}
|
||
);
|
||
|
||
# Return a modified stdenv that builds static libraries instead of
|
||
# shared libraries.
|
||
makeStaticLibraries = overrideMkDerivationArgs (
|
||
args:
|
||
{
|
||
dontDisableStatic = true;
|
||
}
|
||
// lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
|
||
configureFlags = (args.configureFlags or [ ]) ++ [
|
||
"--enable-static"
|
||
"--disable-shared"
|
||
];
|
||
cmakeFlags = (args.cmakeFlags or [ ]) ++ [ "-DBUILD_SHARED_LIBS:BOOL=OFF" ];
|
||
mesonFlags = (args.mesonFlags or [ ]) ++ [
|
||
"-Ddefault_library=static"
|
||
"-Ddefault_both_libraries=static"
|
||
];
|
||
}
|
||
);
|
||
|
||
# Best effort static binaries. Will still be linked to libSystem,
|
||
# but more portable than Nix store binaries.
|
||
makeStaticDarwin =
|
||
stdenv:
|
||
stdenv.override (old: {
|
||
mkDerivationFromStdenv = withOldMkDerivation old (
|
||
stdenv: mkDerivationSuper: args:
|
||
(mkDerivationSuper args).overrideAttrs (
|
||
prevAttrs:
|
||
if prevAttrs ? env.NIX_CFLAGS_LINK then
|
||
{
|
||
env = prevAttrs.env // {
|
||
NIX_CFLAGS_LINK =
|
||
toString (args.env.NIX_CFLAGS_LINK or "")
|
||
+ lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
|
||
};
|
||
}
|
||
else
|
||
{
|
||
NIX_CFLAGS_LINK =
|
||
toString (prevAttrs.NIX_CFLAGS_LINK or "")
|
||
+ lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
|
||
}
|
||
)
|
||
);
|
||
});
|
||
|
||
# Puts all the other ones together
|
||
makeStatic =
|
||
stdenv:
|
||
lib.foldl' (lib.flip lib.id) stdenv (
|
||
lib.optional stdenv.hostPlatform.isDarwin makeStaticDarwin
|
||
|
||
++ [
|
||
makeStaticLibraries
|
||
propagateBuildInputs
|
||
]
|
||
|
||
# Apple does not provide a static version of libSystem or crt0.o
|
||
# So we can’t build static binaries without extensive hacks.
|
||
++ lib.optional (!stdenv.hostPlatform.isDarwin) makeStaticBinaries
|
||
);
|
||
|
||
/*
|
||
Modify a stdenv so that all buildInputs are implicitly propagated to
|
||
consuming derivations
|
||
*/
|
||
propagateBuildInputs = overrideMkDerivationArgs (args: {
|
||
propagatedBuildInputs = (args.propagatedBuildInputs or [ ]) ++ (args.buildInputs or [ ]);
|
||
buildInputs = [ ];
|
||
});
|
||
|
||
/*
|
||
Modify a stdenv so that the specified attributes are added to
|
||
every derivation returned by its mkDerivation function.
|
||
|
||
Example:
|
||
stdenvNoOptimise =
|
||
addAttrsToDerivation
|
||
{ env.NIX_CFLAGS_COMPILE = "-O0"; }
|
||
stdenv;
|
||
*/
|
||
addAttrsToDerivation = extraAttrs: overrideMkDerivationArgs (_: extraAttrs);
|
||
|
||
/*
|
||
Modify a stdenv so as to extend `mkDerivation`'s arguments.
|
||
A stronger version of `addAttrsToDerivation`.
|
||
|
||
Example:
|
||
requireCcache =
|
||
overrideMkDerivationArgs
|
||
(oldAttrs: {
|
||
requiredSystemFeatures = oldAttrs.requiredSystemFeatures or [ ] ++ [ "ccache" ];
|
||
});
|
||
*/
|
||
overrideMkDerivationArgs =
|
||
extension: stdenv:
|
||
stdenv.override (old: {
|
||
mkDerivationFromStdenv = extendMkDerivationArgs old extension;
|
||
});
|
||
|
||
/*
|
||
Use the trace output to report all processed derivations with their
|
||
license name.
|
||
*/
|
||
traceDrvLicenses =
|
||
stdenv:
|
||
stdenv.override (old: {
|
||
mkDerivationFromStdenv = overrideMkDerivationResult (
|
||
pkg:
|
||
let
|
||
printDrvPath =
|
||
val:
|
||
let
|
||
drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;
|
||
license = pkg.meta.license or null;
|
||
in
|
||
builtins.trace "@:drv:${toString drvPath}:${toString license}:@" val;
|
||
in
|
||
pkg
|
||
// {
|
||
outPath = printDrvPath pkg.outPath;
|
||
drvPath = printDrvPath pkg.drvPath;
|
||
}
|
||
);
|
||
});
|
||
|
||
/*
|
||
Modify a stdenv so that it produces debug builds; that is,
|
||
binaries have debug info, and compiler optimisations are
|
||
disabled.
|
||
*/
|
||
keepDebugInfo = overrideMkDerivationArgs (args: {
|
||
dontStrip = true;
|
||
env = (args.env or { }) // {
|
||
NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og";
|
||
NIX_RUSTFLAGS = toString (args.env.NIX_RUSTFLAGS or "") + " -g -C opt-level=0 -C strip=none";
|
||
};
|
||
});
|
||
|
||
# Modify a stdenv so that it uses the Gold linker.
|
||
useGoldLinker = overrideMkDerivationArgs (args: {
|
||
env = (args.env or { }) // {
|
||
NIX_CFLAGS_LINK = toString (args.env.NIX_CFLAGS_LINK or "") + " -fuse-ld=gold";
|
||
};
|
||
});
|
||
|
||
/*
|
||
Copy the libstdc++ from the model stdenv to the target stdenv.
|
||
|
||
TODO(@connorbaker):
|
||
This interface provides behavior which should be revisited prior to the
|
||
release of 24.05. For a more detailed explanation and discussion, see
|
||
https://github.com/NixOS/nixpkgs/issues/283517.
|
||
*/
|
||
useLibsFrom =
|
||
modelStdenv: targetStdenv:
|
||
let
|
||
ccForLibs = modelStdenv.cc.cc;
|
||
/*
|
||
NOTE(@connorbaker):
|
||
This assumes targetStdenv.cc is a cc-wrapper.
|
||
*/
|
||
cc = targetStdenv.cc.override {
|
||
/*
|
||
NOTE(originally by rrbutani):
|
||
Normally the `useCcForLibs`/`gccForLibs` mechanism is used to get a
|
||
clang based `cc` to use `libstdc++` (from gcc).
|
||
|
||
Here we (ab)use it to use a `libstdc++` from a different `gcc` than our
|
||
`cc`.
|
||
|
||
Note that this does not inhibit our `cc`'s lib dir from being added to
|
||
cflags/ldflags (see `cc_solib` in `cc-wrapper`) but this is okay: our
|
||
`gccForLibs`'s paths should take precedence.
|
||
*/
|
||
useCcForLibs = true;
|
||
gccForLibs = ccForLibs;
|
||
};
|
||
in
|
||
overrideCC targetStdenv cc;
|
||
|
||
useMoldLinker =
|
||
stdenv:
|
||
if stdenv.targetPlatform.isDarwin then
|
||
throw "Mold can't be used to emit Mach-O (Darwin) binaries"
|
||
else
|
||
let
|
||
bintools = stdenv.cc.bintools.override {
|
||
extraBuildCommands = ''
|
||
pushd $out/bin
|
||
ln -s ${pkgs.buildPackages.mold}/bin/${stdenv.cc.bintools.targetPrefix}ld.mold ${stdenv.cc.bintools.targetPrefix}ld.mold
|
||
'' # Pre-generated configure scripts call the linker binary without the target prefix when cross compiling.
|
||
+ lib.optionalString (stdenv.cc.bintools.targetPrefix != "") ''
|
||
ln -s ${stdenv.cc.bintools.targetPrefix}ld.mold ld.mold
|
||
''
|
||
+ ''
|
||
popd
|
||
'';
|
||
};
|
||
in
|
||
stdenv.override (
|
||
old:
|
||
{
|
||
allowedRequisites = null;
|
||
cc = stdenv.cc.override { inherit bintools; };
|
||
# gcc >12.1.0 supports '-fuse-ld=mold'
|
||
# the wrap ld above in bintools supports gcc <12.1.0 and shouldn't harm >12.1.0
|
||
# https://github.com/rui314/mold#how-to-use
|
||
}
|
||
//
|
||
lib.optionalAttrs
|
||
(stdenv.cc.isClang || (stdenv.cc.isGNU && lib.versionAtLeast stdenv.cc.version "12"))
|
||
{
|
||
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
|
||
env = (args.env or { }) // {
|
||
NIX_CFLAGS_LINK = toString (args.env.NIX_CFLAGS_LINK or "") + " -fuse-ld=mold";
|
||
};
|
||
});
|
||
}
|
||
);
|
||
|
||
useWildLinker =
|
||
stdenv:
|
||
if !stdenv.targetPlatform.isLinux then
|
||
throw "Wild only supports building Linux ELF files from Linux hosts."
|
||
else
|
||
stdenv.override (prev: {
|
||
allowedRequisites = null;
|
||
cc = prev.cc.override {
|
||
bintools = prev.cc.bintools.override {
|
||
extraBuildCommands = ''
|
||
ln -fs ${pkgs.buildPackages.wild}/bin/* "$out/bin"
|
||
'';
|
||
};
|
||
};
|
||
});
|
||
|
||
/*
|
||
Modify a stdenv so that it builds binaries optimized specifically
|
||
for the machine they are built on.
|
||
|
||
WARNING: this breaks purity!
|
||
*/
|
||
impureUseNativeOptimizations = overrideMkDerivationArgs (args: {
|
||
env = (args.env or { }) // {
|
||
NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " -march=native";
|
||
};
|
||
|
||
NIX_ENFORCE_NO_NATIVE = false;
|
||
|
||
preferLocalBuild = true;
|
||
allowSubstitutes = false;
|
||
});
|
||
|
||
/*
|
||
Modify a stdenv so that it builds binaries with the specified list of
|
||
compilerFlags appended and passed to the compiler.
|
||
|
||
This example would recompile every derivation on the system with
|
||
-funroll-loops and -O3 passed to each gcc invocation.
|
||
|
||
Example:
|
||
nixpkgs.overlays = [
|
||
(self: super: {
|
||
stdenv = super.withCFlags [ "-funroll-loops" "-O3" ] super.stdenv;
|
||
})
|
||
];
|
||
*/
|
||
withCFlags =
|
||
compilerFlags:
|
||
overrideMkDerivationArgs (args: {
|
||
env = (args.env or { }) // {
|
||
NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}";
|
||
};
|
||
});
|
||
|
||
withDefaultHardeningFlags =
|
||
defaultHardeningFlags: stdenv:
|
||
let
|
||
bintools =
|
||
let
|
||
bintools' = stdenv.cc.bintools;
|
||
in
|
||
if bintools' ? override then
|
||
(bintools'.override {
|
||
inherit defaultHardeningFlags;
|
||
})
|
||
else
|
||
bintools';
|
||
in
|
||
stdenv.override (old: {
|
||
cc =
|
||
if stdenv.cc == null then
|
||
null
|
||
else
|
||
stdenv.cc.override {
|
||
inherit bintools;
|
||
};
|
||
allowedRequisites = lib.mapNullable (rs: rs ++ [ bintools ]) (stdenv.allowedRequisites or null);
|
||
});
|
||
}
|