Building the Linux Kernel

Building the kernel yourself lets you enable experimental features, apply custom patches (like PREEMPT_RT), shrink the kernel for embedded systems, or simply understand how it all fits together. The process takes about 30 minutes on modern hardware.

Getting the Source

# Official source: kernel.org # Download latest stable tarball: wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.tar.xz wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.tar.sign # Verify GPG signature (optional but good practice): xz -d linux-6.12.tar.xz gpg --verify linux-6.12.tar.sign linux-6.12.tar # Extract: tar xf linux-6.12.tar cd linux-6.12 # Or clone with git (full history, ~4GB): git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git cd linux # Stable branch (production-ready point releases): git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git git checkout linux-6.12.y

Build Dependencies

# Ubuntu/Debian: apt install build-essential libncurses-dev bison flex libssl-dev \ libelf-dev dwarves bc make gcc pkg-config # Fedora/RHEL: dnf install gcc make ncurses-devel bison flex openssl-devel \ elfutils-libelf-devel dwarves bc # Verify gcc works: gcc --version make --version # Optional: ccache speeds up repeated builds apt install ccache export CC="ccache gcc"

Building the Kernel

# Build everything (kernel + all modules): # -j$(nproc) uses all CPU cores in parallel make -j$(nproc) # Build output: # arch/x86/boot/bzImage ← compressed kernel image # *.ko files throughout ← kernel modules # Build time estimates (on modern 8-core machine): # make localmodconfig build: ~5-10 minutes # make olddefconfig build: ~20-40 minutes # Full allmodconfig build: ~2+ hours # Watch build with verbosity (debug build failures): make -j$(nproc) V=1 2>&1 | tee build.log # Build just a specific module (fast): make -j$(nproc) drivers/net/ethernet/intel/e1000/e1000.ko # Cross-compile for ARM64 (e.g., building for Raspberry Pi on x86): apt install gcc-aarch64-linux-gnu export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc)

Installing the Kernel

# Install kernel modules to /lib/modules/VERSION/: sudo make modules_install # Install kernel image + update initramfs + update GRUB: sudo make install # This runs installkernel script which: # 1. Copies bzImage to /boot/vmlinuz-VERSION # 2. Copies System.map to /boot/System.map-VERSION # 3. Copies .config to /boot/config-VERSION # 4. Generates initrd/initramfs: update-initramfs -c -k VERSION # 5. Updates bootloader: update-grub # Verify files are in /boot: ls /boot/ | grep $(make kernelversion) # config-6.12.0-custom # initrd.img-6.12.0-custom # System.map-6.12.0-custom # vmlinuz-6.12.0-custom # GRUB should now list the new kernel: grep menuentry /boot/grub/grub.cfg | head -5 # Reboot and select new kernel from GRUB menu: sudo reboot # After reboot — verify: uname -r # 6.12.0-custom

Cleanup and Removing a Kernel

# Remove a kernel you no longer want: # 1. Remove from /boot: sudo rm /boot/vmlinuz-6.12.0-custom sudo rm /boot/initrd.img-6.12.0-custom sudo rm /boot/System.map-6.12.0-custom sudo rm /boot/config-6.12.0-custom # 2. Remove modules: sudo rm -rf /lib/modules/6.12.0-custom # 3. Update GRUB: sudo update-grub # Clean build artifacts (before switching configs): make clean # removes built files, keeps .config make mrproper # removes everything including .config make distclean # removes even editor backup files # Check build size: du -sh vmlinux # uncompressed kernel (~100-300MB) du -sh arch/x86/boot/bzImage # compressed image (~10-15MB)