注释

#

已有宏

PROJECT_SOURCE_DIR

使用 cmake 命令后紧跟的目录,一般是工程的根目录

CMAKE_CURRENT_SOURCE_DIR

当前处理的 CMakeLists.txt 所在的路径

EXECUTABLE_OUTPUT_PATH

用来指定生成文件路径,如果不存在该路径则会创建

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output)

搜索

aux_source_directory

查找某个路径下的所有源文件

aux_source_directory(< dir > < variable >)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)

dir:要搜索的目录
variable:将从 dir 目录下搜索到的源文件列表存储到该变量中

file

file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)

GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。(可选)

指定头文件路径

保证在编译过程中编译器能够找到这些头文件,并顺利通过编译。

include_directories(headpath)
include_directories(${PROJECT_SOURCE_DIR}/include)

生成可执行文件

cmake_minimum_required(VERSION 3.15)project(test) #cmake项目名

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output) #输出路径
include_directories(${PROJECT_SOURCE_DIR}/inc) #头文件
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC) #源文件
add_executable(app ${SRC}) #前者为生成的可执行文件名

生成库文件

静态库和动态库

  • 静态库在编译时将所有依赖的库代码直接链接到可执行文件中,使得程序独立性高但体积较大。
  • 动态库在运行时加载,允许程序共享库代码,有助于减小程序体积和节省系统资源,但需要确保运行环境中存在正确的库版本。

更新与维护

  • 静态库

    • 更新静态库后,所有使用该库的应用都需要重新编译和链接,以便包含新的库代码。
  • 动态库

    • 动态库可以在不重新编译应用的情况下进行更新,只要库的接口没有改变。这对于发布补丁或性能优化非常有用。

生成步骤

首先把 main.c 剔除出 src 文件夹,不让其包含在库中

cmake_minimum_required(VERSION 3.15)
project(test)

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) #库文件存放路径(不存在则创建)
include_directories(${PROJECT_SOURCE_DIR}/inc)
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
add_library(test SHARED ${SRC}) #生成动态库 库文件将被命名为libtest.so
#add_library(test STATIC ${SRC}) #生成静态库(默认)库文件将被命名为libtest.a

链接库文件

链接静态库

target_link_librarieslink_libraries 均可
前者更好

cmake_minimum_required(VERSION 3.15)
project(test)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output)
include_directories(${PROJECT_SOURCE_DIR}/inc)
aux_source_directory(${PROJECT_SOURCE_DIR} SRC) 
#除库文件以外的源文件(包括mian.c)
#link_libraries(test) 
#库的名字(可以只写中间部分,也可以全名)
link_directories(${PROJECT_SOURCE_DIR}/lib) 
#自定义库的路径
add_executable(app ${SRC})
target_link_libraries(app test)#要放在最后

链接动态库

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output)
include_directories(${PROJECT_SOURCE_DIR}/inc)
aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
link_directories(${PROJECT_SOURCE_DIR}/lib) #要在add_...之前
add_executable(app ${SRC})
target_link_libraries(app test pthread)#要放在最后

链接多个库

如果多个库之间存在依赖关系,确保按照正确的顺序列出库名称。通常,被依赖的库应该放在后面

cmake_minimum_required(VERSION 3.15)
project(test)set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output)
include_directories(${PROJECT_SOURCE_DIR}/inc)
aux_source_directory(${PROJECT_SOURCE_DIR} SRC)# 自定义库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
add_executable(app ${SRC})# 链接多个静态库
target_link_libraries(app
    lib1  # 第一个库的名字
    lib2  # 依赖lib3
    lib3  # 被lib2依赖
)

静态库动态库混合

如果同时需要链接动态库和静态库,同样可以在 target_link_libraries 中一并列出。

有多个库路径

link_directories(
    ${PROJECT_SOURCE_DIR}/lib1
    ${PROJECT_SOURCE_DIR}/lib2
    ${PROJECT_SOURCE_DIR}/lib3
)

寻找加载库文件

find_library
第一个参数:找到的库文件的路径
第二个参数:库文件名
第三个参数:固定为 PATHS
第 4 - …个参数:查找的路径

find_library(TEST_LIB test PATHS
        ${PROJECT_SOURCE_DIR}/libs 
        /usr/local/lib)
add_executable(app main.c)
target_link_libraries(app ${TEST_LIB})

消息通知

message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
message("test")
message(STATUS "check1")
message(FATAL_ERROR "error")

打印如下

test
-- check1
CMake Error at CMakeLists.txt:29 (message):
  error

(无) :重要消息
STATUS :非重要消息
WARNING:CMake 警告, 会继续执行
AUTHOR_WARNING:CMake 警告 (dev), 会继续执行
SEND_ERROR:CMake 错误, 继续执行,但是会跳过生成的步骤
FATAL_ERROR:CMake 错误, 终止所有处理过程

添加宏

C/C++ 中未赋值的宏默认为 1

add_definitions(-D宏名称)
add_definitions(-DMY_MACRO=2)
add_definitions(-DDEBUG)

项目中 cmake

project_name/
├── src/                # 存放源代码文件
│   ├── CMakeLists.txt  # 构建脚本
│   ├── main.c          # 主程序入口
│   ├── module1.c       # 模块1的实现
│   ├── module2.c       # 模块2的实现
│   └── utils.c         # 工具函数实现
├── include/            # 存放头文件(.h)
│   ├── module1.h       # 模块1的声明
│   ├── module2.h       # 模块2的声明
│   └── utils.h         # 工具函数声明
├── lib/                # 存放第三方库或静态库文件
│   ├── libxyz.a        # 静态库文件
│   └── xyz.h           # 第三方库头文件
├── tests/              # 存放测试代码
│   ├── CMakeLists.txt  # 构建脚本
│   ├── test_module1.c  # 测试模块1
│   └── test_utils.c    # 测试工具函数
├── docs/               # 存放文档(如设计文档、API文档等)
│   ├── design.md       # 设计文档
│   └── api.md          # API文档
├── build/              # 编译生成的中间文件和目标文件
├── bin/                # 存放最终生成的可执行文件
├── CMakeLists.txt      # 构建脚本
├── README.md           # 项目说明文档
└── LICENSE             # 项目许可证

cmake 文件结构

每一个有源文件的地方都要有一个 cmake 文件

项目根目录中

cmake_minimum_required(VERSION 3.15)
project(test)
set(EXE_PATH ${PROJECT_SOURCE_DIR}/bin)
set(INC_PATH ${PROJECT_SOURCE_DIR}/inc)
set(LIB_PATH ${PROJECT_SOURCE_DIR}/lib)
# 设置名字
set(APPNAME app)
set(APPNAME1 test1)
set(APPNAME2 test2)
set(LIBAD ad)
set(LIBDI di)
#设置子目录
add_subdirectory(src)
add_subdirectory(ad)
add_subdirectory(di)
add_subdirectory(tests)

生成库文件

set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
aux_source_directory(${PROJECT_SOURCE_DIR}/di SRC)
include_directories(${INC_PATH})
add_library(${LIBDI} SHARED ${SRC})

生成可执行文件

set(EXECUTABLE_OUTPUT_PATH ${EXE_PATH})
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
include_directories(${INC_PATH})
link_directories(${LIB_PATH})
add_executable(${APPNAME} ${SRC})
target_link_libraries(${APPNAME} ${LIBAD} ${LIBDI} pthread)

生成测试文件

set(EXECUTABLE_OUTPUT_PATH ${EXE_PATH})
#include_directories(${INC_PATH})
link_directories(${LIB_PATH})
add_executable(${APPNAME1} test1.c) #分别生成执行文件
add_executable(${APPNAME2} test2.c)
target_include_directories(${APPNAME1} PUBLIC ${INC_PATH})# 分别链接各自头
target_include_directories(${APPNAME2} PUBLIC ${INC_PATH})
target_link_libraries(${APPNAME1} ${LIBAD}) # 分别链接库
target_link_libraries(${APPNAME2} ${LIBDI} pthread)

交叉编译

  • 项目文件下创建文件声明交叉编译链 arm.cmake
# 目标系统名称
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_STANDARD 99)
# 指定交叉编译器路径
set(TOOLCHAIN_DIR /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-)
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}g++)

查看交叉编译器路径方法:

which arm-linux-gnueabihf-gcc
  • 在 build 目录下 cmake
cmake -DCMAKE_TOOLCHAIN_FILE=./../arm.cmake ..
  • 正常 make

查看生成文件是什么架构:

file ../bin/app