Linux kernel compilation jots

This post was written by eli on October 1, 2015
Posted Under: Linux,Linux kernel

Just a few notes to self as I compiled a kernel on a x86_64 machine, targeting an i386. Kind-of cross-compilation, but with no need for a cross compiler.

Remember to update the (extra) version number in the Makefile.

Also remember that there’s always

$ make help

and it’s very useful.

After copying a known config file to .config:

$ make ARCH=i386 oldconfig
$ time make ARCH=i386 -j 8 bzImage modules && echo Success

And as root (hey, the ARCH parameter wasn’t required!):

# make modules_install INSTALL_MOD_PATH=/path/to/

(this installs into /path/to/lib/modules/{version number}, so don’t write the “/lib/modules” part)

Remember to update the symbolic links to the source directory if necessary.

Note that it’s possible to set the kernel version directly from the make command, overriding the one given in the Makefile. For example, to match the currently running version:

$ make KERNELVERSION=`uname -r` ARCH=i386 -j 8 bzImage modules && echo Success 

Be sure to check in include/generated/utsrelease.h, possibly while the kernel is compiling, that you got it right. In particular, there may be a “+” sign added.

A depmod was required on the running machine as follows (after booting with the kernel, without modules loaded), even though a depmod ran on modules_install:

# depmod -a

Now, to retain the sources only, for the sake of allowing module compilation (this is a lot more than necessary, but I’ll waste a few GBs and save myself the bother of dieting the kernel tree):

$ make clean

Copy the source tree to the target, and on the target itself, go

$ make prepare scripts

(it won’t work if it’s done on the computer that compiled the kernel)

When hacking on the kernel sources, it can be useful to go something like

$ make ARCH=i386 SUBDIRS=drivers/pci/pcie/

in order to compile just a certain subdirectory (like “I didn’t do anything stupid, did I?”).

So nope. SUBDIRS is deprecated. Use the “M=” alternative for modules, even though SUBDIRS catches the built-in objects as well (in case they were played with too).

And it’s also possible to add the known targets, such as

$ make ARCH=i386 SUBDIRS=drivers/pci/pcie/ clean

for cleaning up before compiling etc.

Creating an initramfs file (when necessary)

For a non-running kernel, something like (needs to run as root, or it fails)

# update-initramfs -v -c -k 4.14.0-test -b .
update-initramfs: Generating ./initrd.img-4.14.0-test

(-v for verbose, not really necessary)

In theory, this should have worked as well, but it doesn’t enable the prompt for encrypted root filesystem, which is why I need the initramfs to begin with.

$ mkinitramfs -o initrd.img-4.14.0-test 4.14.0-test

Anyway, update-initramfs got me an 285 MB file, which doesn’t fit into the boot/ directory. The one that came with the distro was 28 MB.

On the other hand, if I do the same thing with the currently running kernel, the output gets small and neat. So maybe because the new kernel is much newer, and maybe because initramfs always copies a lot of modules, and not just in use, when it’s not from the running kernel.

It didn’t help bluffing mkinitramfs by renaming the directories in /lib/modules/ and run mkinitramfs as if it was on the current kernel. Exactly the same file size resulted.

So I opened the initramfs image manually (copying from myself), from within an empty directory with

$ zcat ../initrd.img-4.14.0-test | cpio -i -d -H newc --no-absolute-filenames

and looked for the large files. The directories lib/modules/4.14.0-test/kernel/drivers/{gpu,net,scsi} took ~620 MB together. So removing these three, navigating to the root of the initram filesystem and compressing it back again:

$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../smaller-initramfs.img

which shrunk the image to 94 MB. Which is small enough. The missing modules will load as the real root filesystem is mounted, so modules that aren’t necessary for boot can be deleted this way.

Trying to obtain a smaller initramfs image with

# update-initramfs -u -b .

when the new kernel is running brought me back a 285 MB image. It’s probably a matter of the new kernel’s size. It might be necessary to write a script that removes any module not loaded when the kernel is up from initramfs’ /lib/modules. But it’s not worth the effort at the moment.

 

Add a Comment

required, use real name
required, will not be published
optional, your blog address

Next Post: