Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at devShellTools-shell 579 lines 20 kB view raw
1{ 2 lib, 3 stdenv, 4 buildPackages, 5 runCommand, 6 bc, 7 bison, 8 flex, 9 perl, 10 rsync, 11 gmp, 12 libmpc, 13 mpfr, 14 openssl, 15 cpio, 16 elfutils, 17 hexdump, 18 zstd, 19 python3Minimal, 20 zlib, 21 pahole, 22 kmod, 23 ubootTools, 24 fetchpatch, 25 rustc, 26 rust-bindgen, 27 rustPlatform, 28}: 29 30let 31 lib_ = lib; 32 stdenv_ = stdenv; 33 34 readConfig = 35 configfile: 36 import 37 (runCommand "config.nix" { } '' 38 echo "{" > "$out" 39 while IFS='=' read key val; do 40 [ "x''${key#CONFIG_}" != "x$key" ] || continue 41 no_firstquote="''${val#\"}"; 42 echo ' "'"$key"'" = "'"''${no_firstquote%\"}"'";' >> "$out" 43 done < "${configfile}" 44 echo "}" >> $out 45 '').outPath; 46in 47lib.makeOverridable ( 48 { 49 # The kernel version 50 version, 51 # The kernel pname (should be set for variants) 52 pname ? "linux", 53 # Position of the Linux build expression 54 pos ? null, 55 # Additional kernel make flags 56 extraMakeFlags ? [ ], 57 # The name of the kernel module directory 58 # Needs to be X.Y.Z[-extra], so pad with zeros if needed. 59 modDirVersion ? null, # derive from version 60 # The kernel source (tarball, git checkout, etc.) 61 src, 62 # a list of { name=..., patch=..., extraConfig=...} patches 63 kernelPatches ? [ ], 64 # The kernel .config file 65 configfile, 66 # Manually specified nixexpr representing the config 67 # If unspecified, this will be autodetected from the .config 68 config ? lib.optionalAttrs allowImportFromDerivation (readConfig configfile), 69 # Custom seed used for CONFIG_GCC_PLUGIN_RANDSTRUCT if enabled. This is 70 # automatically extended with extra per-version and per-config values. 71 randstructSeed ? "", 72 # Extra meta attributes 73 extraMeta ? { }, 74 75 # for module compatibility 76 isZen ? false, 77 isLibre ? false, 78 isHardened ? false, 79 80 # Whether to utilize the controversial import-from-derivation feature to parse the config 81 allowImportFromDerivation ? false, 82 # ignored 83 features ? null, 84 lib ? lib_, 85 stdenv ? stdenv_, 86 }: 87 88 let 89 # Provide defaults. Note that we support `null` so that callers don't need to use optionalAttrs, 90 # which can lead to unnecessary strictness and infinite recursions. 91 modDirVersion_ = if modDirVersion == null then lib.versions.pad 3 version else modDirVersion; 92 in 93 let 94 # Shadow the un-defaulted parameter; don't want null. 95 modDirVersion = modDirVersion_; 96 inherit (lib) 97 hasAttr 98 getAttr 99 optional 100 optionals 101 optionalString 102 optionalAttrs 103 maintainers 104 teams 105 platforms 106 ; 107 108 drvAttrs = 109 config_: kernelConf: kernelPatches: configfile: 110 let 111 # Folding in `ubootTools` in the default nativeBuildInputs is problematic, as 112 # it makes updating U-Boot cumbersome, since it will go above the current 113 # threshold of rebuilds 114 # 115 # To prevent these needless rounds of staging for U-Boot builds, we can 116 # limit the inclusion of ubootTools to target platforms where uImage *may* 117 # be produced. 118 # 119 # This command lists those (kernel-named) platforms: 120 # .../linux $ grep -l uImage ./arch/*/Makefile | cut -d'/' -f3 | sort 121 # 122 # This is still a guesstimation, but since none of our cached platforms 123 # coincide in that list, this gives us "perfect" decoupling here. 124 linuxPlatformsUsingUImage = [ 125 "arc" 126 "arm" 127 "csky" 128 "mips" 129 "powerpc" 130 "sh" 131 "sparc" 132 "xtensa" 133 ]; 134 needsUbootTools = lib.elem stdenv.hostPlatform.linuxArch linuxPlatformsUsingUImage; 135 136 config = 137 let 138 attrName = attr: "CONFIG_" + attr; 139 in 140 { 141 isSet = attr: hasAttr (attrName attr) config; 142 143 getValue = attr: if config.isSet attr then getAttr (attrName attr) config else null; 144 145 isYes = attr: (config.getValue attr) == "y"; 146 147 isNo = attr: (config.getValue attr) == "n"; 148 149 isModule = attr: (config.getValue attr) == "m"; 150 151 isEnabled = attr: (config.isModule attr) || (config.isYes attr); 152 153 isDisabled = attr: (!(config.isSet attr)) || (config.isNo attr); 154 } 155 // config_; 156 157 isModular = config.isYes "MODULES"; 158 withRust = config.isYes "RUST"; 159 160 buildDTBs = kernelConf.DTB or false; 161 162 # Dependencies that are required to build kernel modules 163 moduleBuildDependencies = [ 164 pahole 165 perl 166 elfutils 167 # module makefiles often run uname commands to find out the kernel version 168 (buildPackages.deterministic-uname.override { inherit modDirVersion; }) 169 ] 170 ++ optional (lib.versionAtLeast version "5.13") zstd 171 ++ optionals withRust [ 172 rustc 173 rust-bindgen 174 ]; 175 176 in 177 (optionalAttrs isModular { 178 outputs = [ 179 "out" 180 "dev" 181 ]; 182 }) 183 // { 184 passthru = rec { 185 inherit 186 version 187 modDirVersion 188 config 189 kernelPatches 190 configfile 191 moduleBuildDependencies 192 stdenv 193 ; 194 inherit 195 isZen 196 isHardened 197 isLibre 198 withRust 199 ; 200 isXen = lib.warn "The isXen attribute is deprecated. All Nixpkgs kernels that support it now have Xen enabled." true; 201 baseVersion = lib.head (lib.splitString "-rc" version); 202 kernelOlder = lib.versionOlder baseVersion; 203 kernelAtLeast = lib.versionAtLeast baseVersion; 204 }; 205 206 inherit src; 207 208 depsBuildBuild = [ buildPackages.stdenv.cc ]; 209 nativeBuildInputs = [ 210 bison 211 flex 212 perl 213 bc 214 openssl 215 rsync 216 gmp 217 libmpc 218 mpfr 219 elfutils 220 zstd 221 python3Minimal 222 kmod 223 hexdump 224 ] 225 ++ optional needsUbootTools ubootTools 226 ++ optionals (lib.versionAtLeast version "5.2") [ 227 cpio 228 pahole 229 zlib 230 ] 231 ++ optionals withRust [ 232 rustc 233 rust-bindgen 234 ]; 235 236 RUST_LIB_SRC = lib.optionalString withRust rustPlatform.rustLibSrc; 237 238 # avoid leaking Rust source file names into the final binary, which adds 239 # a false dependency on rust-lib-src on targets with uncompressed kernels 240 KRUSTFLAGS = lib.optionalString withRust "--remap-path-prefix ${rustPlatform.rustLibSrc}=/"; 241 242 patches = 243 map (p: p.patch) kernelPatches 244 # Required for deterministic builds along with some postPatch magic. 245 ++ optional (lib.versionOlder version "5.19") ./randstruct-provide-seed.patch 246 ++ optional (lib.versionAtLeast version "5.19") ./randstruct-provide-seed-5.19.patch 247 # Linux 5.12 marked certain PowerPC-only symbols as GPL, which breaks 248 # OpenZFS; this was fixed in Linux 5.19 so we backport the fix 249 # https://github.com/openzfs/zfs/pull/13367 250 ++ 251 optional 252 ( 253 lib.versionAtLeast version "5.12" && lib.versionOlder version "5.19" && stdenv.hostPlatform.isPower 254 ) 255 (fetchpatch { 256 url = "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/patch/?id=d9e5c3e9e75162f845880535957b7fd0b4637d23"; 257 hash = "sha256-bBOyJcP6jUvozFJU0SPTOf3cmnTQ6ZZ4PlHjiniHXLU="; 258 }); 259 260 postPatch = '' 261 # Ensure that depmod gets resolved through PATH 262 sed -i Makefile -e 's|= /sbin/depmod|= depmod|' 263 264 # Some linux-hardened patches now remove certain files in the scripts directory, so the file may not exist. 265 [[ -f scripts/ld-version.sh ]] && patchShebangs scripts/ld-version.sh 266 267 # Set randstruct seed to a deterministic but diversified value. Note: 268 # we could have instead patched gen-random-seed.sh to take input from 269 # the buildFlags, but that would require also patching the kernel's 270 # toplevel Makefile to add a variable export. This would be likely to 271 # cause future patch conflicts. 272 for file in scripts/gen-randstruct-seed.sh scripts/gcc-plugins/gen-random-seed.sh; do 273 if [ -f "$file" ]; then 274 substituteInPlace "$file" \ 275 --replace NIXOS_RANDSTRUCT_SEED \ 276 $(echo ${randstructSeed}${src} ${placeholder "configfile"} | sha256sum | cut -d ' ' -f 1 | tr -d '\n') 277 break 278 fi 279 done 280 281 patchShebangs scripts 282 283 # also patch arch-specific install scripts 284 for i in $(find arch -name install.sh); do 285 patchShebangs "$i" 286 done 287 288 # unset $src because the build system tries to use it and spams a bunch of warnings 289 # see: https://github.com/torvalds/linux/commit/b1992c3772e69a6fd0e3fc81cd4d2820c8b6eca0 290 unset src 291 ''; 292 293 configurePhase = '' 294 runHook preConfigure 295 296 mkdir build 297 export buildRoot="$(pwd)/build" 298 299 echo "manual-config configurePhase buildRoot=$buildRoot pwd=$PWD" 300 301 if [ -f "$buildRoot/.config" ]; then 302 echo "Could not link $buildRoot/.config : file exists" 303 exit 1 304 fi 305 ln -sv ${configfile} $buildRoot/.config 306 307 # reads the existing .config file and prompts the user for options in 308 # the current kernel source that are not found in the file. 309 make $makeFlags "''${makeFlagsArray[@]}" oldconfig 310 runHook postConfigure 311 312 make $makeFlags "''${makeFlagsArray[@]}" prepare 313 actualModDirVersion="$(cat $buildRoot/include/config/kernel.release)" 314 if [ "$actualModDirVersion" != "${modDirVersion}" ]; then 315 echo "Error: modDirVersion ${modDirVersion} specified in the Nix expression is wrong, it should be: $actualModDirVersion" 316 exit 1 317 fi 318 319 buildFlagsArray+=("KBUILD_BUILD_TIMESTAMP=$(date -u -d @$SOURCE_DATE_EPOCH)") 320 321 cd $buildRoot 322 ''; 323 324 buildFlags = [ 325 "KBUILD_BUILD_VERSION=1-NixOS" 326 kernelConf.target 327 "vmlinux" # for "perf" and things like that 328 ] 329 ++ optional isModular "modules" 330 ++ optionals buildDTBs [ 331 "dtbs" 332 "DTC_FLAGS=-@" 333 ] 334 ++ extraMakeFlags; 335 336 installFlags = [ 337 "INSTALL_PATH=$(out)" 338 ] 339 ++ (optional isModular "INSTALL_MOD_PATH=$(out)") 340 ++ optionals buildDTBs [ 341 "dtbs_install" 342 "INSTALL_DTBS_PATH=$(out)/dtbs" 343 ]; 344 345 preInstall = 346 let 347 # All we really need to do here is copy the final image and System.map to $out, 348 # and use the kernel's modules_install, firmware_install, dtbs_install, etc. targets 349 # for the rest. Easy, right? 350 # 351 # Unfortunately for us, the obvious way of getting the built image path, 352 # make -s image_name, does not work correctly, because some architectures 353 # (*cough* aarch64 *cough*) change KBUILD_IMAGE on the fly in their install targets, 354 # so we end up attempting to install the thing we didn't actually build. 355 # 356 # Thankfully, there's a way out that doesn't involve just hardcoding everything. 357 # 358 # The kernel has an install target, which runs a pretty simple shell script 359 # (located at scripts/install.sh or arch/$arch/boot/install.sh, depending on 360 # which kernel version you're looking at) that tries to do something sensible. 361 # 362 # (it would be great to hijack this script immediately, as it has all the 363 # information we need passed to it and we don't need it to try and be smart, 364 # but unfortunately, the exact location of the scripts differs between kernel 365 # versions, and they're seemingly not considered to be public API at all) 366 # 367 # One of the ways it tries to discover what "something sensible" actually is 368 # is by delegating to what's supposed to be a user-provided install script 369 # located at ~/bin/installkernel. 370 # 371 # (the other options are: 372 # - a distribution-specific script at /sbin/installkernel, 373 # which we can't really create in the sandbox easily 374 # - an architecture-specific script at arch/$arch/boot/install.sh, 375 # which attempts to guess _something_ and usually guesses very wrong) 376 # 377 # More specifically, the install script exec's into ~/bin/installkernel, if one 378 # exists, with the following arguments: 379 # 380 # $1: $KERNELRELEASE - full kernel version string 381 # $2: $KBUILD_IMAGE - the final image path 382 # $3: System.map - path to System.map file, seemingly hardcoded everywhere 383 # $4: $INSTALL_PATH - path to the destination directory as specified in installFlags 384 # 385 # $2 is exactly what we want, so hijack the script and use the knowledge given to it 386 # by the makefile overlords for our own nefarious ends. 387 # 388 # Note that the makefiles specifically look in ~/bin/installkernel, and 389 # writeShellScriptBin writes the script to <store path>/bin/installkernel, 390 # so HOME needs to be set to just the store path. 391 # 392 # FIXME: figure out a less roundabout way of doing this. 393 installkernel = buildPackages.writeShellScriptBin "installkernel" '' 394 cp -av $2 $4 395 cp -av $3 $4 396 ''; 397 in 398 '' 399 installFlagsArray+=("-j$NIX_BUILD_CORES") 400 export HOME=${installkernel} 401 ''; 402 403 # Some image types need special install targets (e.g. uImage is installed with make uinstall on arm) 404 installTargets = [ 405 (kernelConf.installTarget or ( 406 if kernelConf.target == "uImage" && stdenv.hostPlatform.linuxArch == "arm" then 407 "uinstall" 408 else if 409 ( 410 kernelConf.target == "zImage" 411 || kernelConf.target == "Image.gz" 412 || kernelConf.target == "vmlinuz.efi" 413 ) 414 && builtins.elem stdenv.hostPlatform.linuxArch [ 415 "arm" 416 "arm64" 417 "parisc" 418 "riscv" 419 ] 420 then 421 "zinstall" 422 else 423 "install" 424 ) 425 ) 426 ]; 427 428 # We remove a bunch of stuff that is symlinked from other places to save space, 429 # which trips the broken symlink check. So, just skip it. We'll know if it explodes. 430 dontCheckForBrokenSymlinks = true; 431 432 postInstall = optionalString isModular '' 433 mkdir -p $dev 434 cp vmlinux $dev/ 435 if [ -z "''${dontStrip-}" ]; then 436 installFlagsArray+=("INSTALL_MOD_STRIP=1") 437 fi 438 make modules_install $makeFlags "''${makeFlagsArray[@]}" \ 439 $installFlags "''${installFlagsArray[@]}" 440 unlink $out/lib/modules/${modDirVersion}/build 441 rm -f $out/lib/modules/${modDirVersion}/source 442 443 mkdir -p $dev/lib/modules/${modDirVersion}/{build,source} 444 445 # To save space, exclude a bunch of unneeded stuff when copying. 446 (cd .. && rsync --archive --prune-empty-dirs \ 447 --exclude='/build/' \ 448 * $dev/lib/modules/${modDirVersion}/source/) 449 450 cd $dev/lib/modules/${modDirVersion}/source 451 452 cp $buildRoot/{.config,Module.symvers} $dev/lib/modules/${modDirVersion}/build 453 make modules_prepare $makeFlags "''${makeFlagsArray[@]}" O=$dev/lib/modules/${modDirVersion}/build 454 455 # For reproducibility, removes accidental leftovers from a `cc1` call 456 # from a `try-run` call from the Makefile 457 rm -f $dev/lib/modules/${modDirVersion}/build/.[0-9]*.d 458 459 # Keep some extra files on some arches (powerpc, aarch64) 460 for f in arch/powerpc/lib/crtsavres.o arch/arm64/kernel/ftrace-mod.o; do 461 if [ -f "$buildRoot/$f" ]; then 462 cp $buildRoot/$f $dev/lib/modules/${modDirVersion}/build/$f 463 fi 464 done 465 466 # !!! No documentation on how much of the source tree must be kept 467 # If/when kernel builds fail due to missing files, you can add 468 # them here. Note that we may see packages requiring headers 469 # from drivers/ in the future; it adds 50M to keep all of its 470 # headers on 3.10 though. 471 472 chmod u+w -R .. 473 arch=$(cd $dev/lib/modules/${modDirVersion}/build/arch; ls) 474 475 # Remove unused arches 476 for d in $(cd arch/; ls); do 477 if [ "$d" = "$arch" ]; then continue; fi 478 if [ "$arch" = arm64 ] && [ "$d" = arm ]; then continue; fi 479 rm -rf arch/$d 480 done 481 482 # Remove all driver-specific code (50M of which is headers) 483 rm -fR drivers 484 485 # Keep all headers 486 find . -type f -name '*.h' -print0 | xargs -0 -r chmod u-w 487 488 # Keep linker scripts (they are required for out-of-tree modules on aarch64) 489 find . -type f -name '*.lds' -print0 | xargs -0 -r chmod u-w 490 491 # Keep root and arch-specific Makefiles 492 chmod u-w Makefile arch/"$arch"/Makefile* 493 494 # Keep whole scripts dir 495 chmod u-w -R scripts 496 497 # Delete everything not kept 498 find . -type f -perm -u=w -print0 | xargs -0 -r rm 499 500 # Delete empty directories 501 find -empty -type d -delete 502 ''; 503 504 requiredSystemFeatures = [ "big-parallel" ]; 505 506 meta = { 507 # https://github.com/NixOS/nixpkgs/pull/345534#issuecomment-2391238381 508 broken = withRust && lib.versionOlder version "6.12"; 509 510 description = 511 "The Linux kernel" 512 + ( 513 if kernelPatches == [ ] then 514 "" 515 else 516 " (with patches: " + lib.concatStringsSep ", " (map (x: x.name) kernelPatches) + ")" 517 ); 518 license = lib.licenses.gpl2Only; 519 homepage = "https://www.kernel.org/"; 520 maintainers = [ maintainers.thoughtpolice ]; 521 teams = [ teams.linux-kernel ]; 522 platforms = platforms.linux; 523 badPlatforms = 524 lib.optionals (lib.versionOlder version "4.15") [ 525 "riscv32-linux" 526 "riscv64-linux" 527 ] 528 ++ lib.optional (lib.versionOlder version "5.19") "loongarch64-linux"; 529 timeout = 14400; # 4 hours 530 } 531 // extraMeta; 532 }; 533 534 # Absolute paths for compilers avoid any PATH-clobbering issues. 535 commonMakeFlags = [ 536 "ARCH=${stdenv.hostPlatform.linuxArch}" 537 "CROSS_COMPILE=${stdenv.cc.targetPrefix}" 538 ] 539 ++ lib.optionals (stdenv.isx86_64 && stdenv.cc.bintools.isLLVM) [ 540 # The wrapper for ld.lld breaks linking the kernel. We use the 541 # unwrapped linker as workaround. See: 542 # 543 # https://github.com/NixOS/nixpkgs/issues/321667 544 "LD=${stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}ld" 545 ] 546 ++ (stdenv.hostPlatform.linux-kernel.makeFlags or [ ]) 547 ++ extraMakeFlags; 548 in 549 550 stdenv.mkDerivation ( 551 builtins.foldl' lib.recursiveUpdate { } [ 552 (drvAttrs config stdenv.hostPlatform.linux-kernel kernelPatches configfile) 553 { 554 inherit pname version; 555 556 enableParallelBuilding = true; 557 558 hardeningDisable = [ 559 "bindnow" 560 "format" 561 "fortify" 562 "stackprotector" 563 "pic" 564 "pie" 565 ]; 566 567 makeFlags = [ 568 "O=$(buildRoot)" 569 ] 570 ++ commonMakeFlags; 571 572 passthru = { inherit commonMakeFlags; }; 573 574 karch = stdenv.hostPlatform.linuxArch; 575 } 576 (optionalAttrs (pos != null) { inherit pos; }) 577 ] 578 ) 579)