nixpkgs/pkgs/stdenv/adapters.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

350 lines
13 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 = stdenv: (import ./generic/make-derivation.nix { inherit lib config; } 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.
Clean up cross bootstrapping For a long time, we've had `crossLibcStdenv`, `*Cross` libc attributes, and `*bsdCross` pre-libc package sets. This was always bad because having "cross" things is "not declarative": the naming doesn't reflect what packages *need* but rather how we *provide* something. This is ugly, and creates needless friction between cross and native building. Now, almost all of these `*Cross` attributes are gone: just these are kept: - Glibc's and Musl's are kept, because those packages are widely used and I didn't want to risk changing the native builds of those at this time. - generic `libcCross`, `theadsCross`, and friends, because these relate to the convolulted GCC bootstrap which still needs to be redone. The BSD and obscure Linux or freestnanding libcs have conversely all been made to use a new `stdenvNoLibc`, which is like the old `crossLibcStdenv` except: 1. It usable for native and cross alike 2. It named according to what it *is* ("a standard environment without libc but with a C compiler"), rather than some non-compositional jargon ("the stdenv used for building libc when cross compiling", yuck). I should have done this change long ago, but I was stymied because of "infinite recursions". The problem was that in too many cases we are overriding `stdenv` to *remove* things we don't need, and this risks cyles since those more minimal stdenvs are used to build things in the more maximal stdenvs. The solution is to pass `stage.nix` `stdenvNoCC`, so we can override to *build up* rather than *tear down*. For now, the full `stdenv` is also passed, so I don't need to change the native bootstraps, but I can see this changing as we make things more uniform and clean those up. Finally, the BSDs also had to be cleaned up, since they have a few pre-libc dependencies, demanding a systematic approach. I realized what rhelmot did in 61202561d92cf1cd74532fcbd8b9d6662c5bc57b (specify what packages just need `stdenvNoLibc`) is definitely the right approach for this, and adjusted NetBSD and OpenBSD to likewise use it.
2024-06-18 16:38:21 +00:00
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:
2020-04-28 14:51:39 +00:00
stdenv.override (prev: { allowedRequisites = null; extraBuildInputs = (prev.extraBuildInputs or []) ++ pkgs; });
# 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;
llvmPackages_{12,13,14,15,16,17,git}.{libcxx,libcxxabi}: merge libcxxabi into libcxx (#292043) - merge libcxxabi into libcxx for LLVM 12, 13, 14, 15, 16, 17, and git. - remove the link time workaround `-lc++ -lc++abi` from 58 packages as it is no longer required. - fixes https://github.com/NixOS/nixpkgs/issues/166205 - provides alternative fixes for. https://github.com/NixOS/nixpkgs/issues/269548 https://github.com/NixOS/nix/issues/9640 - pkgsCross.x86_64-freebsd builds work again This change can be represented in 3 stages 1. merge libcxxabi into libcxx -- files: pkgs/development/compilers/llvm/[12, git]/{libcxx, libcxxabi} 2. update stdenv to account for merge -- files: stdenv.{adapters, cc.wrapper, darwin} 3. remove all references to libcxxabi outside of llvm (about 58 packages modified) ### merging libcxxabi into libcxx - take the union of the libcxxabi and libcxx cmake flags - eliminate the libcxx-headers-only package - it was only needed to break libcxx <-> libcxxabi circular dependency - libcxx.cxxabi is removed. external cxxabi (freebsd) will symlink headers / libs into libcxx. - darwin will re-export the libcxxabi symbols into libcxx so linking `-lc++` is sufficient. - linux/freebsd `libc++.so` is a linker script `LINK(libc++.so.1, -lc++abi)` making `-lc++` sufficient. - libcxx/default.nix [12, 17] are identical except for patches and `LIBCXX_ADDITIONAL_LIBRARIES` (only used in 16+) - git/libcxx/defaul.nix does not link with -nostdlib when useLLVM is true so flag is removed. this is not much different than before as libcxxabi used -nostdlib where libcxx did not, so libc was linked in anyway. ### stdenv changes - darwin bootstrap, remove references to libcxxabi and cxxabi - cc-wrapper: remove c++ link workaround when libcxx.cxxabi doesn't exist (still exists for LLVM pre 12) - adapter: update overrideLibcxx to account for a pkgs.stdenv that only has libcxx ### 58 package updates - remove `NIX_LDFLAGS = "-l${stdenv.cc.libcxx.cxxabi.libName}` as no longer needed - swift, nodejs_v8 remove libcxxabi references in the clang override https://github.com/NixOS/nixpkgs/pull/292043
2024-03-11 10:53:37 +00:00
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"
'';
in
overrideCC stdenv (stdenv.cc.override {
inherit libcxx;
extraPackages = [
pkgs.buildPackages.targetPackages."llvmPackages_${lib.versions.major llvmLibcxxVersion}".compiler-rt
];
});
# 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: {
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 []) ++ [
2022-05-23 18:28:14 +00:00
pkgs.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 = 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)
];
}));
});
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
);
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
{ env.NIX_CFLAGS_COMPILE = "-O0"; }
stdenv;
*/
addAttrsToDerivation = extraAttrs: stdenv: stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (_: extraAttrs);
});
/* 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;
});
});
/* 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;
env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.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";
});
});
/* 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-01-11 00:25:59 +00:00
useLibsFrom = modelStdenv: targetStdenv:
let
ccForLibs = modelStdenv.cc.cc;
/* NOTE(@connorbaker):
* This assumes targetStdenv.cc is a cc-wrapper. */
cc = targetStdenv.cc.override {
2024-01-11 00:25:59 +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. */
useCcForLibs = true;
gccForLibs = ccForLibs;
};
in
overrideCC targetStdenv cc;
2023-02-17 03:18:19 +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
2023-02-17 03:18:19 +00:00
'';
};
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
2023-02-17 03:18:19 +00:00
# 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";
});
});
/* 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: {
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: stdenv:
stdenv.override (old: {
mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
env = (args.env or {}) // { NIX_CFLAGS_COMPILE = toString (args.env.NIX_CFLAGS_COMPILE or "") + " ${toString compilerFlags}"; };
});
});
# 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)
stdenvNoCC
pkgsBuildBuild
pkgsBuildHost
pkgsBuildTarget
pkgsHostHost
pkgsHostTarget
pkgsTargetTarget;
};
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);
});
}