cmake 使用记录
CMake中宏和函数的参数ARGV ARGC ARGN
cmake中的宏(macro)和函数(function)都支持动态参数
变量ARGC记录传入的参数个数
变量ARGV0,ARGV1,…顺序代表传入的参数
变量ARGV则是一个包含所有传入参数的list
变量ARGN也是一个包含传入参数的list,但不是所有参数,而是指macro/function声明的参数之后的所有传入参数
#定义一个宏,显式声明了两个参数hello,world
macro(argn_test hello world)
MESSAGE(STATUS ARGV=${ARGV})
MESSAGE(STATUS ARGN=${ARGN})
MESSAGE(STATUS ARGV0=${ARGV0})
MESSAGE(STATUS ARGV1=${ARGV1})
MESSAGE(STATUS ARGV2=${ARGV2})
MESSAGE(STATUS ARGV3=${ARGV3})
endmacro()
调用宏时传入4个参数
argn_test(TOM JERRY SUSAN BERN)
==== output ====
-- ARGV=TOMJERRYSUSANBERN
-- ARGN=SUSANBERN
-- ARGV0=TOM
-- ARGV1=JERRY
-- ARGV2=SUSAN
-- ARGV3=BERN
CMake变量以及变量的引用
CMake中的变量无需声明,并且没有类型概念,这一点类似于python;变量可以认为都是全局的,哪怕在一个宏中定义的变量,也可以在宏的外面被访问到;所有的变量都是一个列表变量,下文在举例时会详细说明这一点;CMake对于变量是大小写敏感的。
在CMake中,有两种引用方式:对于变量值的引用,和直接引用这个变量本身,使用方式分别是:${varName} 和 varName。
(感觉像是指针)
CMake的宏与函数
同大多数脚本语言一样,CMake中也有宏和函数的概念,关键字分别为"macro"和"function",具体用法如下:
# 宏
macro( [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endmacro()
# 函数
function( [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endfunction()
以简单的求和函数为例,我们来看宏的一个示例:
macro(sum outvar)
set(_args ${ARGN})
set(result 0)
foreach(_var ${_args})
math(EXPR result "result+{_var}")
endforeach()
set(outvar{result})
endmacro()
sum(addResult 1 2 3 4 5)
message("Result is :${addResult}")
上面是一段求和宏定义,我们来解读一下代码:"${ARGN}“是CMake中的一个变量,指代宏中传入的多余参数。因为我们这个宏sum中只定义了一个 参数"outvar”,其余需要求和的数字都是不定形式传入的,所以需要先将多余的参数传入一个单独的变量中。当然,在这个示例中,第一行代码显得多余, 因为似乎没必要将额外参数单独放在一个变量中,但是建议这么做。对上面这个宏再进一步加强:如果我们想限制这个宏中传入的参数数目(尽管在这个宏中实际上 是不必要的),那么可以将宏改写一下:
macro(sum outvar)
set(_args ${ARGN})
list(LENGTH _args argLength)
if(NOT argLength LESS 4) # 限制不能超过4个数字
message(FATAL_ERROR "to much args!")
endif()
set(result 0)
foreach(_var ${ARGN})
math(EXPR result "result+{_var}")
endforeach()
set(outvar{result})
endmacro()
sum(addResult 1 2 3 4 5)
message("Result is :${addResult}")
而CMake中的函数(“function”)与宏唯一的区别就在于,函数不能像宏那样将计算结果传出来(也不是完全不能,只是复杂一些),并且函数中的变量是局部的,而宏中的变量在外面也可以被访问到,请看下例:
macro(macroTest)
set(test1 "aaa")
endmacro()
function(funTest)
set(test2 "bbb")
endfunction()
macroTest()
message("${test1}")
funTest()
message("${test2}")
==== output ====
aaa
运行这段代码后,只会打印出一条信息"aaa",由此可以看到宏与函数的区别
cmake函数参数解析 cmake_parse_arguments
如果我们向一个function传递list作为参数,在function中,形参会变成如下状况:
set(SRC)
list(APPEND SRC a.cpp b.cpp)
list(APPEND SRC c.cpp d.cpp)
function(tst_arguments src_list)
message("src_list = "${src_list})
endfunction()
message("SRC = "${SRC})
tst_arguments(${SRC})
==== output ====
SRC = a.cppb.cppc.cppd.cpp
src_list = a.cpp
很奇怪的是,这里的${SRC}在function外是完整的4个元素,而在function却只剩下了头一个元素(可能跟list的定长有关)。如果我们要传给function以n个源文件组成的list,这样显然不行。
一种简单的解决方法是使用ARGV,ARGC配合,他们的含义如同C/C++中main的argv和argc,分别代表参数和参数个数,使用如下方法解析参数:
function(tst_arguments src_list)
message("ARGC = "${ARGC})
message("ARGV = "${ARGV})
set(INDEX 0)
while(INDEX LESS ${ARGC})
message("ARG = "${ARGV${INDEX}})
math(EXPR INDEX "${INDEX} + 1")
endwhile()
endfunction()
tst_arguments(${SRC})
==== output ====
ARGC = 4
ARGV = a.cppb.cppc.cppd.cpp
ARG = a.cpp
ARG = b.cpp
ARG = c.cpp
ARG = d.cpp
最方便使用的是cmake的cmake_parse_arguments来解析函数参数,它有点像解析一个map键值对,首先看下它的函数原型:
#必须包含这个cmake文件才能使用
include (CMakeParseArguments)
cmake_parse_arguments (<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
首先,prefix是一个前缀,等会儿在引用参数的时候会提到,是一个列表,里面可以包含一些你感兴趣的KeyWord,随后可以通过它来看看你所需要的KeyWord是否被设置。<one_value_keywords>是一个单值参数的KeyWord列表。<multi_value_keywords>是一个多值参数的KeyWord列表(如list),下面举个例子,看看如何使用它们,首先定义所需要的函数,由于参数是由cmake_parse_arguments 来解析的,所以在函数声明中就不需要定义参数了:
function(tst_arguments)
CMAKE_PARSE_ARGUMENTS( TEST "" "NAME;COMMAND;BASELINE" "ARGSLIST" ${ARGN} )
message("TEST_DEFAULT_ARGS is ${TEST_DEFAULT_ARGS} from ${ARGN}")
message("TEST_NAME is ${TEST_NAME}")
message("TEST_COMMAND is ${TEST_COMMAND}")
message("TEST_ARGSLIST is ${TEST_ARGSLIST}")
message("TEST_BASELINE is ${TEST_BASELINE}")
endfunction(tst_arguments)
这里的前缀是TEST,<one_value_keywords>我们设置单值参数的KeyWord(NAME;COMMAND;BASELINE),这将在随后的函数调用中注明KeyWord和Value的关系,<multi_value_keywords>我们设置多值参数的KeyWord(“ARGSLIST”),调用函数:
tst_arguments( NAME testiso
COMMAND "RunMe"
ARGSLIST ${SRC}
BASELINE "/home/sakaue/iWork" )
==== output ====
TEST_DEFAULT_ARGS is from NAME;testiso;COMMAND;RunMe;ARGSLIST;a.cpp;b.cpp;c.cpp;d.cpp;BASELINE;/home/sakaue/iWork
TEST_NAME is testiso
TEST_COMMAND is RunMe
TEST_ARGSLIST is a.cpp;b.cpp;c.cpp;d.cpp
TEST_BASELINE is /home/sakaue/iWork
可以看见,这里调用时的参数传递如同map一样<NAME ,testiso_${datafile} >,<COMMAND , “RunMe”>,<ARGSLIST , ${SRC}>等等,在函数中,使用 前缀+KeyWord 来调用Value,这样比自己解析参数方便许多,而且也不会在还有list参数时和其他类型函数混在一起的情况。
参考
推荐阅读
-
ORACLE 修改表结构 之ALTER CONSTAINTS的使用
-
oracle的nvl函数的使用介绍
-
ASP.NET Core 3.0 WebApi中使用Swagger生成API文档简介
-
Oracle中使用DBMS_XPLAN处理执行计划详解
-
node.js 使用mongoose链接mongodb的操作教程
-
jQuery.clean使用方法及思路分析
-
python编程使用turtle画图实例
-
Oracle 11g 新特性 Flashback Data Archive 使用实例
-
Android AOP框架AspectJ使用详解
-
abp(net core)+easyui+efcore实现仓储管理系统——使用 WEBAPI实现CURD (十五)