cmake使用和参数分析

本文详细介绍了CMake的基础用法,包括如何进行交叉编译、设置编译选项、预定义变量的使用,以及cmake编译宏、函数和高级技巧。通过实例演示了添加执行文件和库编译、指定输出路径、宏定义和依赖管理等关键步骤。

cmake入门实战
使用 cmake 进行交叉编译
CMake 编译选项设置
cmake时添加-fPIC编译选项
cmake官网和官方文档

一、预定义变量

1、宏

CMAKE_CXX_STANDARD 设置gcc标准,-std=c++11
PROJECT_SOURCE_DIR 工程的根目录
PROJECT_BINARY_DIR 运行cmake命令时所在的目录
CMAKE_INCLUDE_PATH 环境变量
CMAKE_LIBRARY_PATH
CMAKE_CURRENT_SOURCE_DIR 当前在处理的CMakeLists.txt所在目录
CMAKE_CURRENT_BINARY_DIR target编译目录
CMAKE_CURRENT_LIST_FILE 调用这个变量的CMakeLists.txt所在的完整路径
CMAKE_CURRENT_SOURCE_DIR CMakeLists.txt所在的完整路径

2、文件设置

# 设置编译模式,debug/release
set(CMAKE_BUILD_TYPE "Debug")
# debug/release的编译选项
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
# 也可以直接设置编译选项
set(CMAKE_CXX_FLAGS ...)
# 设置编译器
# 这两条命令应该放在文件的开始位置(cmake_minimum_required命令之下,其他命令之上),否则可能无效
set (CMAKE_C_COMPILER "/usr/local/gcc/bin/gcc")
set (CMAKE_CXX_COMPILER "/usr/local/gcc/bin/g++")

3、支持的flags变量

CMAKE_C_FLAGS			:C语言编译器选项,对应于环境变量CFLAGS
CMAKE_CXX_FLAGS			:C++语言编译器选项,对应于环境变量CXXFLAGS
CMAKE_CUDA_FLAGS		:CUDA语言编译器选项,对应于环境变量CUDAFLAGS
CMAKE_Fortran_FLAGS		:Fortran语言编译器选项,对应于环境变量FFLAGS

二、cmake编译宏

宏:-D 在命令行使用-D定义宏,在CMakeLists.txt里面可以用set定义宏
CMAKE_CXX_COMPILER 指定c++编译工具
CMAKE_CXX_FLAGS 指定c++编译参数,
CMAKE_C_COMPILER 指定c编译工具
CMAKE_C_FLAGS 指定c编译参数,相当于CFLAGS
CMAKE_TOOLCHAIN_FILE 指定cmake文件,这个文件可以定义一系列的CMAKE_前缀变量
CMAKE_INSTALL_PREFIX 指定cmkae的安装目录(make install)
CMAKE_CXX_STANDARD 指定g++的标准,用set的时候类似 –std=c++11
CMAKE_C_STANDARD指定gcc的标准,用set的时候类似 –std=c11
EXECUTABLE_OUTPUT_PATH 指定exe文件最终输出文件夹
LIBRARY_OUTPUT_PATH 指定lib文件最终输出文件夹

三、cmake的方法(函数)

findpackage()

add_definitions()
添加编译选项,多个可以用空格隔开,实际上可以用它来添加宏定义,添加-std=c++11/c11

add_compile_options(-std=c++11)
添加编译选项(gcc和g++都添加),类似CMAKE_CXX_FLAGS和CMAKE_C_FLAGS,

set()
设置一个变量,也可以用来定义宏,也可以定义其他的环境变量

add_dependencies(taget depend1 …)
给目标添加依赖,在编译目标前会先编译被依赖的目标,多个依赖用空格分开

aux_source_directory(dirname arg)
把指定文件夹下所有的源文件名列表加入到指定变量中

include(file)
导入其他CMakeLists.txt文件

file(cmd filename arg …) 对文件操作
cmd read/write/append/copy/rename/…

install()
安装,与CMAKE_INSTALL_PREFIX有关

四、自己创建函数(function)和宏(macro)

五、cmake语法if-else/while/foreach

六、cmake与/或/非

关键字:
and/or/not

七、CMakeLists.txt文件编辑

1、cmake版本要求

cmake_minimun_required(VERSION version)

2、添加一个可执行文件编译目标

add_executable(target sourcefile …)

3、添加一个动态/静态库的编译目标

add_library(target SHARED/STATIC sourcefile …)

4、给编译目标链接库

target_link_libraries(target –lxxx …)

5、设置变量(可以用这种方法定义宏,只针对宏有内容情况)

set(arg content)

例:

set(EXECUTABLE_OUTPUT_PATH dirname) # 指定exe文件最终的输出路径
set(LIBRARY_OUTPUT_PATH dirname) # 指定lib文件最终的输出路径

这2个设置一般是紧紧跟随同一个CMakeLists.txt文件的add_executable()/add_library()

6、定义宏,格式跟命令行一样

add_definitions(命令行定义宏样式)

例如:add_definitions(-DDEBUG)

7、包含子目录(包含子目录的CMakeLists.txt文件)

add_subdirectory(dirmane)

8、指定头文件扫描目录

include_directories(dirname)

9、指定库扫描目录

link_directories(dirname)

10、消息打印

# 输出非重要消息
message(STATUS "")
# 输出警告消息
message(WARNING "")
# ...

可以设置不同的消息等级,设置如下:

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

11、file命令

file(cmd filename arg1 arg2 ...)

12、在目录中查找所有源文件,文件列表存在variable中

aux_source_directory(<dir> <variable>)

13、在目录中扫描所有符合条件的文件,GLOB只有本地有效,GLOB_RECURSE子文件也有效

file(GLOB USER_LIBS_PATH ./src/*.cpp)
file(GLOB_RECURSE USER_LIBS_PATH ./src/*.cpp)
<think>我们正在讨论CMake中的可变参函数。根据引用[2]引用[3],CMake函数内部可以使用内置变量来处理可变参数,如ARGN、ARGC、ARGV等。 引用[4]提到,对于更复杂的参数解析,可以使用cmake_parse_arguments命令,但这里我们聚焦于基本可变参数处理。 核心点: 1. 在函数定义时,可以不指定具体参数,而在函数内部通过内置变量访问。 2. 内置变量: - ARGC: 传入函数的参数个数(包括命名参数可变参数) - ARGV: 所有参数的列表 - ARGN: 函数声明中没有被命名参数捕获的额外参数(即可变参数部分) 3. 在函数中,我们可以通过循环遍历ARGN来处理可变参数。 我们之前已经给出了两个例子:print_allcalculate_sum。下面将详细解释使用方法。 步骤: 1. 定义函数时,可以指定0个或多个命名参数,然后剩余的参数就是可变参数。 例如:function(my_func arg1 arg2) ... endfunction() 调用:my_func(A B C D) 则:arg1=A, arg2=B, ARGN就是CD。 2. 如果函数定义时没有命名参数,那么所有参数都在ARGN中。 3. 使用foreach循环处理ARGN中的每个参数。 4. 注意:如果参数中包含分号(表示列表),需要正确处理。在传递时,如果希望一个参数作为整体(包含分号),则用双引号括起来。 示例1:基本可变参函数 ```cmake function(print_args) # 打印参数个数 message("Number of arguments: ${ARGC}") # 打印所有参数 message("All arguments: ${ARGV}") # 打印可变参数部分(因为函数没有命名参数,所以ARGN等于ARGV) message("Extra arguments: ${ARGN}") # 遍历每个参数 foreach(arg IN LISTS ARGN) message("Processing argument: ${arg}") endforeach() endfunction() ``` 调用示例: ```cmake print_args(apple banana "cherry;date") ``` 输出: ``` Number of arguments: 3 All arguments: apple;banana;cherry;date Extra arguments: apple;banana;cherry;date Processing argument: apple Processing argument: banana Processing argument: cherry;date ``` 注意:第三个参数是一个包含分号的字符串,所以在遍历时它被视为一个整体。 示例2:带命名参数可变参数 ```cmake function(greet name) message("Hello, ${name}!") # 打印额外的参数 foreach(arg IN LISTS ARGN) message("Extra: ${arg}") endforeach() endfunction() ``` 调用: ```cmake greet("John" "How are you?" "Today is a good day.") ``` 输出: ``` Hello, John! Extra: How are you? Extra: Today is a good day. ``` 示例3:求函数(处理数字) 注意:CMake中数字也是字符串,需要转换为数字进行计算。可以使用math(EXPR ...) 引用[2]中提到,函数内部变量是处理可变参数的关键。 复杂情况:当需要解析关键字参数时,应使用cmake_parse_arguments(如引用[4]所述),但这是另一个话题。 常见问题及解决: - 问题1:如何区分没有参数参数? 答:使用ARGC判断个数,或者检查ARGN是否为空。 - 问题2:如何传递一个列表作为可变参数? 答:使用引号将列表括起来,这样它会被当作一个参数。在函数内部,如果需要将其拆分为列表,可以使用分号分隔或者使用list命令。 示例:传递一个列表 ```cmake set(my_list a b c) # 直接传递,则函数会收到三个参数 print_args(${my_list}) # 相当于 print_args(a b c) # 如果希望整个列表作为一个参数 print_args("${my_list}") # 相当于 print_args("a;b;c"),在函数内部通过${arg}得到的是字符串"a;b;c" ``` 因此,在函数内部,如果需要将这样的字符串当作列表处理,可以: ```cmake function(print_list_as_list) foreach(arg IN LISTS ARGN) # 将参数按分号拆分 list(LENGTH arg len) message("Argument has ${len} elements: ${arg}") # 或者遍历内部元素 foreach(item IN LISTS arg) message("Item: ${item}") endforeach() endforeach() endfunction() ``` 但是注意:这样会使得单个字符串参数(不含分号)也被拆分成单个元素的列表。 总结: 在CMake函数中使用可变参数,主要通过ARGN来获取额外的参数,并结合循环进行处理。同时要注意参数传递时列表的展开与引号的使用。 下面生成相关问题: </think>### CMake函数可变参数使用方法 在CMake中,可变参函数通过特殊内置变量处理不定数量参数,核心方法是使用`ARGN`捕获额外参数。以下是完整实现方法: #### 基础实现方法 ```cmake function(my_function fixed_arg) message("固定参数: ${fixed_arg}") message("额外参数数量: ${ARGC}") # 遍历可变参数 foreach(arg IN LISTS ARGN) message(" - 可变参数: ${arg}") endforeach() endfunction() # 调用示例 my_function("固定值" "可变1" "可变2" "可变3") ``` #### 核心变量说明 | 变量名 | 描述 | 示例 | |--------|------|------| | `ARGC` | 总参数数量 | 调用`func(a b c)`时值为`3` | | `ARGV` | 所有参数列表 | `a;b;c` | | `ARGN` | 命名参数后的可变参数 | `func(a b c)`中`ARGN`=`b;c` | | `ARGV0` | 位置参数1 | `func(a b c)`中值为`a` | | `ARGV1` | 位置参数2 | `func(a b c)`中值为`b` | #### 高级用法:带参数解析的可变参函数 ```cmake function(process_items) # 解析参数:--prefix为选项,--dir单值,ITEMS多值 include(CMakeParseArguments) set(options PREFIX) set(oneValueArgs DIR) set(multiValueArgs ITEMS) cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(PARSE_PREFIX) message("启用前缀模式") endif() message("目录: ${PARSE_DIR}") # 处理多值参数 foreach(item IN LISTS PARSE_ITEMS) message("处理项目: ${item}") endforeach() endfunction() # 调用示例 process_items( --PREFIX --DIR "/project/path" ITEMS "file1" "file2" "file3" ) ``` #### 关键技术要点 1. **参数捕获机制** 使用`${ARGN}`获取所有未命名参数,通过`foreach`循环处理可变参数列表[^2] 2. **作用域控制** 返回值需要使用`PARENT_SCOPE`显式传递: ```cmake function(sum out_var) math(EXPR total "0") foreach(n IN LISTS ARGN) math(EXPR total "${total} + ${n}") endforeach() set(${out_var} ${total} PARENT_SCOPE) endfunction() ``` 3. **参数验证技巧** 检查参数是否存在: ```cmake if(DEFINED ARGN) # 存在可变参数 endif() ``` 4. **特殊字符处理** 传递含分号的参数需用引号包裹: ```cmake my_function("value;with;semicolon") # 作为单个参数传递 ``` #### 实际应用场景 1. **文件批量处理** ```cmake function(process_files target) foreach(file IN LISTS ARGN) target_sources(${target} PRIVATE ${file}) endforeach() endfunction() process_files(my_app "main.cpp" "util.cpp" "lib/*.hpp") ``` 2. **多配置安装规则** ```cmake function(install_multi TYPE) foreach(item IN LISTS ARGN) install(${TYPE} ${item} DESTINATION bin) endforeach() endfunction() install_multi(FILES "app" "tool" CONFIGURATIONS Release Debug) ``` #### 常见问题解决方案 **问题:参数包含空值** 使用`if(DEFINED ...)`检查: ```cmake foreach(arg IN LISTS ARGN) if(DEFINED arg AND NOT arg STREQUAL "") # 有效参数处理 endif() endforeach() ``` **问题:嵌套调用参数传递** 使用引号保持参数结构: ```cmake function(outer) inner("${ARGN}") # 保持内部参数结构 endfunction() ``` > CMake的可变参机制提供了类似C语言的灵活性,配合`cmake_parse_arguments`可实现完整的命名参数支持[^4]。在大型项目中,合理使用可变参函数能显著简化构建脚本[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值