2014-01-01 04:38:06 +01:00
|
|
|
{ stdenv, runCommand, nettools, bc, perl, kmod, writeTextFile, ubootChooser }:
|
2012-07-29 07:23:51 +02:00
|
|
|
|
|
|
|
let
|
2014-01-01 04:46:43 +01:00
|
|
|
readConfig = 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 {
|
2012-07-29 10:31:40 +02:00
|
|
|
# The kernel version
|
|
|
|
version,
|
|
|
|
# The version of the kernel module directory
|
|
|
|
modDirVersion ? version,
|
|
|
|
# The kernel source (tarball, git checkout, etc.)
|
|
|
|
src,
|
|
|
|
# Any patches
|
2012-08-02 05:02:17 +02:00
|
|
|
kernelPatches ? [],
|
2014-01-01 05:09:42 +01:00
|
|
|
# Patches for native compiling only
|
|
|
|
nativeKernelPatches ? [],
|
|
|
|
# Patches for cross compiling only
|
|
|
|
crossKernelPatches ? [],
|
|
|
|
# The native kernel .config file
|
2012-08-01 12:18:03 +02:00
|
|
|
configfile,
|
2014-01-01 05:09:42 +01:00
|
|
|
# The cross kernel .config file
|
|
|
|
crossConfigfile ? configfile,
|
2012-08-01 12:18:03 +02:00
|
|
|
# Manually specified nixexpr representing the config
|
2012-07-29 10:52:34 +02:00
|
|
|
# If unspecified, this will be autodetected from the .config
|
2014-01-01 04:46:43 +01:00
|
|
|
config ? stdenv.lib.optionalAttrs allowImportFromDerivation (readConfig configfile),
|
2014-01-01 05:09:42 +01:00
|
|
|
# Cross-compiling config
|
|
|
|
crossConfig ? if allowImportFromDerivation then (readConfig crossConfigfile) else config,
|
2012-07-29 19:26:39 +02:00
|
|
|
# Whether to utilize the controversial import-from-derivation feature to parse the config
|
|
|
|
allowImportFromDerivation ? false
|
2012-07-29 10:31:40 +02:00
|
|
|
}:
|
|
|
|
|
2012-07-29 10:48:50 +02:00
|
|
|
let
|
2014-01-01 04:46:43 +01:00
|
|
|
inherit (stdenv.lib)
|
2014-01-01 05:09:42 +01:00
|
|
|
hasAttr getAttr optional optionalString maintainers platforms;
|
2014-01-01 04:46:43 +01:00
|
|
|
|
2014-01-01 04:38:06 +01:00
|
|
|
installkernel = writeTextFile { name = "installkernel"; executable=true; text = ''
|
|
|
|
#!${stdenv.shell} -e
|
|
|
|
mkdir -p $4
|
|
|
|
cp -av $2 $4
|
2012-08-07 12:36:50 +02:00
|
|
|
cp -av $3 $4
|
2014-01-01 05:09:42 +01:00
|
|
|
''; };
|
2012-08-01 20:15:26 +02:00
|
|
|
|
|
|
|
commonMakeFlags = [
|
2014-01-02 05:56:24 +01:00
|
|
|
"O=$(buildRoot)"
|
2014-01-01 04:38:06 +01:00
|
|
|
];
|
|
|
|
|
2014-01-01 05:09:42 +01:00
|
|
|
drvAttrs = config_: platform: kernelPatches: configfile:
|
|
|
|
let
|
|
|
|
config = let attrName = attr: "CONFIG_" + attr; in {
|
|
|
|
isSet = attr: hasAttr (attrName attr) config;
|
2012-08-12 03:21:06 +02:00
|
|
|
|
2014-01-01 05:09:42 +01:00
|
|
|
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"));
|
|
|
|
in {
|
|
|
|
outputs = if isModular then [ "out" "dev" ] else null;
|
|
|
|
|
|
|
|
passthru = {
|
2014-01-02 05:56:24 +01:00
|
|
|
inherit version modDirVersion config kernelPatches;
|
2014-01-01 05:09:42 +01:00
|
|
|
};
|
|
|
|
|
2014-01-02 05:56:24 +01:00
|
|
|
inherit src;
|
2014-01-01 05:09:42 +01:00
|
|
|
|
2014-01-02 05:56:24 +01:00
|
|
|
preUnpack = ''
|
2014-01-01 05:09:42 +01:00
|
|
|
mkdir build
|
|
|
|
export buildRoot="$(pwd)/build"
|
2014-01-02 05:56:24 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
patches = map (p: p.patch) kernelPatches;
|
|
|
|
|
|
|
|
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
|
2014-01-05 16:31:16 +01:00
|
|
|
sed -i Makefile -e 's|= depmod|= ${kmod}/sbin/depmod|'
|
2014-01-01 05:09:42 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
configurePhase = ''
|
|
|
|
runHook preConfigure
|
|
|
|
ln -sv ${configfile} $buildRoot/.config
|
|
|
|
make $makeFlags "''${makeFlagsArray[@]}" oldconfig
|
|
|
|
runHook postConfigure
|
|
|
|
'';
|
|
|
|
|
2014-01-02 05:56:24 +01:00
|
|
|
buildFlags = [ "KBUILD_BUILD_VERSION=1-NixOS" platform.kernelTarget ] ++ optional isModular "modules";
|
2014-01-01 05:09:42 +01:00
|
|
|
|
|
|
|
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
|
2014-01-02 05:56:24 +01:00
|
|
|
unlink $out/lib/modules/${modDirVersion}/source
|
|
|
|
|
2014-01-01 05:09:42 +01:00
|
|
|
mkdir -p $dev/lib/modules/${modDirVersion}
|
2014-01-02 05:56:24 +01:00
|
|
|
cd ..
|
|
|
|
mv $sourceRoot $dev/lib/modules/${modDirVersion}/source
|
|
|
|
cd $dev/lib/modules/${modDirVersion}/source
|
|
|
|
|
|
|
|
mv $buildRoot/.config $buildRoot/Module.symvers $TMPDIR
|
|
|
|
rm -fR $buildRoot
|
|
|
|
mkdir $buildRoot
|
|
|
|
mv $TMPDIR/.config $TMPDIR/Module.symvers $buildRoot
|
|
|
|
make modules_prepare $makeFlags "''${makeFlagsArray[@]}"
|
2014-01-01 05:09:42 +01:00
|
|
|
mv $buildRoot $dev/lib/modules/${modDirVersion}/build
|
2014-01-02 05:56:24 +01:00
|
|
|
|
|
|
|
# !!! No documentation on how much of the source tree must be kept
|
Greatly reduce kernel closure size
Based on access analysis with strace, I determined an essentially
minimal required set of files from the kernel source that was needed to
build all current kernel packages on 3.10, which ultimately resulted in
keeping 30M of source. Generalizing from that minimal set, which
required ad-hoc specifications of which headers outside of include/ and
arch/*/include and which files in the scripts/ directory should be kept,
to a policy of keeping all non-arch-specific headers that aren't part of
the drivers/ directory and the entire scripts/ directory added an
additional 17M, but there was nothing in the analysis that indicated
that that ad-hoc specification was at all complete so I think the extra
hit is worth the likely greater compatibility.
For reference, we now keep:
* All headers that are NOT in arch/${notTargetArch}/include or drivers/
* The scripts/ directory
* Makefile
* arch/${targetArch}/Makefile
IMO the most likely cause of future problems are the headers in
drivers/, but hopefully they won't actually be needed as they add 50M
Ideally kernel packages would only use include and
arch/${targetArch}/include, but alas this is observably not the case.
master:
* $out
* size: 234M
* references-closure: linux-headers, glibc, attr, acl, zlib, gcc,
coreutils, perl, bash
merge-kernel-builds:
* $out
* size: 152M
* references-closure: none
* $dev
* size: 57M
* references-closure: linux-headers, glibc, zlib, gcc
So even with the non-minimal set we still beat out master. Keeping the
drivers headers would make us only slightly bigger.
Signed-off-by: Shea Levy <shea@shealevy.com>
2014-01-05 12:55:47 +01:00
|
|
|
# If/when kernel builds fail due to missing files, you can add
|
|
|
|
# them here. Note that we may see packages requiring headers
|
|
|
|
# from drivers/ in the future; it adds 50M to keep all of its
|
|
|
|
# headers on 3.10 though.
|
|
|
|
|
|
|
|
chmod +w -R ../source
|
|
|
|
arch=`cd $dev/lib/modules/${modDirVersion}/build/arch; ls`
|
|
|
|
|
|
|
|
# Remove unusued arches
|
|
|
|
mv arch/$arch .
|
|
|
|
rm -fR arch
|
|
|
|
mkdir arch
|
|
|
|
mv $arch arch
|
|
|
|
|
|
|
|
# Remove all driver-specific code (50M of which is headers)
|
|
|
|
rm -fR drivers
|
|
|
|
|
|
|
|
# Keep all headers
|
|
|
|
find . -type f -name '*.h' -print0 | xargs -0 chmod -w
|
|
|
|
|
|
|
|
# Keep root and arch-specific Makefiles
|
|
|
|
chmod -w Makefile
|
|
|
|
chmod -w arch/$arch/Makefile
|
|
|
|
|
|
|
|
# Keep whole scripts dir
|
|
|
|
chmod -w -R scripts
|
|
|
|
|
|
|
|
# Delete everything not kept
|
|
|
|
find . -type f -perm -u=w -print0 | xargs -0 rm
|
|
|
|
|
|
|
|
# Delete empty directories
|
2014-01-05 02:57:21 +01:00
|
|
|
find -empty -type d -delete
|
2014-01-05 16:31:16 +01:00
|
|
|
|
|
|
|
# Remove reference to kmod
|
|
|
|
sed -i Makefile -e 's|= ${kmod}/sbin/depmod|= depmod|'
|
2014-01-01 05:09:42 +01:00
|
|
|
'' else optionalString installsFirmware ''
|
|
|
|
make firmware_install $makeFlags "''${makeFlagsArray[@]}" \
|
|
|
|
$installFlags "''${installFlagsArray[@]}"
|
|
|
|
'');
|
|
|
|
|
Greatly reduce kernel closure size
Based on access analysis with strace, I determined an essentially
minimal required set of files from the kernel source that was needed to
build all current kernel packages on 3.10, which ultimately resulted in
keeping 30M of source. Generalizing from that minimal set, which
required ad-hoc specifications of which headers outside of include/ and
arch/*/include and which files in the scripts/ directory should be kept,
to a policy of keeping all non-arch-specific headers that aren't part of
the drivers/ directory and the entire scripts/ directory added an
additional 17M, but there was nothing in the analysis that indicated
that that ad-hoc specification was at all complete so I think the extra
hit is worth the likely greater compatibility.
For reference, we now keep:
* All headers that are NOT in arch/${notTargetArch}/include or drivers/
* The scripts/ directory
* Makefile
* arch/${targetArch}/Makefile
IMO the most likely cause of future problems are the headers in
drivers/, but hopefully they won't actually be needed as they add 50M
Ideally kernel packages would only use include and
arch/${targetArch}/include, but alas this is observably not the case.
master:
* $out
* size: 234M
* references-closure: linux-headers, glibc, attr, acl, zlib, gcc,
coreutils, perl, bash
merge-kernel-builds:
* $out
* size: 152M
* references-closure: none
* $dev
* size: 57M
* references-closure: linux-headers, glibc, zlib, gcc
So even with the non-minimal set we still beat out master. Keeping the
drivers headers would make us only slightly bigger.
Signed-off-by: Shea Levy <shea@shealevy.com>
2014-01-05 12:55:47 +01:00
|
|
|
# !!! This leaves references to gcc in $dev
|
2014-01-02 05:56:24 +01:00
|
|
|
# that we might be able to avoid
|
2014-01-01 05:09:42 +01:00
|
|
|
postFixup = if isModular then ''
|
|
|
|
if [ -z "$dontStrip" ]; then
|
|
|
|
find $out -name "*.ko" -print0 | xargs -0 -r ''${crossConfig+$crossConfig-}strip -S
|
|
|
|
fi
|
2014-01-02 05:56:24 +01:00
|
|
|
# !!! Should this be part of stdenv? Also patchELF should take an argument...
|
|
|
|
prefix=$dev
|
|
|
|
patchELF
|
|
|
|
prefix=$out
|
2014-01-01 05:09:42 +01:00
|
|
|
'' else null;
|
2014-01-01 15:21:25 +01:00
|
|
|
|
|
|
|
meta = {
|
|
|
|
description =
|
|
|
|
"The Linux kernel" +
|
|
|
|
(if kernelPatches == [] then "" else
|
|
|
|
" (with patches: "
|
|
|
|
+ stdenv.lib.concatStrings (stdenv.lib.intersperse ", " (map (x: x.name) kernelPatches))
|
|
|
|
+ ")");
|
|
|
|
license = "GPLv2";
|
|
|
|
homepage = http://www.kernel.org/;
|
|
|
|
maintainers = [
|
|
|
|
maintainers.shlevy
|
|
|
|
];
|
|
|
|
platforms = platforms.linux;
|
|
|
|
};
|
2014-01-01 05:09:42 +01:00
|
|
|
};
|
2013-03-02 15:53:56 +01:00
|
|
|
in
|
|
|
|
|
2014-01-01 05:09:42 +01:00
|
|
|
stdenv.mkDerivation ((drvAttrs config stdenv.platform (kernelPatches ++ nativeKernelPatches) configfile) // {
|
2013-03-02 15:53:56 +01:00
|
|
|
name = "linux-${version}";
|
|
|
|
|
|
|
|
enableParallelBuilding = true;
|
|
|
|
|
2014-01-01 04:38:06 +01:00
|
|
|
nativeBuildInputs = [ perl bc nettools ] ++ optional (stdenv.platform.uboot != null)
|
|
|
|
(ubootChooser stdenv.platform.uboot);
|
2012-07-29 10:59:38 +02:00
|
|
|
|
2012-08-01 20:15:26 +02:00
|
|
|
makeFlags = commonMakeFlags ++ [
|
2014-01-01 04:38:06 +01:00
|
|
|
"ARCH=${stdenv.platform.kernelArch}"
|
2012-08-01 20:15:26 +02:00
|
|
|
];
|
|
|
|
|
2014-01-01 15:21:25 +01:00
|
|
|
crossAttrs = let cp = stdenv.cross.platform; in
|
2014-01-01 05:09:42 +01:00
|
|
|
(drvAttrs crossConfig cp (kernelPatches ++ crossKernelPatches) crossConfigfile) // {
|
|
|
|
makeFlags = commonMakeFlags ++ [
|
|
|
|
"ARCH=${cp.kernelArch}"
|
|
|
|
"CROSS_COMPILE=$(crossConfig)-"
|
|
|
|
];
|
|
|
|
|
|
|
|
# !!! 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;
|
2012-08-01 20:15:26 +02:00
|
|
|
};
|
2014-01-01 05:09:42 +01:00
|
|
|
})
|