Let’s say we have a kernel device driver, xyz. It is provided as an external module. This module needs to be integrated into the existing software tree. There are multiple ways to achieve this. Instead of diving into every possible approach, we’ll focus on a streamlined method. This involves integrating the external kernel module as a new Buildroot package. For simplicity, we’ll refer to our package as xyz throughout this process.
To begin, create a dedicated directory for the new package within the Buildroot package tree. First, navigate to the Buildroot source directory.
Next, inside the package/ directory, make a folder named after your kernel module—in our case, xyz. This organizes the module clearly and makes future maintenance easy.
cd buildroot
mkdir package/xyz
Next, we need to create two essential files inside the newly created xyz package folder:
Config.in– This file defines the configuration option. It allows users to enable or disable the package from Buildroot’s menuconfig interface.xyz.mk– This file contains the build logic. It also contains the integration details required to compile the external kernel module. This is part of the Buildroot build process.
To create these two files, run the following commands:
touch buildroot/package/xyz/Config.in
touch buildroot/package/xyz/xyz.mk
These two files form the foundation of your package. The Config.in file makes the xyz package visible as a selectable option within Buildroot’s configuration interface (menuconfig), while the xyz.mk file provides the build instructions needed to compile and integrate the kernel module into the final root filesystem.
We’ll begin by writing the contents of Config.in, since this enables the package to be configured before it’s built.
Open the file using a text editor of your choice—whether you prefer vim, nano, or a graphical editor like VS Code:
config BR2_PACKAGE_XYZ
bool "xyz"
help
This is a sample package for integrating the xyz kernel module into Buildroot.
In the Config.in file above, the prefix BR2_PACKAGE_ should remain unchanged. This is a standard naming convention used across all Buildroot packages. The actual package name should be appended to it — XYZ in this case, forming BR2_PACKAGE_XYZ.
There is no strict technical requirement for using uppercase or lowercase in the name portion. Configuration symbols, like BR2_PACKAGE_XYZ, are conventionally written in uppercase. Directory names, file names, and package identifiers remain in lowercase.
This isn’t enforced by Buildroot, but following the convention helps maintain consistency and improves readability. It keeps the configuration tree clean, well-organized, and easier to work with—especially in large codebases or team environments.
xyz.mk
XYZ_MODULE_VERSION = 1.0
XYZ_SITE = ../abc/third_party/pqr/xyz
XYZ_SITE_METHOD = local
XYZ_LICENSE = GPLv2
XYZ_LICENSE_FILES = COPYING
# Additional module-specific configuration options
XYZ_MODULE_MAKE_OPTS = \
CONFIG_DUMMY1= \
CONFIG_DUMMY2=y
# Build commands for the kernel module
define KERNEL_MODULE_BUILD_CMDS
$(MAKE) -C '$(@D)' LINUX_DIR='$(LINUX_DIR)' CC='$(TARGET_CC)' LD='$(TARGET_LD)' modules
endef
$(eval $(kernel-module))
$(eval $(generic-package))
Breaking it down
An important thing to keep in mind:
The line XYZ_SITE = ../abc/third_party/pqr/xyz specifies the location of the xyz package’s source code on your local machine. This path can be any directory where the source code resides.
In this case, the source code is inside a folder named project_overlay. This folder is located one level above the Buildroot directory. Since Buildroot requires all relative paths to be referenced from its root directory, we use ../ in the xyz.mk file to navigate one level up before pointing to the actual source location.
If your source code is located elsewhere, adjust the path accordingly. Ensure you maintain the correct relative reference from the Buildroot directory.
The line XYZ_SITE_METHOD = local specifies how Buildroot retrieves the source code. Setting it to local tells Buildroot that the source code is available in a local directory. It is not fetched from a remote repository or URL. This is useful when working with in-house projects or external modules stored within your development environment.
The XYZ_MODULE_MAKE_OPTS variable allows you to pass compile-time parameters to the make system. If the kernel module requires any specific configuration flags, define them here. These flags will be passed during the build process.
The define KERNEL_MODULE_BUILD_CMDS section is where the actual build commands are defined. This step ultimately invokes the module’s top-level Makefile, which then triggers the standard Linux Kernel module compilation flow.
The command:
$(MAKE) -C '$(@D)' LINUX_DIR='$(LINUX_DIR)' CC='$(TARGET_CC)' LD='$(TARGET_LD)' modules
is a standard Kbuild Make command. Here’s what each part does:
$(MAKE) -C '$(@D)'– Moves into the source directory of the module and runsmake.LINUX_DIR='$(LINUX_DIR)'– Specifies the Linux Kernel source directory, which Buildroot automatically provides.CC='$(TARGET_CC)' LD='$(TARGET_LD)'– Uses the correct cross-compiler and linker for the target platform, both of which are already defined by Buildroot.
Since LINUX_DIR, TARGET_CC, and TARGET_LD are managed by Buildroot, there’s no need to redefine them. Buildroot takes care of passing the appropriate values. It ensures that the module is compiled with the correct toolchain and kernel headers.
Now, we need to inform the Buildroot package system that our newly created package xyz should be included. To do this, we modify the Buildroot package configuration file:
Open the file buildroot/package/Config.in and add the following entry:
menu "Menu-name whatever you like"
source "package/xyz/Config.in"
endmenu
Explanation:
menu "Menu-name whatever you like"– Creates a menu section in Buildroot’smenuconfig. You can name this menu anything relevant to your package structure.source "package/xyz/Config.in"– Includes theConfig.infile of our xyz package so that it appears as a selectable option inmenuconfig.endmenu– Closes the menu section.
This step ensures that when you run make menuconfig, the option to enable the xyz package appears. It appears under the specified menu.
At this point, you should be able to see the new xyz package option in Buildroot’s menuconfig. The process of invoking Buildroot’s menuconfig is exactly the same as for the kernel configuration. Therefore, I won’t go into those details.
Simply open menuconfig, navigate to your package, select it, and save the changes. Once done, you’ll find that Buildroot has automatically updated its top-level .config file to include the new configuration option:
BR2_PACKAGE_XYZ=y
This confirms that the package has been successfully registered in Buildroot’s build system. The .config file is located in the root directory of Buildroot and is generated after saving your menuconfig selections.
Modifying the Top-Level Makefile of the Actual Source Code
The final step is to update the top-level Makefile of the kernel module source. This ensures it builds correctly within the Buildroot environment.
Top-Level Makefile
Here’s the structure of a top-level Makefile that ensures proper integration with the kernel build system:
obj-m += xxx/ yyy/
subdir-ccflags-y := -I$(src)/include
subdir-ccflags-y += -Wall -g
ifeq ($(KERNELRELEASE),)
PWD := $(shell pwd)
modules:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules
clean:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean
endif
Explanation:
obj-m += xxx/ yyy/– Specifies the directories that contain kernel modules (xxxandyyy).subdir-ccflags-y := -I$(src)/include– Adds an include path for headers.subdir-ccflags-y += -Wall -g– Enables all warnings and debugging symbols.ifeq ($(KERNELRELEASE),)– Ensures that when invoked outside the kernel build system, it correctly calls the kernel’sMakefile.PWD := $(shell pwd)– Gets the current working directory.modules:– Triggers the kernel module build using the kernel’s source directory (LINUX_DIR).clean:– Cleans up generated files.
Subdirectory-Level Makefile
For subdirectories containing individual object files, we define a Makefile in each submodule directory:
xxx-y := foo1.o
xxx-$(CONFIG_AAA_BBB) += foo2.o
ccflags-y += -D
ccflags-y += -I$(src)/nnn/
ccflags-y += -I$(src)/
ppp-y += /foo3.o
ppp-y += /foo4.o
Explanation:
xxx-y := foo1.o– Specifies the object files that should be built by default.xxx-$(CONFIG_AAA_BBB) += foo2.o– Conditionally compilesfoo2.oifCONFIG_AAA_BBBis enabled.ccflags-y += -D– Defines additional compiler flags.ccflags-y += -I$(src)/nnn/and-I$(src)/– Adds include paths for source files.ppp-y += /foo3.o /foo4.o– Adds additional object files to be compiled into the module.
With that, your external kernel module is now seamlessly integrated into Buildroot. This setup keeps things modular, easy to manage, and ensures smooth compilation. Stay tuned for the next post, where we’ll dive into more Buildroot customizations and kernel tweaks!These Makefile updates ensure that Buildroot correctly compiles the kernel module using the kernel’s source tree and configuration. After these modifications, running make inside Buildroot should build the xyz kernel module seamlessly.

3 Comments