cmake(10):使用cmake编译linux驱动或内核模块

本文介绍如何使用CMake工具构建Linux驱动程序,并提供了一个具体的示例。通过定义编译函数和利用CMake命令,可以有效地将驱动和应用程序整合在一起进行构建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 说明

这篇笔记用于说明如何使用cmake构建Linux驱动,这样可以方便地将driver和app作为一个整体统一构建。

2. 示例

首先来看一个代码示例,为了简化起见,我直接在驱动目录下进行构建而没有作为子目录添加到软件工程内。

cmake_minimum_required (VERSION 3.0.0)
project(driver_demo)

# 由于我的系统更新过内核,所以这里需要设置内核源代码路径
set(KDIR /home/linux/linux-5.12)

# 定义编译函数/方法,驱动编译过程主要在这个函数进行
function(compile_module obj)
  set(TARGET_NAME ${obj})
  # 添加目标,obj即为模块名称。由于我在build目录下构建,所以这里选择将.c和.h文件拷贝到该目录下
  add_custom_target(${TARGET_NAME} ALL cp -f ${CMAKE_CURRENT_SOURCE_DIR}/*.c ${CMAKE_CURRENT_BINARY_DIR}/
			COMMAND cp -f ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_BINARY_DIR}/
  			COMMAND echo "compiling module ${obj}.ko..."
  		    )

  # 设置依赖,相当于Makefile中的 $(MODULE_NAME)-objs += demo_main.o
  set(depend_objlist "demo_main.o")
  
  # 设置编译命令
  add_custom_command(TARGET ${TARGET_NAME}
		     POST_BUILD
		     COMMAND echo "obj-m := ${obj}.o" > ${CMAKE_CURRENT_BINARY_DIR}/Makefile
		     COMMAND echo "${obj}-objs:=${depend_objlist}" >>${CMAKE_CURRENT_BINARY_DIR}/Makefile
		     COMMAND make -C ${KDIR} M=${CMAKE_CURRENT_BINARY_DIR} modules
		     )
endfunction()

# 调用编译函数
compile_module(demo)

这里写了一个简单的demo driver,除了demo_main.c文件外不依赖于其他.c。注意,在编译驱动或其他内核模块时,虽然在本地目录进行make,但在实际编译的过程中会进入Linux kernel,所以如何重新编译过系统内核,需要在cmake文件中指定kernel source code的路径。

编译

mkdir build && cd build
cmake ..
make or make demo


3. 命令解析

function

这个命令类似于函数封装,可以将一系列命令封装成一个方法,后续只要调用该方法就行。其格式如下:

function(<name> [<arg1> ...])
  <commands>
endfunction()
  • 以function()开头,endfunction()结束
  • name : 函数名称
  • arg… : 该函数使用的参数
  • commands : 函数内部调用的命令,只有函数被调用时,这些命令才会运行

除了使用固定的arg变量,还可以使用argc和argv来表示可变参数,此时argc代表参数个数,argv则是参数列表,里面的值分别用argv0, argv1 …表示。

add_custom_target

这个命令用于添加一个始终会被构建的目标,该目标可以在make中执行,类似于make all/clean之类的命令。比如上述示例中,make demo的demo既是模块名称,也是目标名称。

这个命令与后面要说的add_custom_command有紧密联系,其格式如下:

add_custom_target(Name [ALL] [command1 [args1...]]
                  [COMMAND command2 [args2...] ...]
                  [DEPENDS depend depend depend ... ]
                  [BYPRODUCTS [files...]]
                  [WORKING_DIRECTORY dir]
                  [COMMENT comment]
                  [JOB_POOL job_pool]
                  [VERBATIM] [USES_TERMINAL]
                  [COMMAND_EXPAND_LISTS]
                  [SOURCES src1 [src2...]])
  • Name : 目标名称,注意Name并不是可以任意设置的,有些cmake内置的命令或关键字不能使用,如:ALL, install, clean等
  • ALL : 表示此目标会被添加进默认的构建目标。(不是很明白这句话的意思,但似乎每一个add_custom_target都会有一个这样的参数)
  • COMMAND : 表示在构建时要运行的命令(该命令可以是shell命令,也可以是可执行文件),如果有多条,那么会按顺序依次执行
  • DEPENDS : 引用add_custom_command命令创建的依赖。(没用过,也不懂)
  • BYPRODUCTS : 指定命令要生成的文件
  • WORKING_DIRECTORY : 指定本命令运行时对应的目录
  • COMMENT : 在执行命令时输出的信息,类似于debug…
  • JOB_POOL : Specify a pool for the Ninja generator. Incompatible with USES_TERMINAL, which implies the console pool. Using a pool that is not defined by JOB_POOLS causes an error by ninja at build time.
  • VERBATIM : 对于有转义字符时,建议使用此参数,确保该字符会被正确转义。否则,解析时可能因平台差异而不同。
  • USES_TERMINAL : 赋予命令直接访问终端的权限。
  • COMMAND_EXPAND_LISTS : 扩展COMMAN参数中的列表,包括使用生成器表达式创建的列表。
  • SOURCES : 执行命令执行所需的额外的源文件

注: 我在测试这个命令的时候,发现如果有多个add_custom_target,那么生成的Makefile只能执行其中一个命令。

add_custom_command

这个命令用于为当前的编译系统添加编译规则,有两个主要用法,一种生成输出文件,另一种针对目标命令。上例中就是第二种情形。

生成文件

格式如下:

add_custom_command(OUTPUT output1 [output2 ...]
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [MAIN_DEPENDENCY depend]
                   [DEPENDS [depends...]]
                   [BYPRODUCTS [files...]]
                   [IMPLICIT_DEPENDS <lang1> depend1
                                    [<lang2> depend2] ...]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [DEPFILE depfile]
                   [JOB_POOL job_pool]
                   [VERBATIM] [APPEND] [USES_TERMINAL]
                   [COMMAND_EXPAND_LISTS])

针对目标

第二种方式对于构建目标非常有用,可以作为目标的一部分,在构建之前或之后执行。注意,目标必须与此命令在同一目录(同一CMakeLists.txt)下。

add_custom_command(TARGET <target>
                   PRE_BUILD | PRE_LINK | POST_BUILD
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [BYPRODUCTS [files...]]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [VERBATIM] [USES_TERMINAL]
                   [COMMAND_EXPAND_LISTS])
  • PRE_BUILD : 在构建目标之前运行
  • PRE_LINK : 在源代码编译之后但是链接二进制文件或静态库之前运行
  • POST_BUILD : 在目标构建之后运行

参考链接

利用CMake编译内核模块
CMake Documentation

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翔底

您的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值