nixpkgs/pkgs/stdenv/adapters.nix

295 lines
10 KiB
Nix
Raw Normal View History

/* 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 = import ./generic/make-derivation.nix { inherit lib config; };
# 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 // f args));
# 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; };
# 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:
2020-04-28 14:51:39 +00:00
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 // {
NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -static";
} // lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) {
configureFlags = (args.configureFlags or []) ++ [
"--disable-shared" # brrr...
];
}));
} // lib.optionalAttrs (stdenv0.hostPlatform.libc == "libc") {
extraBuildInputs = (old.extraBuildInputs or []) ++ [
stdenv0.glibc.static
];
});
# Return a modified stdenv that builds static libraries instead of
# shared libraries.
makeStaticLibraries = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (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" ];
});
});
# Best effort static binaries. Will still be linked to libSystem,
# but more portable than Nix store binaries.
makeStaticDarwin = stdenv: stdenv.override (old: {
# extraBuildInputs are dropped in cross.nix, but darwin still needs them
extraBuildInputs = [ pkgs.buildPackages.darwin.CF ];
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "")
+ lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
nativeBuildInputs = (args.nativeBuildInputs or []) ++ [
(pkgs.buildPackages.makeSetupHook {
substitutions = {
libsystem = "${stdenv.cc.libc}/lib/libSystem.B.dylib";
};
} ./darwin/portable-libsystem.sh)
];
});
});
2021-08-20 06:03:45 +00:00
# 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 cant build static binaries without extensive hacks.
++ lib.optional (!stdenv.hostPlatform.isDarwin) makeStaticBinaries
# Glibc doesnt come with static runtimes by default.
# ++ lib.optional (stdenv.hostPlatform.libc == "glibc") ((lib.flip overrideInStdenv) [ self.stdenv.glibc.static ])
);
2019-07-24 14:04:51 +00:00
/* Modify a stdenv so that all buildInputs are implicitly propagated to
consuming derivations
*/
propagateBuildInputs = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
2019-07-24 14:04:51 +00:00
propagatedBuildInputs = (args.propagatedBuildInputs or []) ++ (args.buildInputs or []);
buildInputs = [];
});
});
2019-07-24 14:04:51 +00:00
/* Modify a stdenv so that the specified attributes are added to
every derivation returned by its mkDerivation function.
Example:
stdenvNoOptimise =
addAttrsToDerivation
{ NIX_CFLAGS_COMPILE = "-O0"; }
stdenv;
*/
addAttrsToDerivation = extraAttrs: stdenv: stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
});
/* Return a modified stdenv that builds packages with GCC's coverage
instrumentation. The coverage note files (*.gcno) are stored in
$out/.build, along with the source code of the package, to enable
programs like lcov to produce pretty-printed reports.
*/
addCoverageInstrumentation = stdenv:
overrideInStdenv stdenv [ pkgs.enableGCOVInstrumentation pkgs.keepBuildTree ];
/* Replace the meta.maintainers field of a derivation. This is useful
when you want to fork to update some packages without disturbing other
developers.
e.g.: in all-packages.nix:
# remove all maintainers.
defaultStdenv = replaceMaintainersField allStdenvs.stdenv pkgs [];
*/
replaceMaintainersField = stdenv: pkgs: maintainers:
stdenv.override (old: {
mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
lib.recursiveUpdate pkg { meta.maintainers = maintainers; });
});
/* 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}:${builtins.toString license}:@" val;
in pkg // {
outPath = printDrvPath pkg.outPath;
drvPath = printDrvPath pkg.drvPath;
});
});
/* Abort if the license predicate is not verified for a derivation
declared with mkDerivation.
One possible predicate to avoid all non-free packages can be achieved
with the following function:
isFree = license: with builtins;
if license == null then true
else if isList license then lib.all isFree license
else license != "non-free" && license != "unfree";
This adapter can be defined on the defaultStdenv definition. You can
use it by patching the all-packages.nix file or by using the override
feature of ~/.config/nixpkgs/config.nix .
*/
validateLicenses = licensePred: stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
let
drv = builtins.unsafeDiscardStringContext pkg.drvPath;
license =
pkg.meta.license or
# Fixed-output derivations such as source tarballs usually
# don't have licensing information, but that's OK.
(pkg.outputHash or
(builtins.trace
"warning: ${drv} lacks licensing information" null));
validate = arg:
if licensePred license then arg
else abort ''
while building ${drv}:
license `${builtins.toString license}' does not pass the predicate.
'';
in pkg // {
outPath = validate pkg.outPath;
drvPath = validate pkg.drvPath;
});
});
/* Modify a stdenv so that it produces debug builds; that is,
binaries have debug info, and compiler optimisations are
disabled. */
keepDebugInfo = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
dontStrip = true;
NIX_CFLAGS_COMPILE = toString (args.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og";
});
});
/* Modify a stdenv so that it uses the Gold linker. */
useGoldLinker = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=gold";
});
});
/* Modify a stdenv so that it builds binaries optimized specifically
for the machine they are built on.
WARNING: this breaks purity! */
impureUseNativeOptimizations = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
NIX_CFLAGS_COMPILE = toString (args.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: stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
NIX_CFLAGS_COMPILE = toString (args.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}";
});
});
}