Unable to add a simple kernel-module to Yocto image - embedded-linux

Goal
I want to add a touchscreen driver available in the linux kernel source tree to my Yocto image (The link takes you to goodix.c). I basically need to add it as a kernel module.
Solution
I follow the Incorporating Out-of-Tree Modules section of the Yocto Mega Manual. I base mine off their example kernel-module recipe, called hello-mod.
In recipe goodix-9271_0.1.bb: RPROVIDES_${PN} = "kernel-module-goodix"
In layer.conf: MACHINE_EXTRA_RDEPENDS += "kernel-module-goodix"
Problem
My build simply consistently fails in do_rootfs with:
Error:
Problem: package packagegroup-base-1.0-r83.imx6ul_var_dart requires packagegroup-machine-base, but none of the providers can be installed
- package packagegroup-base-extended-1.0-r83.imx6ul_var_dart requires packagegroup-base, but none of the providers can be installed
- package packagegroup-machine-base-1.0-r83.imx6ul_var_dart requires kernel-module-goodix, but none of the providers can be installed
- conflicting requests
- nothing provides kernel-module-goodix-5.4.3-imx6ul+gb40ccfdb73ea needed by goodix-9271-0.1-r0.imx6ul_var_dart
(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages)
What I cannot understand after reading the documentation on this section is why this error is happening. I tried adjusting the recipe names (removing the kernel-module prefix, etc) but nothing seems to work. What is going wrong?
Source
inherit module logging
# Driver for Goodix touchscreens
SUMMARY = "Generic driver for Goodix touchscreens"
DESCRIPTION = "Support for Goodix 1151, 5663, 5688, 917S, 9286, 911, 9271, 9110, 927, 928, 912, 9147, and 967 touchscreens"
# License
LICENSE = "GPL-2.0"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
# Compatibility
COMPATIBLE_MACHINE = "(imx)"
# Package name
RPROVIDES_${PN} = "kernel-module-goodix"
# Source
S = "${WORKDIR}"
SRC_URI = "file://Makefile \
file://goodix.c"
# Functions
do_install() {
bbwarn "Installing Goodix kernel module ..."
bbwarn "KERNEL_SRC = ${KERNEL_SRC}"
bbwarn "KERNEL_VERSION = ${KERNEL_VERSION}"
bbwarn "WORKDIR = ${WORKDIR}"
cd ${S}
xz goodix.ko
install --verbose -d ${D}/lib/modules/${KERNEL_VERSION}/kernel/drivers/input/touchscreen
install --verbose -m 0644 goodix.ko.xz ${D}/lib/modules/${KERNEL_VERSION}/kernel/drivers/input/touchscreen
}
# Reference included files
FILES_${PN} = "/lib/modules/${KERNEL_VERSION}/kernel/drivers/input/touchscreen/*"
Edits
The error basically says that kernel-module-goodix-5.3.4-imx6ul+gb40ccfdb73ea isn't provided. I didn't name my package that way though. So why is it looking for something with the suffix 5.3.4-imx6ul+gb40ccfdb73ea there?
Edit (Solution)
For anyone reading this who isn't satisfied by the accepted answer. Just know that what was wrong with my original recipe was that I wasn't naming my actual recipe "kernel-module-<name>.bb". That was actually what was required.

I have created a recipe for an UART Bluetooth driver before and it works fine for me, here is the recipe:
#
# FNLINK BLUETOOTH 8822 KERNEL DRIVER
#
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
SRC_URI = "file://uart_bt.zip"
S = "${WORKDIR}/bluetooth_uart_driver"
inherit module
EXTRA_OEMAKE_append_task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"
EXTRA_OEMAKE += "KDIR=${STAGING_KERNEL_DIR}"
Change S to "bluetooth_uart_driver" because the zip file contains that directory with the content:
ifneq ($(KERNELRELEASE),)
obj-m := hci_uart.o
hci_uart-y := hci_ldisc.o hci_h4.o hci_rtk_h5.o rtk_coex.o
#EXTRA_CFLAGS += -DDEBUG
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
endif
This works well for me, and the .ko file is generated and shipped into /lib/modules/${KVER}/extra , so you can override the do_install function and install it where you want.
Simple Test:
I downloaded the goodix.c driver and created a custom recipe for it with this Makefile (I modified my old BT Makefile):
ifneq ($(KERNELRELEASE),)
obj-m := goodix.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
endif
My recipe:
|meta-test/
|--> recipes-driver/
|--> files/
|--> goodix.c
|--> Makefile
|--> goodix-driver_0.1.bb
goodix-driver_0.1.bb:
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
SRC_URI = "file://goodix.c file://Makefile"
S = "${WORKDIR}"
inherit module
EXTRA_OEMAKE_append_task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"
EXTRA_OEMAKE += "KDIR=${STAGING_KERNEL_DIR}"
With this in a simple poky build I was able to generate the .ko file.
Note:
If goodix.c is present in your upstream Linux kernel, which means you can find it in:
tmp/work/.../linux-../../git/drivers/input/touchscreen/goodix.c
which means you can just patch it without creating a whole recipe for it, you just edit it directly and then go back to git folder and :
git add drivers/input/touchscreen/goodix.c
git commit -m "My-updates"
git format-patch -1 -o /path/to/meta-custom/recipes-kernel/linux/files
Now, in /path/to/meta-custom/recipes-kernel/linux/linux-xx_%.bbappend add:
SRC_URI_append = " file://My-updates.patch"
Now, do not forget to activate it via menuconfig and add its flag to the kernel defconfig file so it gets compiled and shipped within the rootfs.

I am updating my question with an answer which also describes how to create a simple kernel module bitbake file.
File name and placement
Name of my kernel module: foo
Name of my bitbake file: kernel-module-foo (kernel-module- prefix required)
Topology (see below):
├── conf
│ └── layer.conf
├── COPYING.MIT
├── README
├── recipes-kernel
│ └── linux
│ ├── kernel-module-foo.bb
Bitbake file
# Bitbake class(es)
inherit module
# Dependencies
DEPENDS = "virtual/kernel"
# Metadata
SUMMARY = "Sample kernel module"
# Licensing
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5= 0835ade698e0bcf8506ecda2f7b4f302"
# Source
GIT_BRANCH = "my-branch"
SRC_URI = "git://<path-to-git-repo>;branch=${GIT_BRANCH}"
SRCREV = "<my-git-branch-src-revision>"
# OE build directives
EXTRA_OEMAKE_append_task-install = "-C ${STAGING_KERNEL_DIR} M=${S}"
EXTRA_OEMAKE += "KDIR=${STAGING_KERNEL_DIR}"
# Autoinstall (optionally disable)
KERNEL_MODULE_AUTOLOAD += "pwr_ctl_onoff"

Related

Buildroot build error: `ERROR: Dependency "nlohmann_json" not found, tried pkgconfig and cmake`

I'm trying to add the header-only library https://github.com/nlohmann/json "JSON for Modern C++" to my Buildroot package for use both on the target embedded Linux board, as well as on my host build machine in unit tests.
However, I keep getting a variety of errors no matter what I do, including ERROR: Dependency "nlohmann_json" not found, tried pkgconfig and cmake.
What's the proper way to add this library package to be used by my package?
Details about my setup:
That JSON library is known as json-for-modern-cpp in the Buildroot source code, and is located here: https://github.com/buildroot/buildroot/tree/master/package/json-for-modern-cpp
My buildroot/package/json-for-modern-cpp/json-for-modern-cpp.mk file straight from Buildroot looks like this:
################################################################################
#
# json-for-modern-cpp
#
################################################################################
JSON_FOR_MODERN_CPP_VERSION = 3.10.5
JSON_FOR_MODERN_CPP_SOURCE = json-$(JSON_FOR_MODERN_CPP_VERSION).tar.gz
JSON_FOR_MODERN_CPP_SITE = $(call github,nlohmann,json,v$(JSON_FOR_MODERN_CPP_VERSION))
JSON_FOR_MODERN_CPP_LICENSE = MIT
JSON_FOR_MODERN_CPP_LICENSE_FILES = LICENSE.MIT
JSON_FOR_MODERN_CPP_CPE_ID_VENDOR = json-for-modern-cpp_project
JSON_FOR_MODERN_CPP_INSTALL_STAGING = YES
# header only library
JSON_FOR_MODERN_CPP_INSTALL_TARGET = NO
JSON_FOR_MODERN_CPP_CONF_OPTS = -DJSON_BuildTests=OFF -DJSON_MultipleHeaders=ON
$(eval $(cmake-package))
My package's br2-external/package/my-module-name/my-module-name.mk makefile has these dependencies in it (notice I added json-for-modern-cpp to both the MY_MODULE_NAME_DEPENDENCIES target board dependencies, as well as to the HOST_MY_MODULE_NAME_DEPENDENCIES host build system dependencies:
MY_MODULE_NAME_DEPENDENCIES += \
some-other-lib1 \
some-other-lib2 \
json-for-modern-cpp
HOST_MY_MODULE_NAME_DEPENDENCIES += \
host-some-other-lib1 \
host-some-other-lib2 \
json-for-modern-cpp
How to add a Buildroot package to your package, and to your meson.build file
I figured it out. I've documented what I learned in my eRCaGuy_dotfiles/git & Linux cmds, help, tips & tricks - Gabriel.txt notes file. Search that document for "Adding dependencies from other meson.build files" and for "nlohmann" for details and notes.
Here's the solution:
If you need to add a dependency on a 3rd-party library or something, such as JSON for Modern C++ (https://github.com/nlohmann/json), simply do this:
Find that project's meson.build file. Ex: https://github.com/nlohmann/json/blob/develop/meson.build
Notice the 'nlohmann_json' project name at the top. Use that in your module's meson.build file:
all_deps = [
# NB: this `nlohmann_json` meson.build name can be identified from its public repo's
# meson.build file here: https://github.com/nlohmann/json/blob/develop/meson.build#L1
dependency('nlohmann_json')
dependency('some_other_lib2'),
dependency('some_other_lib3'),
dependency('some_other_lib4'),
]
all_deps will then be used in your meson.build file to build your executable and specify your library dependencies--something like this, for example:
my_lib = static_library(
'my_module_name',
include_directories : [include_dirs],
sources: [library_sources],
dependencies: all_deps,
cpp_args: compiler_options,
install: true,
)
Add $(eval $(host-cmake-package)) to the bottom of the json-for-modern-cpp.mk file in Buildroot here: https://github.com/buildroot/buildroot/blob/master/package/json-for-modern-cpp/json-for-modern-cpp.mk. This requires adding your own commit to your own custom fork of that repo.
That changes that file from this:
################################################################################
#
# json-for-modern-cpp
#
################################################################################
JSON_FOR_MODERN_CPP_VERSION = 3.10.5
JSON_FOR_MODERN_CPP_SOURCE = json-$(JSON_FOR_MODERN_CPP_VERSION).tar.gz
JSON_FOR_MODERN_CPP_SITE = $(call github,nlohmann,json,v$(JSON_FOR_MODERN_CPP_VERSION))
JSON_FOR_MODERN_CPP_LICENSE = MIT
JSON_FOR_MODERN_CPP_LICENSE_FILES = LICENSE.MIT
JSON_FOR_MODERN_CPP_CPE_ID_VENDOR = json-for-modern-cpp_project
JSON_FOR_MODERN_CPP_INSTALL_STAGING = YES
# header only library
JSON_FOR_MODERN_CPP_INSTALL_TARGET = NO
JSON_FOR_MODERN_CPP_CONF_OPTS = -DJSON_BuildTests=OFF -DJSON_MultipleHeaders=ON
$(eval $(cmake-package))
to this:
################################################################################
#
# json-for-modern-cpp
#
################################################################################
JSON_FOR_MODERN_CPP_VERSION = 3.10.5
JSON_FOR_MODERN_CPP_SOURCE = json-$(JSON_FOR_MODERN_CPP_VERSION).tar.gz
JSON_FOR_MODERN_CPP_SITE = $(call github,nlohmann,json,v$(JSON_FOR_MODERN_CPP_VERSION))
JSON_FOR_MODERN_CPP_LICENSE = MIT
JSON_FOR_MODERN_CPP_LICENSE_FILES = LICENSE.MIT
JSON_FOR_MODERN_CPP_CPE_ID_VENDOR = json-for-modern-cpp_project
JSON_FOR_MODERN_CPP_INSTALL_STAGING = YES
# header only library
JSON_FOR_MODERN_CPP_INSTALL_TARGET = NO
JSON_FOR_MODERN_CPP_CONF_OPTS = -DJSON_BuildTests=OFF -DJSON_MultipleHeaders=ON
$(eval $(cmake-package))
$(eval $(host-cmake-package))
Again, the only line added was the last one above. That causes cmake to bring in the necessary dependencies for the host build computer too, for your unit tests, and not just for the target embedded Linux board, which is what the $(eval $(cmake-package)) line does.
Use the proper dependencies in your module's Buildroot br2-external/package/my-module-name/my-module-name.mk makefile. For the host it should be host-json-for-modern-cpp, not json-for-modern-cpp, since the latter is for the target board only. Note that the json-for-modern-cpp name seems to be defined in the config file here, by the way: https://github.com/buildroot/buildroot/blob/master/package/json-for-modern-cpp/Config.in#L2.
MY_MODULE_NAME_DEPENDENCIES += \
some-other-lib1 \
some-other-lib2 \
json-for-modern-cpp
HOST_MY_MODULE_NAME_DEPENDENCIES += \
host-some-other-lib1 \
host-some-other-lib2 \
host-json-for-modern-cpp
# This last line just above is now **fixed**!
That's it! It works now.
I'm not sure why I had to add $(eval $(host-cmake-package)) to the buildroot file, as it seems like that should be something in the json-for-modern-cpp.mk file in the Buildroot repo by default, no?

Where's the location of the app/binary defined in a yocto recipe?

I have a following recipe which runs a said service which in turns runs an app on boot-up, but I am trying to understand where the location of the app defined which ends up in sysfs image.
Currently, the appSource binary (defined in Makefile) gets stored in /usr/bin but I'm not sure where the destination location (/usr/bin) is defined.
The following command results in
$ bitbake -e appSource | grep ^FILES_${PN}
FILES_appSource="/usr/bin/* /usr/sbin/* /usr/libexec/* /usr/lib/lib*.so.* /etc /com /var /bin/* /sbin/* /lib/*.so.* /lib/udev /usr/lib/udev /lib/udev /usr/lib/udev
Here's the recipe
inherit autotools-brokensep pkgconfig
DESCRIPTION = "A sample recipe"
LICENSE = "CLOSED"
DEPENDS = "glib-2.0"
FILESPATH =+ "${THISDIR}:"
SRC_URI = "file://appSource"
S = "${WORKDIR}/appSource""
FILES_${PN} += "${systemd_unitdir}/*"
INIT_MANAGER = "systemd"
do_install_append() {
if ${#bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then
install -d ${D}/etc/initscripts
install -d ${D}${systemd_unitdir}/system
install -m 0644 ${WORKDIR}/appService/appService.service ${D}${systemd_unitdir}/system/appService.service
install -d ${D}${systemd_unitdir}/system/multi-user.target.wants/
ln -sf ${systemd_unitdir}/system/appService.service ${D}${systemd_unitdir}/system/multi-user.target.wants/appService.service
fi
}
Here is what I find out:
You are inheriting autotools-brokensep which has the following content:
# Autotools class for recipes where separate build dir doesn't work
# Ideally we should fix software so it does work. Standard autotools supports
# this.
inherit autotools
B = "${S}"
So, it inherit autotools which has do_install with the content of:
autotools_do_install() {
oe_runmake 'DESTDIR=${D}' install
# Info dir listing isn't interesting at this point so remove it if it exists.
if [ -e "${D}${infodir}/dir" ]; then
rm -f ${D}${infodir}/dir
fi
}
So, it runs the install target of your Makefile into ${D} which is ${WORKDIR}/image.
So, I assume that your Makefile has an install target that copies the binary into /usr/bin.
For the FILES variable content, this is defined in bitbake.conf:
FILES_${PN} = "${bindir}/* ${sbindir}/* ${libexecdir}/* ${libdir}/lib*${SOLIBS} \ ...
Provide your Makefile to confirm my assumption, or I do a further research on the topic.

Kernel module build fails with "missing argument to -gdwarf-"

I am trying to build a Xilinx XDMA driver for Yocto, using their supplied makefile. When I run my recipe the build fails with the following errors:
DEBUG: Executing shell function do_compile
NOTE: make -j 32 KERNEL_SRC=./tmp/work-shared/intel-corei7-64/kernel-source
KERNEL_PATH=./tmp/work-shared/intel-corei7-64/kernel-source
KERNEL_VERSION=5.10.78-intel-pk-standard CC=x86_64-poky-linux-gcc
-fuse-ld=bfd
-fmacro-prefix-map=./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0=/usr/src/debug/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0
-fdebug-prefix-map=./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0=/usr/src/debug/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0
-fdebug-prefix-map=./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/recipe-sysroot=
-fdebug-prefix-map=./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/recipe-sysroot-native=
-fdebug-prefix-map=./tmp/work-shared/intel-corei7-64/kernel-source=/usr/src/kernel LD=x86_64-poky-linux-ld.bfd
AR=x86_64-poky-linux-ar
O=./tmp/work-shared/intel-corei7-64/kernel-build-artifacts KBUILD_EXTRA_SYMBOLS=
Makefile:17: XVC_FLAGS: .
make -C /lib/modules/5.13.0-40-generic/build
M=./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/git/linux_driver/xdma modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-40-generic'
make[2]: Entering directory './tmp/work-shared/intel-corei7-64/kernel-build-artifacts'
./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/git/linux_driver/xdma/Makefile:17: XVC_FLAGS: .
CC [M] ./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/git/linux_driver/xdma/libxdma.o
CC [M] ./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/git/linux_driver/xdma/xdma_cdev.o
x86_64-poky-linux-gcc: error: missing argument to '-gdwarf-'
CC [M] ./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/git/linux_driver/xdma/cdev_ctrl.o
make[3]: *** [/usr/src/linux-headers-5.13.0-40-generic/scripts/Makefile.build:281: ./tmp/work/intel_corei7_64-poky-linux/xdma-driver-mod/1.0+gitAUTOINC+8d75946900-r0/git/linux_driver/xdma/libxdma.o] Error 1
make[3]: *** Waiting for unfinished jobs....
x86_64-poky-linux-gcc: error: missing argument to '-gdwarf-'
ERROR: oe_runmake failed
WARNING: exit code 1 from a shell command.
I have no idea why this happens as it is not something I have specifically enabled. I have searched through the module.bbclass file but I couldn't see anything obvious. I believe that something needs to be configured such that the -gdwarf- actual ends up being set to a valid value (e.g. -gdwarf-2 or -gdwarf-4 etc.)
A grep through the poky repo for dwarf did not reveal anything neither did a search of /usr/src/linux-headers-5.13.0-40-generic/scripts/.
My bitbake recipe is as follows:
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=441c1ecbc199a036abf37f3aa47c5f34"
SRC_URI += https://github.com/Xilinx/dma_ip_drivers.git;protocol=ssh;nobranch=1;branch=master"
# Modify these as desired
PV = "1.0+git${SRCPV}"
SRCREV = "8d7594690058dfa828accc02ac81348e416ffe38"
S = "${WORKDIR}/git/xdma/linux-driver/xdma"
RPROVIDES_${PN} += "xdma"
inherit module
EXTRA_OEMAKE_task-install:append = " -C ${STAGING_KERNEL_DIR} M=${S}"
EXTRA_OEMAKE += "KDIR=${STAGING_KERNEL_DIR}"
The makefile is the standard one from GitHub. The driver builds correctly for Ubuntu using make and I can also build the module if I change my recipe such that it does not include inherit module; this change will build the module (xdma.ko) but does to install it in the roofs. I am also not sure if inherit module includes additional functionality which may be rewired.
How to I either:
prevent / disable the -gdwarf flag being generated
configure the recipe that the -gdwarf- resolves to something valid
View the actual command being invoked that is causing the issue.
Attempts to build the xdma.ko module without the inherit module result in an invalid binary being built, i.e. when I try an load the module on the target I get:
insmod xdma.ko
insmod: ERROR: could not insert module xdma.ko: Invalid module format
Which indicates that the module is compiled from the wrong target.
inherit module is required when building kernel modules for Yocto. If it is omitted the build modules is not compatible with the target.
Workaround for the -gdwarf- error was to manually write a new makefile which is compatible with Yocto:
TARGET_MODULE:=xdma
topdir := $(shell cd $(src)/.. && pwd)
EXTRA_CFLAGS := -I$(topdir)/include
SRC := $(shell pwd)
$(TARGET_MODULE)-objs := libxdma.o xdma_cdev.o cdev_ctrl.o cdev_events.o cdev_sgdma.o cdev_xvc.o cdev_bypass.o xdma_mod.o xdma_thread.o
obj-m := $(TARGET_MODULE).o
all :
$(MAKE) -C $(KERNEL_SRC) M=$(SRC)
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symvers
This makefile correctly builds the Xilinx XDMA driver for Yocto. I can confirm that the driver works with Kintex-KC705 FPGA development card.

How to statically build kernel module with buildroot?

Is there an example package somewhere on how you might go about statically compiling in a device driver?
I know that obj-y is used for static compilation vs obj-m. I have a dynamically loadable module being built in my buildroot package right now. That dynamic module works exactly as I would expect. I even figured out that I could change the module makefile to use obj-y, and add a buildroot option where, if I clicked it it would append a line in the drivers/Makefile. The output appeared to show that my module got built. But it didn't at all seem to me that my driver's init function was being executed at startup, because I don't see my device file in /dev.
Supposing you have a driver in driver.c, and a buildroot package called STATICDRVR, you can use the following Config.in and STATICDRVR.mk files to add a static module to be built when the kernel is built:
Config.in
config BR2_PACKAGE_STATICDRVR
bool "Build & link static driver?"
help
This is a driver that blah blah greatness whatever
STATICDRVR.mk
STATICDRVR_VERSION = master
STATICDRVR_SITE = /location/to/STATICDRVR_containing_src
STATICDRVR_SITE_METHOD = local
STATICDRVR_MODULE_SUBDIRS = src
STATICDRVR_INSTALL_TARGET = YES
STATICDRVR_LICENSE = GPLv2
STATICDRVR_LICENSE_FILES = COPYING
STATICDRVR_NAME = STATICDRVR
STATICDRVR_DEPENDENCIES = linux
define STATICDRVR_BUILD_CMDS
#make sure that obj-y += STATICDRVR/ is only in the build makefile once
sed -i '/obj-y += STATICDRVR/d' $(BUILD_DIR)/linux-$(LINUX_VERSION)/drivers/Makefile
echo "obj-y += STATICDRVR/" >> $(BUILD_DIR)/linux-$(LINUX_VERSION)/drivers/Makefile
rm -rf $(BUILD_DIR)/linux-$(LINUX_VERSION)/drivers/STATICDRVR
cp -r $(#D)/src $(BUILD_DIR)/linux-$(LINUX_VERSION)/drivers/STATICDRVR
echo "obj-y += driver.o" > $(BUILD_DIR)/linux-$(LINUX_VERSION)/drivers/STATICDRVR/Makefile
endef
define STATICDRVR_INSTALL_STAGING_CMDS
endef
define STATICDRVR_INSTALL_TARGET_CMDS
endef
endif
define STATICDRVR_DEVICES
endef
define STATICDRVR_PERMISSIONS
endef
define STATICDRVR_USERS
endef
$(eval $(kernel-module))
$(eval $(generic-package))
It is not possible to statically link an external module with the kernel. To do that, you have to patch the kernel itself and add your module there.

Building an out-of-tree Linux kernel module in a separate object directory

I'm confronting the Linux kernel build system (Kbuild, kernel ≥2.6.28) with the directory structure and build system for a larger project. Our project contains an out-of-tree Linux kernel module, and our directory structure looks like this (simplified, obviously):
checkout/src/common/*.c source files (common to Linux and other platforms)
checkout/src/linux-driver/*.c source files (for the Linux kernel driver)
checkout/build/linux/Kbuild Kbuild
tmp/linux-2.6.xx/ where the Linux kernel is unpacked and configured
output/linux-arm-debug/ where object files must end up
The build process must not modify anything under checkout, and building the module must not modify anything under tmp/linux-2.6.xx. All output files must end up under output/linux-arm-debug (or whatever architecture and debug variant was selected at build time).
I've read kbuild/modules.txt, and started to write my Kbuild file:
MOD_OUTPUT_DIR = ../../../output/linux-$(ARCH)-$(DEBUG)
obj-m += $(MOD_OUTPUT_DIR)/foo_mod.o
$(MOD_OUTPUT_DIR)/our_module-objs := $(MOD_OUTPUT_DIR)/foo_common.o $(MOD_OUTPUT_DIR)/foo_linux.o
This handles storing the object files in a different directory from where Kbuild lives. Now how can I specify that foo_common.o needs to be compiled from …/checkout/src/common/foo_common.c and foo_linux.o from …/checkout/src/linux-driver/foo_linux.c?
Here is a Makefile which does out of source-tree builds for out of kernel-tree modules (adapted from #Mark's comment)...
KDIR ?= /lib/modules/$(shell uname -r)/build
BUILD_DIR ?= $(PWD)/build
BUILD_DIR_MAKEFILE ?= $(PWD)/build/Makefile
default: $(BUILD_DIR_MAKEFILE)
make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) modules
$(BUILD_DIR):
mkdir -p "$#"
$(BUILD_DIR_MAKEFILE): $(BUILD_DIR)
touch "$#"
clean:
make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) clean
Note: You still need a Kbuild file...
obj-m += my_driver.o
I had a similar problem. I modified linux_2_6_34/scripts/Makefile.build as follows.
ifdef SRCDIR
src := $(SRCDIR)
else
src := $(obj)
endif
SRCDIR is the directory source.
To compile the module, run
make -c $(KDIR) M=$(Your_output_dir) SRCDIR=$(your source directory)`
My inelegant but effective solution is to copy the source files into the output tree.
FOO_SOURCES_DIR = $(src)/../../../checkout/src
FOO_MOD_OUTPUT_DIR = ../../../output/linux-$(ARCH)-$(DEBUG)
# Specify the object files
obj-m += $(FOO_MOD_OUTPUT_DIR)/foo_mod.o
FOO_MODULE_OBJS := $(FOO_MOD_OUTPUT_DIR)/foo_common.o $(FOO_MOD_OUTPUT_DIR)/foo_linux.o
$(FOO_MOD_OUTPUT_DIR)/foo_mod-objs := $(FOO_MODULE_OBJS)
# Where to find the sources
$(src)/$(FOO_MOD_OUTPUT_DIR)/foo_common.c: $(FOO_SOURCES_DIR)/common/foo_common.c
$(src)/$(FOO_MOD_OUTPUT_DIR)/foo_linux.c: $(FOO_SOURCES_DIR)/linux-driver/foo_linux.c
# Rules to copy the sources
FOO_COPIED_SOURCES = $(patsubst %.o,$(src)/%.c,$(FOO_MODULE_OBJS))
$(FOO_COPIED_SOURCES):
$(Q)mkdir -p $(#D)
cp -f $< $#
clean-files += $(FOO_COPIED_SOURCES)
clean-dirs += $(FOO_MOD_OUTPUT_DIR)
While you haven't mentioned what you've tried so far (or whether you found a solution already), it looks like you just need to continue further down the modules.txt file a bit -- to Section 4.3:
--- 4.3 Several Subdirectories
kbuild can handle files that are spread over several directories.
Consider the following example:
.
|__ src
| |__ complex_main.c
| |__ hal
| |__ hardwareif.c
| |__ include
| |__ hardwareif.h
|__ include
|__ complex.h
To build the module complex.ko, we then need the following
kbuild file:
--> filename: Kbuild
obj-m := complex.o
complex-y := src/complex_main.o
complex-y += src/hal/hardwareif.o
ccflags-y := -I$(src)/include
ccflags-y += -I$(src)/src/hal/include
As you can see, kbuild knows how to handle object files located
in other directories. The trick is to specify the directory
relative to the kbuild file's location. That being said, this
is NOT recommended practice.
For the header files, kbuild must be explicitly told where to
look. When kbuild executes, the current directory is always the
root of the kernel tree (the argument to "-C") and therefore an
absolute path is needed. $(src) provides the absolute path by
pointing to the directory where the currently executing kbuild
file is located.
A bit late, but it looks like O= flag is what you need.
You can set the environment variable KBUILD_OUTPUT. This functions similar to the O= option; however, since it's an environment variable, it can span multiple makefiles where O= can't be passed or an out-of-directory module needs to be built. I was having this same issue with trying to build a set of compat-wireless modules and I needed to use O= for the actual kernel image build.

Resources