cmake处理参数时的一些问题说明

函数传参空格和分号的坑

我们在处理函数和宏的时候不过不小心会遇到很多坑例如:

someCommand(a b c)
someCommand(a   b c)

因为cmake中使用空格或者分号分隔符所以上面代码等价于:

someCommand(a b;c)
someCommand(a;;;;b;c)

如果我们想要参数的值包含空格和引号,就需要使用引号将其引起来,例如

someCommand(a "b b" c)
someCommand(a "b;b" c)
someCommand(a;"b;b";c)

使用空格和分号作为分隔符还有一点区别,当涉及到变量求值并且参数未使用引号的时候,例如:

set(containsSpace "b b")
set(containsSemiColon "b;b")

someCommand(a ${containsSpace} c)
someCommand(a ${containsSemiColon} c) 

实际上someCommand(a ${containsSpace} c)会传递三个参数,而someCommand(a ${containsSemiColon} c) 会传递四个参数.

测试:

function(someCommand)
    message("=======[${ARGC}]========")
    message("=======[${ARGV}]========")
endfunction()

set(containsSpace "b b")
set(containsSemiColon "b;b")

someCommand(a ${containsSpace} c)
someCommand(a ${containsSemiColon} c) 

在这里插入图片描述

function(someCommand)
    message("=======[${ARGC}]========")
    message("=======[${ARGV}]========")
    message("xxxxxxxxxxxxxxxxxxxxxxxxx")
endfunction()
mesage("=====================")
set(empty                    "")
set(space                   " ")
set(semicolon               ";")
set(semiSpace              "; ")
set(spaceSemi              " ;")
set(spaceSemiSpace        " ; ")
set(spaceSemiSemi         " ;;")
set(semiSemiSpace         ";; ")
set(spcaeSemiSemiSpcae   " ;; ")

someCommand(${empty})
someCommand(${space})
someCommand(${semicolon})
someCommand(${semiSpace})
someCommand(${spaceSemi})
someCommand(${spaceSemiSpace})
someCommand(${spaceSemiSemi})
someCommand(${semiSemiSpace})
someCommand(${spcaeSemiSemiSpcae})

在这里插入图片描述

通过上面的例子可以得出:

  1. 当参数时变量的求值的结果的时候,空格不能被抛弃,也不会充当分隔符.
  2. 当参数没有引号的时候,其值开头和结尾的一个或者多个分号会被丢弃.
  3. 当参数没有加引号的时候,其值中间的连续分号会被合并成一个分号.

通常如果我们传递的参数如果是一个变量求值的结果,那建议使用引号,这样可以避免大多数的困扰,但是并不总是这样的,也有明确需要参数不使用引号的情况.

例如:
关键字参数

function(func)
    set(noValues ENABLE_A ENABLE_B)
    set(singleVaues FORMAT ARCH)
    set(multiValues SOURCE IMAGES)

    cmake_parse_arguments(
        ARG
        "${noValues}" "${singleVaues}" "${multiValues}"
        ${ARGV}
    )
endfunction()

"${noValues}" "${singleVaues}" "${multiValues}"这三个参数明确使用了引号,${ARGV}这个参数明确不使用引号.

func(a "" c)
func("a;b;c" "1;2;3")

对于第一条命令${ARGV}的求值是:a;;c,根据上述结论3,因为中间的多个分号会被合并成一个,所以cmake_parse_arguments()命令实际上只会把ac作为要解析的参数.
对于第二条命令,${ARGV}的求值是:a;b;c;1;2;3,本来就是想把a;b;c当做第一个参数,把1;2;3 当作第二个参数,但是cmake_parse_arguments()命令实际上会认为传入了6个参数.
上述问题都可以通过避免使用${ARGV}来解决,也就是使用下面的命令形式:

cmake_parse_arguments(
	PARSE_ARGV 0 ARG
	"${noValues}" "${singleVaues}" "${multiValues}"	
)

这种方式可以是参数完全按照传入的方式保留.
我i们在自己定义函数或者宏的时候,一个相对常见的需求就是围绕现有的命令创建某种包装器.项目可能希望支持一些额外的选项或者删除现有的选项,或者它可能希望在调用之前或之后执行的某些处理.保留参数并不在改变其结构或丢失信息的情况下转发他们可能会非常困难.

函数转发的坑

demo

function(printArgs)
   message("ARGC = ${ARGC}\n"
           "ARGN = ${ARGN}")
endfunction()

printArgs("a;b;c" "d;e;f")

在这里插入图片描述
因此传入的承诺书是带引号的,所以ARGC的值是2,但是ARGV却是一个包含6个值的列表,原始的参数形式在这里丢失了,如果要做参数转发就会产生错误,例如:

function(printArgs)
    message("ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
endfunction()

printArgs("a;b;c" "d;e;f")

function(inner)
    message("inner:\n"
            "ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
endfunction()

function(outer)
    message("outer:\n"
            "ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
    inner(${ARGN})
endfunction()
message("=====================")
outer("a;b;c" "d;e;f")

在这里插入图片描述
解决上面问题其实使用cmake_parse_arguments()命令的PARSE_ARGV形式:

function(inner)
    message("inner:\n"
            "ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
endfunction()

function(outer)
    message("outer:\n"
            "ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
    cmake_parse_arguments(PARSE_ARGV 0 FWD "" "" "")
    message("FWD_UNPARSED_ARGUMENTS = ${FWD_UNPARSED_ARGUMENTS}")
    inner(${FWD_UNPARSED_ARGUMENTS})
endfunction()
message("=====================")
outer("a;b;c" "d;e;f")

在这里插入图片描述
如果有空的双引号就会出错:

outer("a;b;c" "d;e;f")

在这里插入图片描述

因为没有关键字需要解析,所以所有的参数都被保存到FWD_UNPARSED_ARGUMENTS中,这种方式转发原始参数就不会丢失参数的原始形式.
为了避免空参数丢失,每个参数都应该单独列出来,并加上引号.如下:

function(inner)
    message("inner:\n"
            "ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
endfunction()

function(outer)
    message("outer:\n"
            "ARGC = ${ARGC}\n"
            "ARGN = ${ARGN}")
    cmake_parse_arguments(PARSE_ARGV 0 FWD "" "" "")
    set(quoteArgs "")
    foreach(arg IN LISTS FWD_UNPARSED_ARGUMENTS)
        string(APPEND quoteArgs " [===[${arg}]===]")
    endforeach()
    message("quoteArgs = ${quoteArgs}")
    cmake_language(EVAL CODE "inner(${quoteArgs})")
endfunction()
message("=====================")
outer("a;b;c" "d;e;f" "")

在这里插入图片描述
注意: string(APPEND quoteArgs " [===[${arg}]===]")引号第一个空格不能省.
上面解决方案因为用到cmake_parse_arguments()命令的PARSE_ARGV形式,所以在宏里面不能使用.

函数传参遇到不平衡方括号的坑

还有一种特殊情况,就是参数带有不平衡的方括号需要特别注意,例如:

function(func)
    message("Number of arguments: ${ARGC}")
    math(EXPR lastIndex "${ARGC} - 1")
    foreach(n RANGE 0 ${lastIndex})
        message("ARGV${n} = ${ARGV${n}}")
    endforeach()
    foreach(arg IN LISTS ARGV)
        message("${arg}")
    endforeach()
endfunction()
message("=====================")
func("a[a" "b]b" "c[c]c" "d[d" "eee")

在这里插入图片描述
func()函数可以看到5个参数,但是对ARGV取值来说,只能取到3个值,这就是方括号不平衡的问题.我们写cmake的时候需要特别注意,避免使用.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

波雅_汉库克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值