nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix
Shea Levy 008992619f linux/manual-config: Cross-compiling support
With this, I was able to successfully compile a defconfig kernel for the
sheevaplug, though I didn't actually try to run it (not having a
sheevaplug myself).

For native compiles, the most significant difference is that the
platform's kernel target is built directly rather than hoping the
default make target will pull it in.

Also some stylistic improvements along the way.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-12-31 22:38:06 -05:00

193 lines
5.6 KiB
Nix

{ stdenv, runCommand, nettools, bc, perl, kmod, writeTextFile, ubootChooser }:
let
inherit (stdenv.lib)
hasAttr getAttr optionalAttrs optional optionalString maintainers platforms;
# Function to parse the config file into a nix expression
readConfig = configFile:
let
configAttrs = 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
''}";
config = configAttrs // rec {
attrName = attr: "CONFIG_" + attr;
isSet = attr: hasAttr (attrName attr) config;
getValue = attr: if isSet attr then getAttr (attrName attr) config else null;
isYes = attr: (isSet attr) && ((getValue attr) == "y");
isNo = attr: (isSet attr) && ((getValue attr) == "n");
isModule = attr: (isSet attr) && ((getValue attr) == "m");
isEnabled = attr: (isModule attr) || (isYes attr);
isDisabled = attr: (!(isSet attr)) || (isNo attr);
};
in
config;
in
{
# The kernel version
version,
# The version of the kernel module directory
modDirVersion ? version,
# The kernel source (tarball, git checkout, etc.)
src,
# Any patches
kernelPatches ? [],
# The kernel .config file
configfile,
# Manually specified nixexpr representing the config
# If unspecified, this will be autodetected from the .config
config ? optionalAttrs allowImportFromDerivation (readConfig configfile),
# Whether to utilize the controversial import-from-derivation feature to parse the config
allowImportFromDerivation ? false
}:
let
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-${version}-source";
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|'
'';
installPhase = ''
cd ..
mv $sourceRoot $out
'';
};
in
stdenv.mkDerivation {
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);
makeFlags = commonMakeFlags ++ [
"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;
};
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;
meta = {
description = "The Linux kernel";
license = "GPLv2";
homepage = http://www.kernel.org/;
maintainers = [
maintainers.shlevy
];
platforms = platforms.linux;
};
}