Integrating an External Kernel Module into Buildroot

A step-by-step guide to packaging an out-of-tree driver as a native Buildroot package

Vivek Bhadra  |  Buildroot Linux Kernel Device Drivers Embedded Systems

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.

Step 1 – Create the Package Directory

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

Step 2 – Create the Required Package Files

Next, we need to create two essential files inside the newly created xyz package folder:

  • Config.in – Defines the configuration option. It allows users to enable or disable the package from Buildroot’s menuconfig interface.
  • xyz.mk – Contains the build logic and integration details required to compile the external kernel module as part of the Buildroot build process.
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, while the xyz.mk file provides the build instructions needed to compile and integrate the kernel module into the final root filesystem.

Step 3 – Write Config.in

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 – 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.
Naming convention: The prefix BR2_PACKAGE_ must remain unchanged – it is a standard naming convention used across all Buildroot packages. Append your package name in uppercase to form BR2_PACKAGE_XYZ. Configuration symbols are conventionally uppercase; directory names, file names, and package identifiers stay lowercase. Buildroot does not enforce this, but following the convention keeps the configuration tree clean and consistent, especially in large codebases or team environments.

Step 4 – Write 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

Variable / DirectivePurpose
XYZ_SITE Path to the source code on your local machine. Uses ../ to navigate one level above the Buildroot directory. Adjust if your source lives elsewhere.
XYZ_SITE_METHOD = local Tells Buildroot the source is in a local directory – not fetched from a remote repository or URL. Ideal for in-house projects and out-of-tree modules.
XYZ_MODULE_MAKE_OPTS Passes compile-time parameters to the make system. Define any kernel module configuration flags here; they will be forwarded during the build.
KERNEL_MODULE_BUILD_CMDS Defines the actual build commands. Invokes the module’s top-level Makefile, which triggers the standard Linux kernel module compilation flow.

The build command itself is a standard Kbuild invocation:

$(MAKE) -C '$(@D)' LINUX_DIR='$(LINUX_DIR)' CC='$(TARGET_CC)' LD='$(TARGET_LD)' modules
  • $(MAKE) -C '$(@D)' – Moves into the module’s source directory and runs make.
  • LINUX_DIR='$(LINUX_DIR)' – Specifies the Linux kernel source directory, automatically provided by Buildroot.
  • CC='$(TARGET_CC)' LD='$(TARGET_LD)' – Uses the correct cross-compiler and linker for the target platform, both already defined by Buildroot.
No manual redefinition needed: LINUX_DIR, TARGET_CC, and TARGET_LD are all managed by Buildroot. There is no need to redefine them – Buildroot passes the correct values automatically, ensuring the module is compiled with the right toolchain and kernel headers.

Step 5 – Register the Package in Buildroot

Now we need to inform the Buildroot package system that our newly created package xyz should be included. Open 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 named section in Buildroot’s menuconfig. Choose any name relevant to your package structure.
  • source "package/xyz/Config.in" – Includes the Config.in of our xyz package so it appears as a selectable option in menuconfig.
  • endmenu – Closes the menu section.

This step ensures that when you run make menuconfig, the option to enable the xyz package appears under the specified menu.

Step 6 – Enable the Package via menuconfig

At this point, the new xyz package option should be visible in Buildroot’s menuconfig. Simply open menuconfig, navigate to your package, select it, and save the changes. Buildroot will automatically update its top-level .config file:

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 Kernel Module

The final step is to update the top-level Makefile of the kernel module source so it builds correctly within the Buildroot environment.

Top-Level Makefile

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 containing kernel modules (xxx and yyy).
  • 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’s Makefile.
  • PWD := $(shell pwd) – Captures the current working directory.
  • modules: – Triggers the kernel module build using the kernel’s source directory (LINUX_DIR).
  • clean: – Cleans up generated build artefacts.

Subdirectory-Level Makefile

For subdirectories containing individual object files, 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 – Object files built unconditionally by default.
  • xxx-$(CONFIG_AAA_BBB) += foo2.o – Conditionally compiles foo2.o only when CONFIG_AAA_BBB is 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.

Summary

StepAction
mkdir package/xyzCreate the package directory inside the Buildroot tree
Config.inDeclare the package option and help text for menuconfig
xyz.mkDefine source location, site method, build flags, and build commands
package/Config.inRegister the package under a menu so it appears in menuconfig
make menuconfigEnable the package and save; Buildroot writes BR2_PACKAGE_XYZ=y
Top-Level MakefileUpdate the module’s own Makefile to invoke the Kbuild system via LINUX_DIR
makeBuildroot compiles the xyz kernel module using the correct toolchain and kernel headers
With these steps complete, your external kernel module is seamlessly integrated into Buildroot. The setup remains modular, straightforward to maintain, and ensures smooth compilation across the target toolchain. These Makefile updates ensure that Buildroot correctly compiles the kernel module using the kernel’s source tree and configuration. Running make inside Buildroot will build the xyz kernel module without any additional manual steps.

Leave a Reply