{ 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 -- ''; })