From df82dd000a705d937ba98650e68a2d7fdc2088f7 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Mon, 25 Mar 2013 05:37:42 -0400 Subject: [PATCH] manual-config: Fully general cross-compiling In the most general case, the cross and native kernel may differ in patches and configuration file as well as architecture, kernel target, etc. It's probably overkill to support that case, but since it was doable without much duplication and it will make integrating with the existing cross-compilation support in the generic kernel I decided to implement it anyway. Signed-off-by: Shea Levy --- .../linux/kernel/manual-config.nix | 275 +++++++++--------- 1 file changed, 144 insertions(+), 131 deletions(-) diff --git a/pkgs/os-specific/linux/kernel/manual-config.nix b/pkgs/os-specific/linux/kernel/manual-config.nix index 3f4e333e7bd625..f60889adab6fef 100644 --- a/pkgs/os-specific/linux/kernel/manual-config.nix +++ b/pkgs/os-specific/linux/kernel/manual-config.nix @@ -1,6 +1,16 @@ { stdenv, runCommand, nettools, bc, perl, kmod, writeTextFile, ubootChooser }: -{ +let + parseConfig = configfile: import (runCommand "config.nix" {} '' + echo "{" > "$out" + while IFS='=' read key val; do + [ "x''${key#CONFIG_}" != "x$key" ] || continue + no_firstquote="''${val#\"}"; + echo ' "'"$key"'" = "'"''${no_firstquote%\"}"'";' >> "$out" + done < "${configfile}" + echo "}" >> $out + '').outPath; +in { # The kernel version version, # The version of the kernel module directory @@ -9,117 +19,153 @@ src, # Any patches kernelPatches ? [], - # The kernel .config file + # Patches for native compiling only + nativeKernelPatches ? [], + # Patches for cross compiling only + crossKernelPatches ? [], + # The native kernel .config file configfile, + # The cross kernel .config file + crossConfigfile ? configfile, # Manually specified nixexpr representing the config # If unspecified, this will be autodetected from the .config - config ? stdenv.lib.optionalAttrs allowImportFromDerivation import (runCommand "config.nix" {} '' - echo "{" > "$out" - while IFS='=' read key val; do - [ "x''${key#CONFIG_}" != "x$key" ] || continue - no_firstquote="''${val#\"}"; - echo ' "'"$key"'" = "'"''${no_firstquote%\"}"'";' >> "$out" - done < "${configfile}" - echo "}" >> $out - '').outPath, + config ? stdenv.lib.optionalAttrs allowImportFromDerivation (parseConfig configfile), + # Cross-compiling config + crossConfig ? if allowImportFromDerivation then parseConfig crossConfigfile else config, # Whether to utilize the controversial import-from-derivation feature to parse the config allowImportFromDerivation ? false }: -let config_ = config; in - let inherit (stdenv.lib) optional optionalString getAttr hasAttr; - config = let attrName = attr: "CONFIG_" + attr; in { - isSet = attr: hasAttr (attrName attr) config; - - getValue = attr: if config.isSet attr then getAttr (attrName attr) config else null; - - isYes = attr: (config.getValue attr) == "y"; - - isNo = attr: (config.getValue attr) == "n"; - - isModule = attr: (config.getValue attr) == "m"; - - isEnabled = attr: (config.isModule attr) || (config.isYes attr); - - isDisabled = attr: (!(config.isSet attr)) || (config.isNo attr); - } // config_; - installkernel = writeTextFile { name = "installkernel"; executable=true; text = '' #!${stdenv.shell} -e mkdir -p $4 cp -av $2 $4 cp -av $3 $4 - '';}; - - isModular = config.isYes "MODULES"; - - installsFirmware = (config.isEnabled "FW_LOADER") && - (isModular || (config.isDisabled "FIRMWARE_IN_KERNEL")); + ''; }; commonMakeFlags = [ "O=$(buildRoot)" ]; - # Some image types need special install targets (e.g. uImage is installed with make uinstall) - installTarget = target: [ (if target == "uImage" then "uinstall" else "install") ]; - - sourceRoot = stdenv.mkDerivation { - name = "linux-source-${version}"; - - inherit src; - - patches = map (p: p.patch) kernelPatches; - - phases = [ "unpackPhase" "patchPhase" "installPhase" ]; + drvAttrs = config: platform: kernelPatches: configfile: + let config_ = config; in + let + config = let attrName = attr: "CONFIG_" + attr; in { + isSet = attr: hasAttr (attrName attr) config; - prePatch = '' - for mf in $(find -name Makefile -o -name Makefile.include -o -name install.sh); do - echo "stripping FHS paths in \`$mf'..." - sed -i "$mf" -e 's|/usr/bin/||g ; s|/bin/||g ; s|/sbin/||g' - done - sed -i Makefile -e 's|= depmod|= ${kmod}/sbin/depmod|' - # Patch kconfig to print "###" after every question so that - # generate-config.pl from the generic builder can answer them. - # This only affects oldaskconfig. - sed -e '/fflush(stdout);/i\printf("###");' -i scripts/kconfig/conf.c - ''; - - installPhase = '' - cd .. - mv $sourceRoot $out - ''; - }; + getValue = attr: if config.isSet attr then getAttr (attrName attr) config else null; + + isYes = attr: (config.getValue attr) == "y"; + + isNo = attr: (config.getValue attr) == "n"; + + isModule = attr: (config.getValue attr) == "m"; + + isEnabled = attr: (config.isModule attr) || (config.isYes attr); + + isDisabled = attr: (!(config.isSet attr)) || (config.isNo attr); + } // config_; + + isModular = config.isYes "MODULES"; + + installsFirmware = (config.isEnabled "FW_LOADER") && + (isModular || (config.isDisabled "FIRMWARE_IN_KERNEL")); + + sourceRoot = stdenv.mkDerivation { + name = "linux-source-${version}"; + + inherit src; + + patches = map (p: p.patch) kernelPatches; + + phases = [ "unpackPhase" "patchPhase" "installPhase" ]; + + prePatch = '' + for mf in $(find -name Makefile -o -name Makefile.include -o -name install.sh); do + echo "stripping FHS paths in \`$mf'..." + sed -i "$mf" -e 's|/usr/bin/||g ; s|/bin/||g ; s|/sbin/||g' + done + + sed -i Makefile -e 's|= depmod|= ${kmod}/sbin/depmod|' + + # Patch kconfig to print "###" after every question so that + # generate-config.pl from the generic builder can answer them. + # This only affects oldaskconfig. + sed -e '/fflush(stdout);/i\printf("###");' -i scripts/kconfig/conf.c + ''; + + installPhase = '' + cd .. + mv $sourceRoot $out + ''; + }; + in { + outputs = if isModular then [ "out" "dev" ] else null; + + passthru = { + inherit version modDirVersion config kernelPatches src; + }; + + inherit sourceRoot; + + unpackPhase = '' + mkdir build + export buildRoot="$(pwd)/build" + cd ${sourceRoot} + ''; + + configurePhase = '' + runHook preConfigure + ln -sv ${configfile} $buildRoot/.config + make $makeFlags "''${makeFlagsArray[@]}" oldconfig + runHook postConfigure + ''; + + buildFlags = [ platform.kernelTarget ] ++ optional isModular "modules"; + + installFlags = [ + "INSTALLKERNEL=${installkernel}" + "INSTALL_PATH=$(out)" + ] ++ (optional isModular "INSTALL_MOD_PATH=$(out)") + ++ optional installsFirmware "INSTALL_FW_PATH=$(out)/lib/firmware"; + + # Some image types need special install targets (e.g. uImage is installed with make uinstall) + installTargets = [ (if platform.kernelTarget == "uImage" then "uinstall" else "install") ]; + + postInstall = optionalString installsFirmware '' + mkdir -p $out/lib/firmware + '' + (if isModular then '' + make modules_install $makeFlags "''${makeFlagsArray[@]}" \ + $installFlags "''${installFlagsArray[@]}" + unlink $out/lib/modules/${modDirVersion}/build + mkdir -p $dev/lib/modules/${modDirVersion} + mv $out/lib/modules/${modDirVersion}/source $dev/lib/modules/${modDirVersion}/source + mv $buildRoot $dev/lib/modules/${modDirVersion}/build + '' else optionalString installsFirmware '' + make firmware_install $makeFlags "''${makeFlagsArray[@]}" \ + $installFlags "''${installFlagsArray[@]}" + ''); + + postFixup = if isModular then '' + if [ -z "$dontStrip" ]; then + find $out -name "*.ko" -print0 | xargs -0 -r ''${crossConfig+$crossConfig-}strip -S + # Remove all references to the source directory to avoid unneeded + # runtime dependencies + find $out -name "*.ko" -print0 | xargs -0 -r sed -i \ + "s|${sourceRoot}|$NIX_STORE/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${sourceRoot.name}|g" + fi + '' else null; + }; in -stdenv.mkDerivation { +stdenv.mkDerivation ((drvAttrs config stdenv.platform (kernelPatches ++ nativeKernelPatches) configfile) // { name = "linux-${version}"; enableParallelBuilding = true; - outputs = if isModular then [ "out" "dev" ] else null; - - passthru = { - inherit version modDirVersion config kernelPatches src; - }; - - inherit sourceRoot; - - unpackPhase = '' - mkdir build - export buildRoot="$(pwd)/build" - cd ${sourceRoot} - ''; - - configurePhase = '' - runHook preConfigure - ln -sv ${configfile} $buildRoot/.config - make $makeFlags "''${makeFlagsArray[@]}" oldconfig - runHook postConfigure - ''; - nativeBuildInputs = [ perl bc nettools ] ++ optional (stdenv.platform.uboot != null) (ubootChooser stdenv.platform.uboot); @@ -127,52 +173,19 @@ stdenv.mkDerivation { "ARCH=${stdenv.platform.kernelArch}" ]; - buildFlags = [ stdenv.platform.kernelTarget ] ++ optional isModular "modules"; - - installFlags = [ - "INSTALLKERNEL=${installkernel}" - "INSTALL_PATH=$(out)" - ] ++ (optional isModular "INSTALL_MOD_PATH=$(out)") - ++ optional installsFirmware "INSTALL_FW_PATH=$(out)/lib/firmware"; - - installTargets = installTarget stdenv.platform.kernelTarget; - - crossAttrs = let cp = stdenv.cross.platform; in { - buildFlags = [ cp.kernelTarget ] ++ optional isModular "modules"; - - makeFlags = commonMakeFlags ++ [ - "ARCH=${cp.kernelArch}" - "CROSS_COMPILE=$(crossConfig)-" - ]; - - installTargets = installTarget cp.kernelTarget; - - buildInputs = optional (cp.uboot != null) (ubootChooser cp.uboot).crossDrv; - }; + crossAttrs = let cp = stdenv.cross.platform; in + (drvAttrs crossConfig cp (kernelPatches ++ crossKernelPatches) crossConfigfile) // { + makeFlags = commonMakeFlags ++ [ + "ARCH=${cp.kernelArch}" + "CROSS_COMPILE=$(crossConfig)-" + ]; - postInstall = optionalString installsFirmware '' - mkdir -p $out/lib/firmware - '' + (if isModular then '' - make modules_install $makeFlags "''${makeFlagsArray[@]}" \ - $installFlags "''${installFlagsArray[@]}" - unlink $out/lib/modules/${modDirVersion}/build - mkdir -p $dev/lib/modules/${modDirVersion} - mv $out/lib/modules/${modDirVersion}/source $dev/lib/modules/${modDirVersion}/source - mv $buildRoot $dev/lib/modules/${modDirVersion}/build - '' else optionalString installsFirmware '' - make firmware_install $makeFlags "''${makeFlagsArray[@]}" \ - $installFlags "''${installFlagsArray[@]}" - ''); - - postFixup = if isModular then '' - if [ -z "$dontStrip" ]; then - find $out -name "*.ko" -print0 | xargs -0 -r ''${crossConfig+$crossConfig-}strip -S - # Remove all references to the source directory to avoid unneeded - # runtime dependencies - find $out -name "*.ko" -print0 | xargs -0 -r sed -i \ - "s|${sourceRoot}|$NIX_STORE/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${sourceRoot.name}|g" - fi - '' else null; + # !!! uboot has messed up cross-compiling, nativeDrv builds arm tools on x86, + # crossDrv builds x86 tools on x86 (but arm uboot). If this is fixed, uboot + # can just go into buildInputs (but not nativeBuildInputs since cp.uboot + # may be different from stdenv.platform.uboot) + buildInputs = optional (cp.uboot != null) (ubootChooser cp.uboot).crossDrv; + }; meta = { description = "The Linux kernel"; @@ -183,4 +196,4 @@ stdenv.mkDerivation { ]; platforms = stdenv.lib.platforms.linux; }; -} +})