虽然Linux内核模块传统上使用Kbuild系统构建,但使用CMake构建内核模块也是可行的,特别是在需要与用户空间应用程序共享构建系统或需要跨平台构建时。本指南将介绍如何使用CMake配置和构建Linux内核模块。
cmake_minimum_required(VERSION 3.10)
project(MyKernelModule)
# 设置内核构建目录(通常在构建时通过命令行指定)
if(NOT DEFINED LINUX_KERNEL_DIR)
message(FATAL_ERROR "Please specify LINUX_KERNEL_DIR pointing to your kernel source")
endif()
# 查找内核版本
execute_process(
COMMAND make -s -C ${LINUX_KERNEL_DIR} kernelversion
OUTPUT_VARIABLE KERNEL_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# 设置模块名称
set(MODULE_NAME mymodule)
set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/modules)
# 创建输出目录
file(MAKE_DIRECTORY ${OUTPUT_DIR})
# 添加模块源文件
set(MODULE_SOURCES
src/mymodule.c
)
# 自定义命令构建内核模块
add_custom_command(
OUTPUT ${OUTPUT_DIR}/${MODULE_NAME}.ko
COMMAND make -C ${LINUX_KERNEL_DIR} M=${CMAKE_CURRENT_SOURCE_DIR} modules
DEPENDS ${MODULE_SOURCES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Building kernel module ${MODULE_NAME}"
)
# 自定义目标
add_custom_target(
${MODULE_NAME}_module ALL
DEPENDS ${OUTPUT_DIR}/${MODULE_NAME}.ko
)
# 安装规则
install(
FILES ${OUTPUT_DIR}/${MODULE_NAME}.ko
DESTINATION /lib/modules/${KERNEL_VERSION}/extra
)
虽然使用CMake,但仍需要一个简单的Kbuild文件来与内核构建系统交互:
# Kbuild
obj-m := mymodule.o
mymodule-objs := src/mymodule.o
# 检查内核配置选项
function(check_kernel_config OPTION RESULT)
execute_process(
COMMAND grep -q "CONFIG_${OPTION}=y" ${LINUX_KERNEL_DIR}/.config
RESULT_VARIABLE RETVAL
)
if(RETVAL EQUAL 0)
set(${RESULT} TRUE PARENT_SCOPE)
else()
set(${RESULT} FALSE PARENT_SCOPE)
endif()
endfunction()
check_kernel_config("MODULES" HAVE_MODULES)
if(NOT HAVE_MODULES)
message(FATAL_ERROR "Kernel does not have module support enabled")
endif()
# 设置交叉编译工具链
if(DEFINED CROSS_COMPILE)
set(ENV{CROSS_COMPILE} ${CROSS_COMPILE})
endif()
# 设置架构
if(DEFINED ARCH)
set(ENV{ARCH} ${ARCH})
endif()
# 添加内核头文件路径
include_directories(
${LINUX_KERNEL_DIR}/include
${LINUX_KERNEL_DIR}/arch/x86/include # 根据架构调整
)
mkdir build
cd build
cmake -DLINUX_KERNEL_DIR=/path/to/kernel/source ..
make
cmake -DLINUX_KERNEL_DIR=/path/to/kernel/source \
-DARCH=arm \
-DCROSS_COMPILE=arm-linux-gnueabihf- ..
sudo make install
sudo depmod -a
sudo modprobe mymodule
# 在CMakeLists.txt中添加
add_definitions(-DDEBUG)
add_definitions(-g)
gdb vmlinux
(gdb) add-symbol-file /path/to/mymodule.ko 0xffffffffa0000000 # 地址从dmesg获取
内核版本不匹配:
缺少内核头文件:
sudo apt-get install linux-headers-$(uname -r)
权限问题:
符号未导出:
如果CMake集成过于复杂,可以考虑以下替代方案:
混合构建:
add_custom_command
调用make构建内核模块ExternalProject:
include(ExternalProject)
ExternalProject_Add(
kernel_module
SOURCE_DIR ${CMAKE_SOURCE_DIR}/kernel
BUILD_COMMAND make -C ${LINUX_KERNEL_DIR} M=${CMAKE_SOURCE_DIR}/kernel modules
INSTALL_COMMAND ""
)
使用CMake构建Linux内核模块虽然需要额外的配置,但可以提供更好的集成性和灵活性,特别是在同时构建用户空间和内核空间组件的项目中。本指南提供了基本配置和高级选项,可根据具体项目需求进行调整。