nixos-conf/custom/modules/kernel.nix

222 lines
7.6 KiB
Nix

{
pkgs,
lib,
kernel-src,
buildLinux,
structuredExtraConfig ? { },
kernelPatches ? [ ],
extraConfig ? "",
sccacheDir ? "/var/cache/sccache/nix-builds/kernel",
sccacheServerUds ? null,
enforceSccache ? true,
features ? { },
randstructSeed ? null,
...
}:
let
makefile = builtins.readFile "${kernel-src}/Makefile";
lines = lib.splitString "\n" makefile;
normalizeKernelPatch = p: p // { patch = p.patch or null; };
kernelPatches' = map normalizeKernelPatch kernelPatches;
get =
name:
let
line = lib.findFirst (
l: lib.hasPrefix "${name} =" (lib.strings.trim l)
) (throw "Makefile missing ${name}") lines;
in
lib.strings.trim (lib.removePrefix "${name} =" (lib.strings.trim line));
V = get "VERSION";
P = get "PATCHLEVEL";
S = get "SUBLEVEL";
E = get "EXTRAVERSION";
kver = "${V}.${P}.${S}${E}";
in
let
args = {
inherit
buildLinux
features
randstructSeed
;
};
llvm = pkgs.llvmPackages_latest;
rust = pkgs.rustc-unwrapped;
buildPkgs = args.buildPackages or pkgs.buildPackages;
buildLlvm = buildPkgs.llvmPackages_latest;
llvmBuildPackages = buildPkgs // {
stdenv = buildLlvm.stdenv;
};
realClang = lib.getExe llvm.clang-unwrapped;
realLd = lib.getExe' llvm.lld "ld.lld";
realAr = lib.getExe' llvm.llvm "llvm-ar";
realNm = lib.getExe' llvm.llvm "llvm-nm";
realStrip = lib.getExe' llvm.llvm "llvm-strip";
realObjcopy = lib.getExe' llvm.llvm "llvm-objcopy";
realObjdump = lib.getExe' llvm.llvm "llvm-objdump";
realReadelf = lib.getExe' llvm.llvm "llvm-readelf";
realHostCC = lib.getExe' buildLlvm.stdenv.cc "${buildLlvm.stdenv.cc.targetPrefix}cc";
realHostCXX = lib.getExe' buildLlvm.stdenv.cc "${buildLlvm.stdenv.cc.targetPrefix}c++";
realHostAr = lib.getExe' buildLlvm.llvm "llvm-ar";
realHostLd = lib.getExe' buildLlvm.lld "ld.lld";
realRustc = lib.getExe' rust "rustc";
realHostRustc = realRustc;
sccacheConfig = pkgs.writeText "kernel-sccache.conf" ''
[cache.disk]
dir = "${sccacheDir}"
size = "100G"
'';
mkSccacheWrapper =
name: compiler:
pkgs.runCommand "${name}-sccache-wrapper"
{
passthru.meta.mainProgram = name;
}
''
mkdir -p $out/bin
cat > $out/bin/${name} <<'WRAP'
#!${pkgs.bash}/bin/bash
exec ${pkgs.sccache}/bin/sccache ${compiler} "$@"
WRAP
chmod +x $out/bin/${name}
'';
sccacheSetup = lib.optionalString enforceSccache ''
mkdir -p ${lib.escapeShellArg sccacheDir} 2>/dev/null || true
mkdir -p "$NIX_BUILD_TOP/.sccache/preprocessor" 2>/dev/null || true
export SCCACHE_CONF=${lib.escapeShellArg sccacheConfig}
export SCCACHE_LOCAL_PREPROCESSOR_CACHE_DIR="$NIX_BUILD_TOP/.sccache/preprocessor"
export SCCACHE_NO_DAEMON=1
'';
clangSccache = mkSccacheWrapper "clang" realClang;
hostccSccache = mkSccacheWrapper "cc" realHostCC;
hostcxxSccache = mkSccacheWrapper "c++" realHostCXX;
rustcSccache = pkgs.writeShellScriptBin "rustc" ''
set -euo pipefail
mkdir -p ${lib.escapeShellArg sccacheDir} 2>/dev/null || true
mkdir -p "$NIX_BUILD_TOP/.sccache/preprocessor" 2>/dev/null || true
export SCCACHE_CONF=${lib.escapeShellArg sccacheConfig}
export SCCACHE_LOCAL_PREPROCESSOR_CACHE_DIR="$NIX_BUILD_TOP/.sccache/preprocessor"
export SCCACHE_NO_DAEMON=1
${lib.optionalString (
sccacheServerUds != null
) "export SCCACHE_SERVER_UDS=${lib.escapeShellArg sccacheServerUds}"}
if [ -n "''${SCCACHE_ENFORCE_MARKER-}" ]; then
: > "''${SCCACHE_ENFORCE_MARKER}"
fi
exec ${pkgs.sccache}/bin/sccache ${realRustc} "$@"
'';
hostrustcSccache = pkgs.writeShellScriptBin "rustc" ''
set -euo pipefail
mkdir -p ${lib.escapeShellArg sccacheDir} 2>/dev/null || true
mkdir -p "$NIX_BUILD_TOP/.sccache/preprocessor" 2>/dev/null || true
export SCCACHE_CONF=${lib.escapeShellArg sccacheConfig}
export SCCACHE_LOCAL_PREPROCESSOR_CACHE_DIR="$NIX_BUILD_TOP/.sccache/preprocessor"
export SCCACHE_NO_DAEMON=1
${lib.optionalString (
sccacheServerUds != null
) "export SCCACHE_SERVER_UDS=${lib.escapeShellArg sccacheServerUds}"}
'';
structuredExtraConfig' =
(with lib.kernel; {
LTO_CLANG_THIN = yes;
# LTO_CLANG_FULL = no;
# LTO_NONE = no;
})
// structuredExtraConfig;
in
(buildLinux (
args
// {
kernelPatches = kernelPatches';
inherit extraConfig;
version = kver;
modDirVersion = kver;
src = kernel-src;
stdenv = llvm.stdenv;
buildPackages = llvmBuildPackages;
extraMakeFlags = (args.extraMakeFlags or [ ]) ++ [
"LLVM=1"
"LLVM_IAS=1"
"CC=${lib.getExe clangSccache}"
"LD=${realLd}"
"AR=${realAr}"
"NM=${realNm}"
"STRIP=${realStrip}"
"OBJCOPY=${realObjcopy}"
"OBJDUMP=${realObjdump}"
"READELF=${realReadelf}"
"HOSTCC=${lib.getExe hostccSccache}"
"HOSTCXX=${lib.getExe hostcxxSccache}"
"HOSTAR=${realHostAr}"
"HOSTLD=${realHostLd}"
"RUSTC=${lib.getExe rustcSccache}"
"HOSTRUSTC=${lib.getExe hostrustcSccache}"
];
structuredExtraConfig = structuredExtraConfig';
ignoreConfigErrors = true;
extraMeta.branch = "${V}.${P}";
}
)).overrideAttrs
(old: {
__noChroot = true;
postPatch =
(old.postPatch or "")
+ sccacheSetup
+ lib.optionalString enforceSccache ''
# -- Sccache caching smoke test --
echo "==> Testing sccache caching..."
SCCACHE_TEST_SRC="$NIX_BUILD_TOP/.sccache-test.c"
SCCACHE_TEST_OBJ="$NIX_BUILD_TOP/.sccache-test.o"
SCCACHE_TEST_ID=$(date +%s%N)
printf '// sccache smoke test %s\nint main(void) { return 0; }\n' "$SCCACHE_TEST_ID" > "$SCCACHE_TEST_SRC"
${pkgs.sccache}/bin/sccache --zero-stats >/dev/null 2>&1 || true
${lib.getExe clangSccache} -c "$SCCACHE_TEST_SRC" -o "$SCCACHE_TEST_OBJ" 2>&1
STATS1=$(${pkgs.sccache}/bin/sccache --show-stats --stats-format json 2>/dev/null || echo '{}')
COMPILED=$(echo "$STATS1" | ${pkgs.jq}/bin/jq '[.stats.cache_hits.counts // {}, .stats.cache_misses.counts // {}] | add | to_entries | map(.value) | add // 0' 2>/dev/null || echo 0)
WRITE_ERRORS=$(echo "$STATS1" | ${pkgs.jq}/bin/jq '.stats.cache_errors.counts // {} | to_entries | map(.value) | add // 0' 2>/dev/null || echo 0)
if [ "$COMPILED" -lt 1 ]; then
echo "FATAL: sccache first compile was not cached."
${pkgs.sccache}/bin/sccache --show-stats --stats-format text || true
exit 1
fi
if [ "$WRITE_ERRORS" -gt 0 ]; then
echo "FATAL: sccache cache write errors detected ($WRITE_ERRORS)."
${pkgs.sccache}/bin/sccache --show-stats --stats-format text || true
exit 1
fi
echo "==> sccache first compile OK (cached=$COMPILED, write_errors=$WRITE_ERRORS)"
rm -f "$SCCACHE_TEST_OBJ"
${lib.getExe clangSccache} -c "$SCCACHE_TEST_SRC" -o "$SCCACHE_TEST_OBJ" 2>&1
STATS2=$(${pkgs.sccache}/bin/sccache --show-stats --stats-format json 2>/dev/null || echo '{}')
HITS=$(echo "$STATS2" | ${pkgs.jq}/bin/jq '.stats.cache_hits.counts // {} | to_entries | map(.value) | add // 0' 2>/dev/null || echo 0)
if [ "$HITS" -lt 1 ]; then
echo "FATAL: sccache second compile did not hit cache."
${pkgs.sccache}/bin/sccache --show-stats --stats-format text || true
exit 1
fi
echo "==> sccache cache hit OK (hits=$HITS)"
rm -f "$SCCACHE_TEST_SRC" "$SCCACHE_TEST_OBJ"
${pkgs.sccache}/bin/sccache --zero-stats >/dev/null 2>&1 || true
# -- End sccache caching smoke test --
'';
})