openssl headers missing kernel
PIE PIC kernel build
cross compile linux kernel ARM
Yocto vs Buildroot embedded linux
free linux kernel development course
free embedded systems course
kernel 6.x compile ubuntu fedora
Anyone who has compiled the Linux kernel from source has hit at least one confusing error message. This lesson is your troubleshooting reference. We cover the most common errors that appear when building the kernel — including the OpenSSL header issue and the PIE/PIC compiler mismatch — explain what causes them at a deeper level, and show you exactly how to fix them on modern distributions.
We also introduce Yocto and Buildroot, the two major frameworks used in embedded Linux product development, and finish with practical advice on what to do when you hit an error you cannot immediately solve.
1. Installing All Required Dependencies First
Most kernel build failures come down to one thing: a missing package. The kernel’s own documentation lists its minimum requirements in Documentation/process/changes.rst inside the kernel source tree. Always check this file for the kernel version you are building, because the requirements change between major versions.
For kernel 6.x on the major distributions, here is what you need before you even start:
# Ubuntu / Debian (kernel 6.x)
sudo apt update
sudo apt install build-essential flex bison \
libssl-dev libelf-dev libncurses-dev \
bc dwarves pahole git
# Fedora / RHEL / Rocky Linux (kernel 6.x)
sudo dnf install gcc make flex bison \
openssl-devel elfutils-libelf-devel ncurses-devel \
bc dwarves git
# Arch Linux
sudo pacman -S base-devel flex bison openssl \
libelf ncurses bc pahole git
Starting from kernel 5.16, the BPF CO-RE (Compile Once, Run Everywhere) feature requires
pahole (part of the dwarves package) to generate BTF (BPF Type Format) information during the build. If you see an error about BTF generation or pahole not found, install the dwarves package. This is a new requirement compared to older kernel build guides.2. Error: openssl/opensslv.h — No Such File or Directory
This is one of the most commonly encountered kernel build errors, especially on fresh installations. Here is what it looks like:
scripts/sign-file.c:25:10: fatal error: openssl/opensslv.h: No such file or directory
#include <openssl/opensslv.h>
^~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [scripts/Makefile.host: scripts/sign-file] Error 1
make: *** [Makefile: scripts] Error 2
sign-file utility, which is used to digitally sign kernel modules. The OpenSSL runtime library (libssl) is usually already installed on most systems, but the development headers (the .h files that compiler needs) are a separate package that is not installed by default.# Ubuntu / Debian:
sudo apt install libssl-dev
# Fedora / RHEL:
sudo dnf install openssl-devel
# Raspberry Pi OS:
sudo apt install libssl-dev
# After installing, simply re-run your make command
make -j$(nproc)
The reason the development headers are separate from the runtime is a deliberate packaging decision in Linux distributions: end users only need the runtime library to run programs that use SSL. Developers who compile software against OpenSSL need the headers additionally. The kernel build system is a developer tool, so you need both.
3. Error: Kernel Does Not Support PIC Mode / -fPIC
This error appeared more commonly when building older kernels with newer GCC versions, but understanding it is important for any embedded Linux developer.
… or …
gcc: error: unrecognized command line option ‘-fno-PIE’
PIC = Position Independent Code. Code that can run at any memory address without modification. Required for shared libraries (.so files) in user space.
PIE = Position Independent Executable. A regular executable compiled with PIC, enabling ASLR (Address Space Layout Randomisation) for better security.
Some distributions configure GCC to generate PIE by default for all code. The Linux kernel cannot be compiled as a PIC/PIE binary — it has its own position-dependent linking and load-time relocation mechanism. Modern kernels (5.x, 6.x) explicitly pass -fno-PIE and -fno-pic compiler flags to disable PIE/PIC mode. This is why you will see -fno-PIE in the kernel build output on kernel 6.x — it is working correctly.
CFLAGS=-fno-PIE to make — but for any current project, just use a kernel version from the 5.x or 6.x series and the build system handles this for you.4. Other Common Build Errors — Quick Reference
… or …
make: flex: No such file or directory
# Ubuntu:
sudo apt install flex bison
# Fedora:
sudo dnf install flex bison
Failed to generate BTF for vmlinux
Try to disable CONFIG_DEBUG_INFO_BTF
# Ubuntu:
sudo apt install dwarves
# Fedora:
sudo dnf install dwarves
scripts/config --disable CONFIG_DEBUG_INFO_BTF
make -j$(nproc)
needed by ‘certs/x509_certificate_list’
.config file copied from a distribution kernel (like Ubuntu’s). The distribution has its own code-signing certificate. Fix by clearing the certificate config options:scripts/config --disable SYSTEM_TRUSTED_KEYS
scripts/config --disable SYSTEM_REVOCATION_KEYS
make -j$(nproc)
Error line→ Missing header/tool
→ Install the package
→ Signing key issue
→ Clear cert config
→ Install dwarves
→ or disable BTF
→ Copy exact msg
→ Search: “linux kernel 6.x ” + error
make -j$(nproc) again5. The Most Reliable Troubleshooting Technique
When you hit a kernel build error that you cannot immediately recognise, there is one technique that works more often than you might expect: copy the exact error message, open a search engine, and search for something like linux kernel 6.x build fails openssl/opensslv.h. Include the kernel version and the key part of the error.
The Linux kernel community is vast and well-documented. Chances are very high that someone else has hit the same error on the same distribution and posted a working fix. The kernel’s own mailing list archives, Stack Overflow, the Arch Linux wiki, and the Ubuntu Ask community are especially good sources.
Always use
make -j$(nproc) instead of plain make. The nproc command returns the number of available CPU cores on your system. Building in parallel dramatically reduces build time — from potentially 45 minutes to under 10 minutes on a modern multi-core machine. On a 4-core machine, make -j4 builds roughly 4 times faster than a single-threaded build.6. Embedded Linux: Yocto and Buildroot
In professional embedded Linux product development, you rarely build the kernel by hand using the steps described in this series. Instead, you use a Linux builder framework. These are complete build systems that take a hardware description, a list of packages, and a kernel configuration, and produce an entire bootable Linux image — kernel, root filesystem, bootloader, and all.
6.1 What a BSP Team Does
In larger companies, a BSP (Board Support Package) team is responsible for porting Linux to new hardware. Their job includes writing or adapting the bootloader (usually U-Boot), writing the device tree source (DTS) files that describe the hardware to the kernel, and configuring and building the kernel for the specific SoC. If you join an embedded Linux team, understanding the kernel build process deeply — as covered in this series — means you can understand and contribute to BSP work even if a framework like Yocto automates the mechanics.
6.2 Why You Still Need to Understand Manual Builds
Even when Yocto or Buildroot is used in a project, there are situations where manual kernel knowledge is essential:
- Debugging a kernel issue requires reading and understanding kernel config options directly.
- Writing a new device driver means testing it by manually building and loading a kernel module — not running a full Yocto build for every change.
- Kernel configuration tuning for performance or security is done at the
make menuconfiglevel regardless of which framework is used on top. - Cross-compilation concepts — target architecture, cross-compiler prefix, sysroot — are the same whether you use Buildroot or do it manually.
7. Cross-Compilation Basics
When your development machine is x86-64 but you are building a kernel for an ARM device (like a Raspberry Pi or an i.MX board), you need a cross-compiler — a compiler that runs on x86-64 but produces ARM binaries.
# Install an ARM64 cross-compiler on Ubuntu
sudo apt install gcc-aarch64-linux-gnu
# Set environment variables before building the kernel
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# Now run make as normal — it will use the cross-compiler
make -j$(nproc)
# For 32-bit ARM (e.g. older Raspberry Pi models):
sudo apt install gcc-arm-linux-gnueabihf
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make -j$(nproc)
ARCH tells the kernel’s build system which CPU architecture to build for. Valid values include x86, x86_64, arm, arm64, riscv, mips, and others. CROSS_COMPILE is the prefix for the cross-compiler toolchain binaries — so aarch64-linux-gnu- means the build system will call aarch64-linux-gnu-gcc, aarch64-linux-gnu-ld, etc. These same variables work identically in kernel 4.x, 5.x, and 6.x.8. Verifying a Successful Build
After a successful kernel build, here is how to confirm everything is in order before installing:
# Check the main kernel image was produced
ls -lh arch/x86/boot/bzImage # x86-64
ls -lh arch/arm64/boot/Image.gz # ARM64
# Check kernel modules were built
find . -name "*.ko" | wc -l # Should show hundreds of modules
# Check the kernel version string embedded in the build
strings arch/x86/boot/bzImage | grep "Linux version"
# Check module signing configuration
grep CONFIG_MODULE_SIG .config
# View build configuration summary
make listnewconfig # Shows new Kconfig options not yet set in .config
🎯 Interview Questions & Answers
sign-file that digitally signs kernel modules. This tool uses the OpenSSL cryptographic library. The build system needs the OpenSSL development headers (the .h files) — not just the runtime library. On Ubuntu/Debian, installing libssl-dev fixes this. On Fedora/RHEL, the package is called openssl-devel.-fno-PIE to the compiler to enforce this.ARCH tells the kernel’s kbuild system which CPU architecture to target (e.g. arm64, x86_64, riscv). It selects the right architecture-specific source directories and Makefiles. CROSS_COMPILE provides the prefix of the cross-compiler toolchain binaries so that kbuild uses aarch64-linux-gnu-gcc instead of the host’s native gcc. Together these two variables completely control the target architecture of the build./proc/sys/kernel/tainted. Kernel developers may decline to debug issues on a tainted kernel since the cause could be the untrusted code.make builds files sequentially — one at a time. make -j$(nproc) tells make to run as many parallel jobs as there are CPU cores. On a 4-core machine this reduces build time from 30-45 minutes to under 10 minutes. The $(nproc) subcommand automatically returns the correct number of cores, making the command portable across different machines.✅ Chapter 4 LKM Part 1 — What You Have Learned
- How the Linux virtual address space is split into user space (Ring 3) and kernel space (Ring 0)
- Why Linux is classified as a monolithic kernel and how system calls bridge the two worlds
- How LKMs let you extend the running kernel without rebooting
- The complete LKM lifecycle: compile → load → init → run → exit → unload
- How to write a minimal Hello World kernel module with
module_init,module_exit,printk - The kbuild Makefile pattern used to build any kernel module
- How to fix the most common kernel build errors including OpenSSL headers and PIE issues
- What Yocto and Buildroot are and when each is used in embedded Linux product development
You have completed the first part of the LKM series! The next chapter dives into kernel module parameters, symbol exporting, kernel data structures, and writing a real character device driver.
