cmake 系列使用教程
cmake 使用教程(一)- 起步
cmake 使用教程(二)- 添加库
cmake 使用教程(三)- 安装测试系统自检
cmake 使用教程(四)- 文件生成器
cmake 使用教程(五)-cpack 生成安装包
cmake 使用教程(六)- 蛋疼的语法
cmake 使用教程(七)- 流程和循环
cmake 使用教程(八)-macro 和 function
这个系列的文章翻译自官方 cmake 教程: cmake tutorial
示例程序地址: github.com/rangaofei/t
不会仅仅停留在官方教程本人作为一个安卓开发者, 实在是没有 linux c 程序开发经验, 望大佬们海涵教程是在 macos 下完成, 大部分 linux 我也测试过, 有特殊说明的我会标注出来本教程基于 cmake-3.10.2, 同时认为你已经安装好 cmake
cmake 中有两个相似的关键字, macro 和 function 这两个都是创建一段有名字的代码稍后可以调用, 还可以传参数
macro 宏定义与 function 函数的相同点
macro 形式如下:
- macro(<name> [arg1 [arg2 [arg3 ...]]])
- COMMAND1(ARGS ...)
- COMMAND2(ARGS ...)
- ...
- endmacro(<name>)
function 形式如下:
- function(<name> [arg1 [arg2 [arg3 ...]]])
- COMMAND1(ARGS ...)
- COMMAND2(ARGS ...)
- ...
- function(<name>)
定义一个名称为 name 的宏 (函数),arg1... 是传入的参数我们除了可以用 ${arg1} 来引用变量以外, 系统为我们提供了一些特殊的变量:
变量 | 说明 |
---|---|
ARGV# | # 是一个下标,0 指向第一个参数,累加 |
ARGV | 所有的定义时要求传入的参数 |
ARGN | 定义时要求传入的参数以外的参数,比如定义宏(函数)时,要求输入 1 个,书记输入了 3 个,则剩下的两个会以数组形式存储在 ARGN 中 |
ARGC | 传入的实际参数的个数,也就是调用函数是传入的参数个数 |
macro 宏定义与 function 函数的不同点
宏的 ARGNARGV 等参数不是通常 CMake 意义上的变量 它们是字符串替换, 很像 C 预处理器对宏的处理 因此, 如下命令是错误的:
- if(ARGV1) # ARGV1 is not a variable
- if(DEFINED ARGV2) # ARGV2 is not a variable
- if(ARGC GREATER 2) # ARGC is not a variable
- foreach(loop_var IN LISTS ARGN) # ARGN is not a variable
正确写法如下:
- if(${ARGV1})
- if(DEFINED ${ARGV2})
- if(${ARGC} GREATER 2)
- foreach(loop_var IN LISTS ${ARGN})
- or
- set(list_var "${ARGN}")
- foreach(loop_var IN LISTS list_var)
一个简单的例子
- macro(FOO arg1 arg2 arg3)
- message(STATUS "this is arg1:${arg1},ARGV0=${ARGV0}")
- message(STATUS "this is arg2:${arg2},ARGV1=${ARGV1}")
- message(STATUS "this is arg3:${arg3},ARGV2=${ARGV2}")
- message(STATUS "this is argc:${ARGC}")
- message(STATUS "this is args:${ARGV},ARGN=${ARGN}")
- if(arg1 STREQUAL one)
- message(STATUS "this is arg1")
- endif()
- if(ARGV2 STREQUAL "two")
- message(STATUS "this is arg2")
- endif()
- set(${arg1} nine)
- message(STATUS "after set arg1=${${arg1}}")
- endmacro(FOO)
- function(BAR arg1)
- message(STATUS "this is arg1:${arg1},ARGV0=${ARGV0}")
- message(STATUS "this is argn:${ARGN}")
- if(arg1 STREQUAL first)
- message(STATUS "this is first")
- endif()
- set(arg1 ten)
- message(STATUS "after set arg1=${arg1}")
- endfunction(BAR arg1)
- set(p1 one)
- set(p2 two)
- set(p3 three)
- set(p4 four)
- set(p5 five)
- set(p6 first)
- set(p7 second)
- FOO(${p1} ${p2} ${p3} ${p4} ${p5})
- BAR(${p6} ${p7})
- message(STATUS "after bar p6=${p6}")
输出结果如下:
- -- this is arg1:one,ARGV0=one
- -- this is arg2:two,ARGV1=two
- -- this is arg3:three,ARGV2=three
- -- this is argc:5
- -- this is args:one;two;three;four;five,ARGN=four;five
- -- after set arg1=nine
- -- this is arg1:first,ARGV0=first
- -- this is argn:second
- -- this is first
- -- after set arg1=ten
- -- after bar p6=first
接下来看一个让我们蛋都能疼碎了的例子, 简直不想用 cmake:
- macro(_bar)
- foreach(arg IN LISTS ARGN)
- message(STATUS "this is in macro ${arg}")
- endforeach()
- endmacro()
- function(_foo)
- foreach(arg IN LISTS ARGN)
- message(STATUS "this in function is ${arg}")
- endforeach()
- _bar(x y z)
- endfunction()
- _foo(a b c)
看一下输出:
- -- this in function is a
- -- this in function is b
- -- this in function is c
- -- this is in macro a
- -- this is in macro b
- -- this is in macro c
就是这么蛋疼, 我们传给了_bar(x y z), 结果打印出来的是 a b c, 那我们把第二行的 foreach 改成
foreach(arg IN LISTS ${ARGN})
, 看一下结果:
- -- this in function is a
- -- this in function is b
- -- this in function is c
没有输出_bar 中的信息为啥? 因为这个 ARGN 的作用域是在 function 中的, 也就是_foo 函数中的那个 ARGN 有兴趣的话可以试试在 macro 中调用 function
来源: https://juejin.im/post/5a8ab0e4f265da4e9d223972