core/pkgs/stdenv/adapters.nix

378 lines
14 KiB
Nix
Raw Normal View History

2024-05-13 22:50:12 +00:00
/* *
Various functions that take a stdenv and return a new stdenv with different behaviour.
e.g. using a different C compiler.
2024-05-13 21:24:10 +00:00
*/
2024-05-02 00:46:19 +00:00
{ lib, pkgs, config }:
let
# N.B. Keep in sync with default arg for stdenv/generic.
2024-05-13 21:24:10 +00:00
defaultMkDerivationFromStdenv = stdenv:
(import ./generic/make-derivation.nix { inherit lib config; }
stdenv).mkDerivation;
2024-05-02 00:46:19 +00:00
# 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.
2024-05-13 21:24:10 +00:00
withOldMkDerivation = stdenvSuperArgs: k: stdenvSelf:
let
mkDerivationFromStdenv-super =
stdenvSuperArgs.mkDerivationFromStdenv or defaultMkDerivationFromStdenv;
mkDerivationSuper = mkDerivationFromStdenv-super stdenvSelf;
in k stdenvSelf mkDerivationSuper;
2024-05-02 00:46:19 +00:00
# Wrap the original `mkDerivation` providing extra args to it.
2024-05-13 21:24:10 +00:00
extendMkDerivationArgs = old: f:
withOldMkDerivation old
(_: mkDerivationSuper: args: (mkDerivationSuper args).overrideAttrs f);
2024-05-02 00:46:19 +00:00
# Wrap the original `mkDerivation` transforming the result.
2024-05-13 21:24:10 +00:00
overrideMkDerivationResult = old: f:
withOldMkDerivation old
(_: mkDerivationSuper: args: f (mkDerivationSuper args));
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
in rec {
2024-05-02 00:46:19 +00:00
# Override the compiler in stdenv for specific packages.
2024-05-13 21:24:10 +00:00
overrideCC = stdenv: cc:
stdenv.override {
allowedRequisites = null;
cc = cc;
};
2024-05-02 00:46:19 +00:00
# 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:
2024-05-13 21:24:10 +00:00
stdenv.override (prev: {
allowedRequisites = null;
extraBuildInputs = (prev.extraBuildInputs or [ ]) ++ pkgs;
});
2024-05-02 00:46:19 +00:00
# Override the libc++ dynamic library used in the stdenv to use the one from the platforms
# default stdenv. This allows building packages and linking dependencies with different
# compiler versions while still using the same libc++ implementation for compatibility.
#
# Note that this adapter still uses the headers from the new stdenvs libc++. This is necessary
# because older compilers may not be able to parse the headers from the default stdenvs libc++.
overrideLibcxx = stdenv:
assert stdenv.cc.libcxx != null;
assert pkgs.stdenv.cc.libcxx != null;
# only unified libcxx / libcxxabi stdenv's are supported
assert lib.versionAtLeast pkgs.stdenv.cc.libcxx.version "12";
assert lib.versionAtLeast stdenv.cc.libcxx.version "12";
let
llvmLibcxxVersion = lib.getVersion llvmLibcxx;
stdenvLibcxx = pkgs.stdenv.cc.libcxx;
llvmLibcxx = stdenv.cc.libcxx;
libcxx = pkgs.runCommand "${stdenvLibcxx.name}-${llvmLibcxxVersion}" {
outputs = [ "out" "dev" ];
isLLVM = true;
} ''
mkdir -p "$dev/nix-support"
ln -s '${stdenvLibcxx}' "$out"
echo '${stdenvLibcxx}' > "$dev/nix-support/propagated-build-inputs"
ln -s '${lib.getDev llvmLibcxx}/include' "$dev/include"
'';
2024-05-13 21:24:10 +00:00
in overrideCC stdenv (stdenv.cc.override {
2024-05-02 00:46:19 +00:00
inherit libcxx;
extraPackages = [
2024-05-13 21:24:10 +00:00
pkgs.buildPackages.targetPackages."llvmPackages_${
lib.versions.major llvmLibcxxVersion
}".compiler-rt
2024-05-02 00:46:19 +00:00
];
});
# 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:
2024-05-13 21:24:10 +00:00
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:
{
NIX_CFLAGS_LINK = toString (args.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 ];
});
2024-05-02 00:46:19 +00:00
# Return a modified stdenv that builds static libraries instead of
# shared libraries.
makeStaticLibraries = stdenv:
stdenv.override (old: {
2024-05-13 21:24:10 +00:00
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" ];
});
2024-05-02 00:46:19 +00:00
});
# Best effort static binaries. Will still be linked to libSystem,
# but more portable than Nix store binaries.
2024-05-13 21:24:10 +00:00
makeStaticDarwin = stdenv:
stdenv.override (old: {
# extraBuildInputs are dropped in cross.nix, but darwin still needs them
extraBuildInputs = [ pkgs.buildPackages.darwin.CF ];
mkDerivationFromStdenv = withOldMkDerivation old
(stdenv: mkDerivationSuper: args:
(mkDerivationSuper args).overrideAttrs (prevAttrs: {
NIX_CFLAGS_LINK = toString (prevAttrs.NIX_CFLAGS_LINK or "")
+ lib.optionalString (stdenv.cc.isGNU or false) " -static-libgcc";
nativeBuildInputs = (prevAttrs.nativeBuildInputs or [ ])
++ lib.optionals stdenv.hasCC [
(pkgs.buildPackages.makeSetupHook {
name = "darwin-portable-libSystem-hook";
substitutions = {
libsystem = "${stdenv.cc.libc}/lib/libSystem.B.dylib";
targetPrefix = stdenv.cc.bintools.targetPrefix;
};
} ./darwin/portable-libsystem.sh)
];
}));
});
2024-05-02 00:46:19 +00:00
# Puts all the other ones together
2024-05-13 21:24:10 +00:00
makeStatic = stdenv:
lib.foldl (lib.flip lib.id) stdenv
(lib.optional stdenv.hostPlatform.isDarwin makeStaticDarwin
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
++ [
makeStaticLibraries
propagateBuildInputs
]
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
# 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);
2024-05-02 00:46:19 +00:00
/* Modify a stdenv so that all buildInputs are implicitly propagated to
consuming derivations
*/
propagateBuildInputs = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
2024-05-13 21:24:10 +00:00
propagatedBuildInputs = (args.propagatedBuildInputs or [ ])
++ (args.buildInputs or [ ]);
buildInputs = [ ];
2024-05-02 00:46:19 +00:00
});
});
/* 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;
*/
2024-05-13 21:24:10 +00:00
addAttrsToDerivation = extraAttrs: stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
});
2024-05-02 00:46:19 +00:00
/* Use the trace output to report all processed derivations with their
license name.
*/
traceDrvLicenses = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = overrideMkDerivationResult (pkg:
let
2024-05-13 21:24:10 +00:00
printDrvPath = val:
let
drvPath = builtins.unsafeDiscardStringContext pkg.drvPath;
license = pkg.meta.license or null;
in builtins.trace
"@:drv:${toString drvPath}:${builtins.toString license}:@" val;
2024-05-02 00:46:19 +00:00
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
2024-05-13 21:24:10 +00:00
disabled.
*/
2024-05-02 00:46:19 +00:00
keepDebugInfo = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
dontStrip = true;
2024-05-13 21:24:10 +00:00
env = (args.env or { }) // {
NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "")
+ " -ggdb -Og";
};
2024-05-02 00:46:19 +00:00
});
});
2024-05-13 21:24:10 +00:00
# Modify a stdenv so that it uses the Gold linker.
2024-05-02 00:46:19 +00:00
useGoldLinker = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
2024-05-13 21:24:10 +00:00
NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "")
+ " -fuse-ld=gold";
2024-05-02 00:46:19 +00:00
});
});
2024-05-13 21:24:10 +00:00
# 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.
2024-05-02 00:46:19 +00:00
useLibsFrom = modelStdenv: targetStdenv:
let
ccForLibs = modelStdenv.cc.cc;
2024-05-13 21:24:10 +00:00
# NOTE(@connorbaker):
# This assumes targetStdenv.cc is a cc-wrapper.
2024-05-02 00:46:19 +00:00
cc = targetStdenv.cc.override {
2024-05-13 21:24:10 +00:00
# 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.
2024-05-02 00:46:19 +00:00
useCcForLibs = true;
gccForLibs = ccForLibs;
};
2024-05-13 21:24:10 +00:00
in overrideCC targetStdenv cc;
2024-05-02 00:46:19 +00:00
2024-05-13 21:24:10 +00:00
useMoldLinker = stdenv:
let
bintools = stdenv.cc.bintools.override {
extraBuildCommands = ''
wrap ${stdenv.cc.bintools.targetPrefix}ld.mold ${
../build-support/bintools-wrapper/ld-wrapper.sh
} ${pkgs.mold}/bin/ld.mold
wrap ${stdenv.cc.bintools.targetPrefix}ld ${
../build-support/bintools-wrapper/ld-wrapper.sh
} ${pkgs.mold}/bin/ld.mold
'';
};
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: {
NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "")
+ " -fuse-ld=mold";
});
});
2024-05-02 00:46:19 +00:00
/* Modify a stdenv so that it builds binaries optimized specifically
for the machine they are built on.
2024-05-13 21:24:10 +00:00
WARNING: this breaks purity!
*/
2024-05-02 00:46:19 +00:00
impureUseNativeOptimizations = stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
2024-05-13 21:24:10 +00:00
env = (args.env or { }) // {
NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "")
+ " -march=native";
};
2024-05-02 00:46:19 +00:00
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: {
2024-05-13 21:24:10 +00:00
env = (args.env or { }) // {
NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "")
+ " ${toString compilerFlags}";
};
2024-05-02 00:46:19 +00:00
});
});
# Overriding the SDK changes the Darwin SDK used to build the package, which:
# * Ensures that the compiler and bintools have the correct Libsystem version; and
# * Replaces any SDK references with those in the SDK corresponding to the requested SDK version.
#
# `sdkVersion` can be any of the following:
# * A version string indicating the requested SDK version; or
# * An attrset consisting of either or both of the following fields: darwinSdkVersion and darwinMinVersion.
overrideSDK = import ./darwin/override-sdk.nix {
inherit lib extendMkDerivationArgs;
inherit (pkgs)
2024-05-13 21:24:10 +00:00
stdenvNoCC pkgsBuildBuild pkgsBuildHost pkgsBuildTarget pkgsHostHost
pkgsHostTarget pkgsTargetTarget;
2024-05-02 00:46:19 +00:00
};
2024-05-13 21:24:10 +00:00
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);
2024-05-02 00:46:19 +00:00
});
}