使用cmake编译内核模块的几种方法

18 篇文章 8 订阅

这一段要把内核模块集成到整个工程中进行编译,但是内核模块原来是用makefile编译的,现在需要转换成cmake。经过一天的探索,总共找到3种方式来实现这个目标。下面这是第一种方法,具体思路就是在cmake中使用add_custom_command和add_custom_target的方式来实现编译,也就是把makefile中规定的obj-m:= 和ALL伪目标以及make等操作全部都放到cmake中执行。

这里给出一个通用模板,并且给出了详细注释。

cmake_minimum_required(VERSION 3.0.0)
project(episode LANGUAGES C)

# 1. 查找内核头文件目录
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(KernelHeaders REQUIRED)
# 2. 将内核头文件目录添加到本次编译的头文件目录,相当于-I
include_directories(${KERNELHEADERS_INCLUDE_DIRS})

# 3. 设置最终的模块文件和目标文件
set(MODULE_FILE "${PROJECT_NAME}.ko")
set(KBUILD_FILE "obj-m := ${PROJECT_NAME}.o")

# 4. 设置某些有特殊要求的目标对象的编译参数,这里是目标文件中有浮点运算,而编译器默认关闭了 msse
set(KBUILD_FILE "${KBUILD_FILE}\nCFLAGS_src/${PROJECT_NAME}.o += -mhard-float -msse -msse2 ")
set(KBUILD_FILE "${KBUILD_FILE}\nCFLAGS_src/episode_space_index.o += -mhard-float -msse -msse2 ")

# 5. 设置模块构建命令,用变量代替
set(KBUILD_CMD $(MAKE) -C ${KERNELHEADERS_DIR} modules M=${CMAKE_CURRENT_BINARY_DIR} src=${CMAKE_CURRENT_SOURCE_DIR})

# 6. 遍历src目录获取所有的.c文件,并将他们添加到sources_absolute列表中,GLOB_RECURSE会遍历匹配src目录的所有文件以及子目录下面的文件
file(GLOB_RECURSE sources_absolute ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
# 7. 针对每一个.c文件,获取其相对路径,放到sources_relative列表中,并将待构建目标文件追加到KBuild文件中,同时在构建目录下创建对应的文件夹用来存放将要生成的目标文件
foreach(file ${sources_absolute})
  # 7.1 RELATIVE_PAT推断出指定文件file相对于特定目录的路径,并将该路径赋值给变量${file}
  file(RELATIVE_PATH file "${CMAKE_CURRENT_SOURCE_DIR}" "${file}")
  # 7.2 提取上一步拿到的变量${file}中的目录,保存到变量file_dir
  get_filename_component(file_dir "${file}" DIRECTORY)
  # 7.3 提取上一步拿到的变量${file}中的文件名称(不含目录和文件名的后缀),保存到变量file_name_we
  get_filename_component(file_name_we "${file}" NAME_WE)
  
  # 7.4 在构建目录下,给上面解析的文件创建对应的目录,用来保存.c生成的.o文件
  file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${file_dir})

  # 7.5 将待构建的目标文件(.o文件)追加到Kbuild文件中
  set(KBUILD_FILE "${KBUILD_FILE}\n${PROJECT_NAME}-y += ${file_dir}/${file_name_we}.o")

  # 7.6 将源代码文件的相对路径放到sources_relative 列表中
  list(APPEND sources_relative "${file_dir}/${file_name_we}.c")
endforeach()

# 8. 追加编译选项到KBuild文件中
set(KBUILD_FILE "${KBUILD_FILE}\nccflags-y := -DMODULE_NAME=\\\"${PROJECT_NAME}\\\"")

# 9. 删除sources_relative列表后面的空格
message(WARNING ${sources_relative})
string(REGEX REPLACE "\n$" "" ${sources_relative} "${sources_relative}")
message(WARNING ${sources_relative})

# 10. 将前面${KBUILD_FILE}缓存的数据写入到Kbuild文件中
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/Kbuild ${KBUILD_FILE})

# 11. 创建一个custom_command命令,用于构建内核模块
add_custom_command(OUTPUT ${MODULE_FILE}
  COMMAND ${KBUILD_CMD}
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
  DEPENDS ${sources_relative} VERBATIM)
# 12. 创建一个构建目标
add_custom_target(${PROJECT_NAME} ALL DEPENDS ${MODULE_FILE})

需要说明的地方有几个:

1. 这里会遍历src目录下的所有.c文件并将它们分别编译成目标文件,如果有些不想要编译的,可以改名,或者在遍历那块把对应的文件忽略掉;

2. 因为目标文件名称带了src/,所以后面要想对某个目标文件进行设置某些编译参数之类的,需要把src/带上,这里因为有俩目标文件使用了fpu相关计算,需要开启msse等支持。

第二种方法是保留makefile,只是在cmake中使用cmake支持的make命令,设定执行make的目录名称即可。

##############################
### build kernel #### 
##############################

SET(SCENE_MODULE_NAME ./episode module/episode.ko)## build kernel module ####
add_custom_target(build_kernel All
    COMMAND${CMAKE_MAKE_PROGRAM}&& rm -rf *.o *.mod.c *.symvers *.order *.make *.mod. *.cmd. *.tmp
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/episode_module/
    COMMENT "Clean kernel module of Episode makefile target")
## make insmod to install module #### 
add custom target(insmod COMMAND
    COMMAND make insmod
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/episode module/ 
    COMMENT "Oriainal kernel module of Episode makefile target")

#################1############## install module to path ##################################
SET(SCENE MODULE_PATH ${CMAKE_SYSTEM_VERSION})
MESSAGE("The System Version:${SCENE_MODULE_PATH}")
install(PROGRAMSS{SCENE_MODULE_NAME} DESTINATION lib/kernel/${SCENE_MODULE_PATH})

第三种,

cmake_minimum_required(VERSION 3.4.2)
PROJECT(scene_storage)

include(XXX.cmake)
include(./yyy.cmake)


execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/episode_module)
##############################
### build kernel          ####
##############################

set(KERNEL_DIR /usr/src/linux-headers-${CMAKE_SYSTEM_VERSION})
set(SCENE_MODULE_NAME ${CMAKE_CURRENT_BINARY_DIR}/episode_module/episode.ko)

add_custom_target(episode ALL cp -f ${CMAKE_CURRENT_SOURCE_DIR}/episode_module/*.c ${CMAKE_CURRENT_BINARY_DIR}/episode_module/
    COMMAND cp -f  ${CMAKE_CURRENT_SOURCE_DIR}/episode_module/*.h ${CMAKE_CURRENT_BINARY_DIR}/episode_module/
    COMMAND cp -f  ${CMAKE_CURRENT_SOURCE_DIR}/episode_module/Makefile ${CMAKE_CURRENT_BINARY_DIR}/episode_module/
    COMMENT "Copy kernel module of Episode makefile target"
    
    COMMAND make -C ${KERNEL_DIR} M=${CMAKE_CURRENT_BINARY_DIR}/episode_module/ modules
    COMMENT "Make kernel module of Episode makefile target"

    COMMAND rm -rf *.o *.mod.c *.symvers *.order *.makers *.mod .*.cmd .*.tmp
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/episode_module/
    COMMENT "Clean kernel module of Episode makefile target"
    )

## make insmod to install module ####
add_custom_target(insmod COMMAND
    COMMAND make insmod
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/episode_module/
    COMMENT "Install kernel module of Episode makefile target")


##############################
## install module to path ####
##############################
SET(SCENE_MODULE_PATH ${CMAKE_SYSTEM_VERSION})
MESSAGE("The System Version:${SCENE_MODULE_PATH}")
install(PROGRAMS ${SCENE_MODULE_NAME} DESTINATION lib/kernel/${SCENE_MODULE_PATH})

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
有三种方法可以使用cmake编译内核模块。 第一种方法是在cmake使用add_custom_command和add_custom_target来实现编译。具体思路是将makefile中的obj-m和ALL伪目标以及make等操作都放到cmake中执行。 第二种方法是保留makefile,在cmake使用cmake支持的make命令,并指定执行make的目录名称。 第三种方法是在cmake文件中指定内核源代码的路径,然后使用cmake的命令来编译驱动或其他内核模块。 以上是三种常用的在cmake编译内核模块方法。您可以根据具体情况选择其中的一种来使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [使用cmake编译内核模块几种方法](https://blog.csdn.net/jinking01/article/details/128345501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [cmake(10):使用cmake编译linux驱动或内核模块](https://blog.csdn.net/rangfei/article/details/119352372)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值