没志青年
发布于 2025-06-14 / 20 阅读
0

CMake

项目配置

cmake_minimum_required(VERSION 3.0)  # 最低 cmake 版本
project(app C) # 项目名称和开发语言
add_executable(可执行文件名称 源文件) # 生成可执行文件

指定C++标准

方法1
set(CMAKE_CXX_STANDARD 11)
​
方法2 使用命令时指定
cmake CMakeLists.txt -DCMAKE_CXX_STANDARD=14

指定输出路径

set(EXECUTABLE_OUTPUT_PATH 完整路径)

注意:指定相对路径的话就是 Makefile 所在的目录而言

变量与LIST

定义变量

写法1
set(SRC_LIST add.c  div.c   main.c  mult.c  sub.c)
​
写法2
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)

使用变量

${变量名}

变量拼接

写法1
set(新的变量名 ${变量名1} ${变量名2} ...)

写法2
list(APPEND 新的变量名 ${变量名1} ${变量名2} ...)

移除字符串

list(REMOVE_ITEM 变量 要移除的那个文件)

引入源文件

可以在 add_executable 中手动添加文件,但是不推荐。

方法1
aux_source_directory(选择的目录 将这些文件存储到哪个变量中)
​
方法2
file(GLOB或者GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)

file("") 双引号可加可不加

  • GLOB:不递归搜索

  • GLOB_RECURSE:递归搜索

对于file第二个参数,使用通配符

/src/*.cpp

引入头文件

include_directories(头文件所在路径)

路径使用空格隔开,但是推荐使用多个 include_directories,或是换行

库文件制作

不仅可以制作可执行文件,还可以制作库文件。

静态库与动态库?

  • 静态库:在编译时直接链接到可执行文件中,程序可直接执行而不依赖外部的库文件。

    • Windows:.lib

    • Linux:.a

  • 动态库:编译时不会链接到可执行文件中,而是在程序启动或运行时动态的加载库文件。因此想让程序运行,除了可执行文件,还得有这些库。

    • Windows:.dll

    • Linux:.so

优缺点显而易见:

系统库与第三方库?

  • 系统库:

  • 第三方库:你自己写的库,或者从网上下载的库,除了系统库呗。

静态库制作

add_library(库名称 STATIC 库文件(多个使用空格隔开,可使用变量))

linux中:lib库名称.a

指定输出路径

只能
set(LIBRARY_OUTPUT_PATH 路径)

动态库制作

add_library(库名称 SHARED 库文件(多个使用空格隔开,可使用变量))

linux中:lib库名称.so

指定输出路径

set(EXECUTABLE_OUTPUT_PATH 路径)
或者
set(LIBRARY_OUTPUT_PATH 路径)

引入库文件

手动引入

【cmake学习】cmake 引入第三方库(头文件目录、库目录、库文件)_cmake添加第三方库-CSDN博客

注意,链接库一定要放在 add_executable 后面!!!

库的名称可以是 libxxx.a 也可以是 xxx

引入库路径,如果你需要系统库就不用填这个

link_directories(库的路径)

引入库文件,这里指定的是全局默认库,所有工程都会链接到。

link_libraries(库名称)

一个项目中的多个工程使用的库可能不一样,使用全局默认库的话,对于那些不需要的库也链接进去了,占空间。

target_link_libraries 可以指定某个工程需要哪些库文件。

这个一定要放在 add_executable 后面,因为你只有指定了项目的可执行文件或库,才能去给它分配库。

target_link_libraries(工程名
    第一个库文件
    第二个库文件
    ...
)

也可以使用空格隔开

批量引入

手动引入麻烦了,要写一大堆。

打印日志

相当于 printf()

message(等级 "字符串")

等级

说明

STATUS

WARNING

AUTHOR_WARNING

SEND_ERROR

FATAL_ERROR

添加宏定义

add_definitions(-D宏名称)

// 例如需要 DENUG 这个宏
add_definitions(-DDEBUG)

使用宏定义可以

CMake宏

功能

PROJECT_SOURCE_DIR

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

PROJECT_BINARY_DIR

执行cmake命令的目录

CMAKE_CURRENT_SOURCE_DIR

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

CMAKE_CURRENT_BINARY_DIR

target 编译目录

EXECUTABLE_OUTPUT_PATH

重新定义目标二进制可执行文件的存放位置

LIBRARY_OUTPUT_PATH

重新定义目标链接库文件的存放位置

PROJECT_NAME

返回通过PROJECT指令定义的项目名称

CMAKE_BINARY_DIR

项目实际构建路径,假设在build目录进行的构建,那么得到的就是这个目录的路径

CMake嵌套

对于复杂的需要分层的项目,就要用到 CMake 嵌套,和 Maven 一个道理。

在工程的主目录下有一个 CMakeLists.txt,称为父节点,同时在项目的不同子目录中也有很多 CMakeLists.txt,称为子节点。

子节点可以使用父节点的变量,父节点不能使用子节点的变量,经常在父节点中定义全局变量。

在父节点中

add_subdirectory(子目录路径 [binary_dir] [EXCLUDE_FROM_ALL])
​
binary_dir:指定了输出文件的路径,一般不需要指定,忽略即可。
EXCLUDE_FROM_ALL:在子路径下的目标默认不会被包含到父路径的ALL目标里,并且也会被排除在IDE工程文件之外。用户必须显式构建在子路径下的目标。

子节点只关心它的目录,和之前的一样,只不过可以使用父节点中的变量了。

流程控制

条件判断

if(条件)
  ...
elseif(条件1)
  ...
else()
  ...
endif()

elseif和else可选

条件表达式

逻辑

NOT 条件

条件1 AND 条件2

条件1 OR 条件2

大小

文件

是否存咋

if(EXISTS path-to-file-or-directory)

是不是目录

if(IS_DIRECTORY path)

是不是软链接

if(IS_SYMLINK file-name)

是不是绝对路径

if(IS_ABSOLUTE path)

其它

是否在列表中

v >= 3.3

if(<variable|string> IN_LIST <variable>)

路径是否相等

v >= 3.24

if(<variable|string> PATH_EQUAL <variable|string>)

也可以直接使用字符串比较

循环

foreach

foreach(变量 源)
    ....
endforeach()

while

while(<condition>)
    <commands>
endwhile()

while(${LEN} GREATER  0)
    message(STATUS "names = ${NAME}")
    # 弹出列表头部元素
    list(POP_FRONT NAME)
    # 更新列表长度
    list(LENGTH NAME LEN)
endwhile()
​


交叉编译

例如交叉编译工具链使用的是 arm-linux-gnueabihf

# 指定目标平台和芯片架构
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
​
# 交叉编译工具链所在路径
set(CMAKE_FIND_ROOT_PATH /home/toolchain/arm)
​
# 指定交叉编译工具
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as)
​
# 只在当前系统下查找可执行文件,不考虑目标系统路径
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# 只从目标系统路径中查找库文件,不考虑主机系统路径
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
# 只从目标系统路径中查找头文件,不考虑主机系统路径。
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
​
# 设置编译器标志,这里要根据不同的芯片架构进行修改
set(CMAKE_C_FLAGS "-mcpu=cortex-a7 -mthumb")
set(CMAKE_CXX_FLAGS "-mcpu=cortex-a7 -mthumb")

CMAKE_FIND_ROOT_PATH 是一个变量,可以设置,用于指定目标平台的根目录。

比如你要交叉编译到 ARM32位架构的芯片,你把你要用到的该平台的库、头文件和其他资源放在这里。

设置了这些参数,CMake就不会乱找了,有可能你需要a文件,结果虚拟机上库中也有a文件,那就会引起变编译错误。

交叉编译模板

cmake_minimum_required(VERSION 3.10)
project(mycrossapp)

file(GLOB SRC_LIST ${PROJECT_BINARY_DIR}/*.cpp)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 交叉编译配置
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_FIND_ROOT_PATH /Embbed_WorkSpace/ARM_TOOLCHAIN/arm-linux-gnueabihf-7.5.0)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_C_FLAGS "-mcpu=cortex-a7 -mthumb")
set(CMAKE_CXX_FLAGS "-mcpu=cortex-a7 -mthumb")

include_directories(
	${PROJECT_BINARY_DIR}/lib/ffmpeg/include
)

link_directories(
    ${PROJECT_BINARY_DIR}/lib/ffmpeg/lib
)

add_executable(mycrossapp${SRC_LIST})

target_link_libraries(mycrossapp
    PRIVATE
    
    avcodec
    avformat
    swscale
    avutil
    swresample
)