内建变量
# cmake -S source_dir -B build_dir
CMAKE_MINIMUM_REQUIRED(VERSION 3.14)
CMAKE_SOURCE_DIR # 顶层 CMakeLists.txt 所在目录
CMAKE_BINARY_DIR # build 目录
CMAKE_CURRENT_SOURCE_DIR # 当前处理的 CMakeLists.txt 在 src 中的目录
CMAKE_CURRENT_BINARY_DIR # 当前处理的 CMakeLists.txt 在 build 中的 目录
# 重点
PROJECT(APP)
APP_SOURCE_DIR # 同 CMAKE_SOURCE_DIR
APP_BINARY_DIR # 同 CMAKE_BINARY_DIR
PROJECT_SOURCE_DIR # 同 CMAKE_SOURCE_DIR
PROJECT_NAME # 项目名称
# 可执行文件输出路径
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 库文件输出路径
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 静态库输出路径
CMAKE_ARCHIVE_OUTPUT_DIRECTORY
# 动态库输出路径
CMAKE_LIBRARY_OUTPUT_DIRECTORY
# 可执行文件输出路径
CMAKE_RUNTIME_OUTPUT_DIRECTORY
# 给一个 target 指定编译宏
TARGET_COMPILE_DEFINITIONS(target _GNU_SOURCE)
# 添加宏定义
ADD_DEFINITIONS(-DDEFINE_NAME=define_value)
CMAKE_EXPORT_COMPILE_COMMANDS # 设置为 ON,导出编译命令
CMAKE_C_FLAGS # 编译 C 的选项
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -rdynamic -Wl,-rpath=.")
CMAKE_INSTALL_PREFIX # 安装目录前缀,INSTALL 目录的 dir 一次为相对目录
CMAKE_TOOLCHAIN_FILE # 工具链所在的文件,一般配置在 cmake -D 中,clion 要提前配置
# 通常为 ./build/arch/arm-linux-cross-compile.cmake
# 工具链文件
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") # For C code
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # For C++ code
# 搜索路径 library include ...
set(CMAKE_FIND_ROOT_PATH /home/xxx/linux/tool/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf)
# 只从指定的路径找,不从系统目录找 ONLY NEVER BOTH
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
cmake 内部常用命令
execute_process(${CMAKE_COMMAND} -E directory ${CMAKE_BINARY_DIR}/SYMVERS)
cmake -E touch ${CMAKE_BINARY_DIR}/test)
cmake shell 中常用命令
# build 某个目标, 来自 clion
# build/target 为 build 目录
# 也可以 make all / make clean / make xxx
# cmake 没有成功,使用 sudo
/bin/cmake --build /home/wjxh/learn/build/target --target clean -- -j 6
/bin/cmake --build /home/wjxh/learn/build/target --target timer -- -j 6
/bin/cmake --build /home/wjxh/learn/build/target --target all -- -j 6
/bin/cmake --build /home/wjxh/learn/build/target --target install -- -j 6
clion 编写 linux 驱动核心代码,活用 cmake -> Makefile
function(compile_module obj)
add_custom_target(${obj}
# 必须使用 CMAKE_CURRENT_SOURCE_DIR CMAKE_CURRENT_BINARY_DIR 进行拷贝
# 不能使用 shell 命令进行拷贝,或者可能因为没有刷新 cache
# CMAKE_CURRENT_SOURCE_DIR 可以从 build.make 查看实际效果
# step 1
COMMAND
cp -rfa ${CMAKE_CURRENT_SOURCE_DIR}/* ${CMAKE_CURRENT_BINARY_DIR}/
COMMAND
# ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/arm.symvers
${CMAKE_COMMAND} -E make_directory ${SYMVERS_DIR}
# 所有的 symbol 都放到 arm.symvers 中
COMMAND
# ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/arm.symvers ${CMAKE_CURRENT_BINARY_DIR}/
${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/../arm.symvers ${SYMVERS_DIR}/
)
add_custom_command(TARGET ${obj}
# step 2
PRE_BUILD COMMAND
${CMAKE_COMMAND} -E echo "compiling module ${obj}.ko..."
# 每一个 Makefile 最后都要加一个 空格,否则 会缺失 endif
# PRE_BUILD COMMAND
# ${CMAKE_COMMAND} -E echo ${symvers} >> ${CMAKE_CURRENT_BINARY_DIR}/Makefile
# step 3
COMMAND
export KERNEL_DIR=${LINUX_PATH} &&
export SYMVERS_DIR=${SYMVERS_DIR} &&
export KO_INC=${KO_INC} &&
export MODULE_PATH=${CMAKE_SOURCE_DIR}/infected/modules &&
make
# step 4
POST_BUILD COMMAND
${CMAKE_COMMAND} -E echo "compile module ${obj}.ko OK"
POST_BUILD COMMAND
${CMAKE_COMMAND} -E make_directory ${KO_DIR}
# ${CMAKE_CURRENT_LIST_DIR}
POST_BUILD COMMAND
${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/*.ko ${KO_DIR}/
POST_BUILD COMMAND
${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/*.symvers ${SYMVERS_DIR}/
# POST_BUILD COMMAND
# ${CMAKE_COMMAND} -E cat ${CMAKE_CURRENT_BINARY_DIR}/Module.symvers >> ${CMAKE_BINARY_DIR}/arm.symvers
)
# install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${module}${KO} DESTINATION drivers)
# -DDEBUG=TRUE 打开提示
# if (DEFINED DEBUG)
# 修改 DEBUG,而不是添加 或 删除
if (${DEBUG} STREQUAL "TRUE")
# 必须打开下面内容,编写 led.c 才会进行提示
aux_source_directory(. ${obj}_SRC)
add_executable(${obj}_exe ${${obj}_SRC})
endif()
endfunction()
macro(add_module_flag flags)
set (EXTRA_FLAGS "EXTRA_CFLAGS += ${flags}")
# set (symvers "KBUILD_EXTRA_SYMBOLS += ${CMAKE_CURRENT_BINARY_DIR}/*.symvers")
endmacro()
驱动的 Makefile
# CROSS_COMPILE ARCH PATH 都在 /etc/environment 中配置了,可以直接使用
# KERNEL_DIR 是从 CMAKE 中传过来的
# MODULE_PATH 也是从 CMAKE 传过来的
MODULE_NAME=spi_drv
ifneq ($(KERNELRELEASE), )
obj-m := $(MODULE_NAME).o
$(MODULE_NAME)-objs += spi.o
#${MODULE_NAME}-objs := platform.o
KBUILD_EXTRA_SYMBOLS += ${SYMVERS_DIR}/common.symvers
EXTRA_CFLAGS += -I${KO_INC}
else
PWD := $(shell pwd)
default:
make -C $(KERNEL_DIR) M=$(PWD) modules
# ${CROSS_COMPILE}strip -d *.ko
mv Module.symvers $(MODULE_NAME).symvers
clean:
make -C $(KERNEL_DIR) M=$(PWD) clean
rm -f *.c
rm -rf Module.s* modules.order *.markers .tmp_versions
endif
驱动的 CMakeLists.txt
compile_module(spi)