Out-of-Tree Kernel Modules as Buildroot Packages: Build Order and Installation

Package the driver against the product kernel

An out-of-tree driver should be built against the kernel that will ship with the image, not whichever kernel happens to run on the build workstation. A recipe that invokes /lib/modules/$(uname -r)/build can work on a developer machine and silently target the wrong architecture or configuration in automation. Buildroot’s kernel-module helper connects the driver to the product kernel’s build directory and flags.

This guide fixes the Buildroot side at 2025.02 and uses Linux 6.12 documentation for external-module concepts. The fictional edge-sensor package illustrates integration boundaries only. Its source URL, release version and license must come from the real driver project; none are invented below. No kernel, module or target image was built for this article.

Pinned driver sources build against the product kernel, install into the target image, and are checked with clean configurations.
Conceptual packaging flow; no kernel or driver build asserted

Define source identity and prerequisites first

Pin a source release or immutable revision and record its archive integrity and actual license files. Check whether the source really supports the selected kernel API and architecture. A driver described as “Linux compatible” may only have been maintained against a vendor branch. Packaging cannot repair that API mismatch by itself.

The Config.in entry must depend on BR2_LINUX_KERNEL. The helper expects this requirement to be enforced at the configuration layer. Other library or toolchain conditions need their own declarations. The 2025.02 helper implementation adds the linux build dependency and requests module support for enabled packages, but that does not establish that the driver’s required subsystem or bus support is configured correctly.

Use the helper before the main package infrastructure

The kernel-module helper contributes build and installation hooks; it is not a standalone replacement for generic-package or another appropriate package infrastructure. A driver-only package commonly evaluates kernel-module followed by generic-package. A mixed userspace/module project may combine it with the infrastructure appropriate to the userspace build.

# Source identity and license metadata go above these lines.
EDGE_SENSOR_MODULE_SUBDIRS = driver

$(eval $(kernel-module))
$(eval $(generic-package))

This fragment assumes that driver is the directory containing the external module’s Kbuild entry. If the module lives at the source root, the default applies instead. Read the version-pinned helper reference before combining hooks: a custom hook that consumes the compiled module must be registered after kernel-module has registered its own build hook.

Pass only variables the driver actually understands

MODULE_MAKE_OPTS supplies additional definitions to the kernel build invocation. It is useful for a driver-specific switch or a documented version variable, but should not become a second, inconsistent source of architecture and compiler settings. Inspect the upstream Kbuild files to see which variables they consume. Setting KVERSION has no effect if the driver never reads it.

LINUX_DIR identifies the configured kernel build tree. LINUX_VERSION_PROBED is the actual kernel release obtained from that tree, which can differ from the configured version label because of local version information. Treat these as values provided by Buildroot, not variables to overwrite. Preserve a verbose build log that proves the module invocation reaches the expected tree and receives the intended cross-build flags.

Understand what installation does and does not finish

The helper calls the kernel’s modules_install flow using Buildroot’s kernel make flags. Inspect the generated target tree for a module under the intended kernel-release directory, and verify that the final image contains it. Do not add an unqualified host-side modules_install command that could write into the build machine’s /lib/modules.

Module dependency metadata and aliases must correspond to the complete module set in the final filesystem. Check the product’s finalization path and the resulting modules.dep or its binary counterpart when available; merely finding a .ko file is insufficient. Firmware and userspace configuration are separate assets. A correctly installed module may still fail to bind because required firmware, device descriptions or runtime permissions are missing.

Keep external symbols and kernel artifacts together

For Linux 6.12, the external-module documentation explains that modules_prepare does not produce Module.symvers when symbol versioning is enabled. The relevant complete kernel build artifacts matter. Do not substitute exported userspace headers for the kernel’s configured build tree.

When one external module depends on symbols exported by another, make the dependency explicit and arrange for the relevant symbol information to be available during modpost. A build-order edge alone is not always the complete symbol-sharing solution. Review the upstream Kbuild arrangement and keep the producer and consumer artifacts paired. Never suppress unresolved-symbol diagnostics simply to produce an output file with the expected name.

Verify with clean outputs and deliberate removal

Propose a fresh output build that contains only the selected kernel and driver configuration, then inspect the build invocation, installed path, module metadata and final image. Separately test a configuration with the package disabled using another fresh output directory. This reveals stale module files that incremental rebuilds can leave behind.

Changing a driver source revision, kernel configuration or module subdirectory deserves a clean comparison. A package rebuild is convenient for development, but does not prove removed files disappeared from the target tree. Retain the earlier output for diagnosis instead of deleting it as the first troubleshooting step. Loading and unloading a hardware driver should happen only on an authorized lab target with a recovery path, because it can disrupt devices and services.

Acceptance and delivery contract

Accept the recipe when configuration prerequisites are explicit, the helper runs before the main infrastructure, module subdirectories match real source layout, and all build/install paths target the selected kernel and image. Verify dependency metadata after finalization and ensure a disabled-package image contains no stale driver. Keep source revision, kernel release, configuration and installed artifact hashes together.

This establishes packaging discipline, not runtime driver quality or guaranteed compatibility with future kernels. Signing, load-time ABI checks and device behavior still require their own acceptance evidence. A good handover lets another engineer reproduce the module-image pairing without using the original developer’s host kernel, private build directory or undocumented manual installation steps.

Similar Posts