在 CMake 中转发无值函数参数的简单方法
Simple way to forward a no-value function parameter in CMake
我有两个 CMake 函数(我们称它们为 inner
和 outer
),它们使用 cmake_parse_arguments
和相同的选项(无值参数)XXX
和一些其他参数,所以它们看起来像
function(inner)
set(prefix ARG)
set(noValues XXX)
set(singleValues ...)
set(multiValues ...)
cmake_parse_arguments(${prefix}
"${noValues}"
"${singleValues}"
"${multiValues}"
${ARGN})
...
endfunction()
function(outer)
set(prefix ARG)
set(noValues XXX)
set(singleValues ...)
set(multiValues ...)
cmake_parse_arguments(${prefix}
"${noValues}"
"${singleValues}"
"${multiValues}"
${ARGN})
...
inner(
$<$<BOOL:${ARG_XXX}>:XXX>
...)
endfunction()
目的是如果在调用outer
时设置了XXX
,它将被传递给inner
。但这似乎不起作用;如果我添加
# in outer
message("in outer, FILE=${ARG_FILE}, XXX=${ARG_XXX}")
# in inner
message("in outer, FILE=${ARG_FILE}, XXX=${ARG_XXX}")
(FILE
是另一个通过的参数,但它是一个强制性的单值参数,所以只有 FILE "${ARG_FILE}
效果很好)我明白了
in outer, FILE=abc.def, XXX=TRUE
in inner, FILE=abc.def, XXX=FALSE
为什么这不像我预期的那样工作,正确的方法是什么?
当然可以
if (ARG_XXX)
inner(XXX ...all the other arguments...)
else()
inner(...all the other arguments...)
endif()
但我希望这不是必需的,因为实际的代码库不仅有 2 层,每个层有 1 个函数...
CMake 版本为 3.15.5,但答案必须适用于 3.10.2 及更高版本。
这里的想法是使用 CMake 的列表扩展参数传递语法。当您编写 func(${args})
时,它将使用列表 ${args}
的 元素 来构建对 func
的调用。例如,如果您有 set(args "1" "2" "3")
,则 func(${args})
与 func("1" "2" "3")
相同,但如果您 引用 func
的参数那么这不会发生,即 func("${args}") == func("1;2;3")
.
所以在这种情况下,我们只是将您的 TRUE
或 FALSE
变量 ARG_XXX
转换为局部变量 XXX
,即 XXX
或空 true/false,然后调用 inner(${XXX})
.
if (ARG_XXX)
set(XXX XXX)
else ()
set(XXX "")
endif ()
inner(${XXX})
据我所知没有更好的方法。这是一个完整的演示:
# test.cmake
cmake_minimum_required(VERSION 3.9)
function(inner)
cmake_parse_arguments(ARG "XXX" "" "" ${ARGN})
message(STATUS "inner: ARG_XXX = ${ARG_XXX}")
endfunction()
function(outer)
cmake_parse_arguments(ARG "XXX" "" "" ${ARGN})
message(STATUS "outer: ARG_XXX = ${ARG_XXX}")
if (ARG_XXX)
set(xxx XXX)
else ()
set(xxx "")
endif ()
inner(${xxx})
endfunction()
outer()
outer(XXX)
运行 和 cmake -P test.cmake
这将打印:
$ ~/Downloads/cmake-3.9.6-Linux-x86_64/bin/cmake -P test.cmake
-- outer: ARG_XXX = FALSE
-- inner: ARG_XXX = FALSE
-- outer: ARG_XXX = TRUE
-- inner: ARG_XXX = TRUE
这 非常 很久以前就可以工作了,但是我的 ~/Downloads
文件夹中有 Kitware-official 静态链接版本 3.9,所以我使用了它。
另一方面,如果inner
的每个调用者已经解析了ARG_XXX
,那么你可以使用CMake的动态作用域规则来查看ARG_XXX
在调用者中设置。当你调用一个函数时,CMake 复制变量环境并将其传递给被调用者。因此,以下内容也将起作用:
cmake_minimum_required(VERSION 3.9)
function(inner)
cmake_parse_arguments(ARG "" "" "" ${ARGN})
message(STATUS "inner: ARG_XXX = ${ARG_XXX}")
endfunction()
function(outer)
cmake_parse_arguments(ARG "XXX" "" "" ${ARGN})
message(STATUS "outer: ARG_XXX = ${ARG_XXX}")
inner()
endfunction()
outer()
outer(XXX)
在这种情况下,inner
依赖于 outer
来解析 XXX
选项。显然,如果 inner
可能被任意函数调用(并且将 ARG_XXX
设置为合理的值成为其合同的一部分),这将是相当脆弱的。
我有两个 CMake 函数(我们称它们为 inner
和 outer
),它们使用 cmake_parse_arguments
和相同的选项(无值参数)XXX
和一些其他参数,所以它们看起来像
function(inner)
set(prefix ARG)
set(noValues XXX)
set(singleValues ...)
set(multiValues ...)
cmake_parse_arguments(${prefix}
"${noValues}"
"${singleValues}"
"${multiValues}"
${ARGN})
...
endfunction()
function(outer)
set(prefix ARG)
set(noValues XXX)
set(singleValues ...)
set(multiValues ...)
cmake_parse_arguments(${prefix}
"${noValues}"
"${singleValues}"
"${multiValues}"
${ARGN})
...
inner(
$<$<BOOL:${ARG_XXX}>:XXX>
...)
endfunction()
目的是如果在调用outer
时设置了XXX
,它将被传递给inner
。但这似乎不起作用;如果我添加
# in outer
message("in outer, FILE=${ARG_FILE}, XXX=${ARG_XXX}")
# in inner
message("in outer, FILE=${ARG_FILE}, XXX=${ARG_XXX}")
(FILE
是另一个通过的参数,但它是一个强制性的单值参数,所以只有 FILE "${ARG_FILE}
效果很好)我明白了
in outer, FILE=abc.def, XXX=TRUE
in inner, FILE=abc.def, XXX=FALSE
为什么这不像我预期的那样工作,正确的方法是什么?
当然可以
if (ARG_XXX)
inner(XXX ...all the other arguments...)
else()
inner(...all the other arguments...)
endif()
但我希望这不是必需的,因为实际的代码库不仅有 2 层,每个层有 1 个函数...
CMake 版本为 3.15.5,但答案必须适用于 3.10.2 及更高版本。
这里的想法是使用 CMake 的列表扩展参数传递语法。当您编写 func(${args})
时,它将使用列表 ${args}
的 元素 来构建对 func
的调用。例如,如果您有 set(args "1" "2" "3")
,则 func(${args})
与 func("1" "2" "3")
相同,但如果您 引用 func
的参数那么这不会发生,即 func("${args}") == func("1;2;3")
.
所以在这种情况下,我们只是将您的 TRUE
或 FALSE
变量 ARG_XXX
转换为局部变量 XXX
,即 XXX
或空 true/false,然后调用 inner(${XXX})
.
if (ARG_XXX)
set(XXX XXX)
else ()
set(XXX "")
endif ()
inner(${XXX})
据我所知没有更好的方法。这是一个完整的演示:
# test.cmake
cmake_minimum_required(VERSION 3.9)
function(inner)
cmake_parse_arguments(ARG "XXX" "" "" ${ARGN})
message(STATUS "inner: ARG_XXX = ${ARG_XXX}")
endfunction()
function(outer)
cmake_parse_arguments(ARG "XXX" "" "" ${ARGN})
message(STATUS "outer: ARG_XXX = ${ARG_XXX}")
if (ARG_XXX)
set(xxx XXX)
else ()
set(xxx "")
endif ()
inner(${xxx})
endfunction()
outer()
outer(XXX)
运行 和 cmake -P test.cmake
这将打印:
$ ~/Downloads/cmake-3.9.6-Linux-x86_64/bin/cmake -P test.cmake
-- outer: ARG_XXX = FALSE
-- inner: ARG_XXX = FALSE
-- outer: ARG_XXX = TRUE
-- inner: ARG_XXX = TRUE
这 非常 很久以前就可以工作了,但是我的 ~/Downloads
文件夹中有 Kitware-official 静态链接版本 3.9,所以我使用了它。
另一方面,如果inner
的每个调用者已经解析了ARG_XXX
,那么你可以使用CMake的动态作用域规则来查看ARG_XXX
在调用者中设置。当你调用一个函数时,CMake 复制变量环境并将其传递给被调用者。因此,以下内容也将起作用:
cmake_minimum_required(VERSION 3.9)
function(inner)
cmake_parse_arguments(ARG "" "" "" ${ARGN})
message(STATUS "inner: ARG_XXX = ${ARG_XXX}")
endfunction()
function(outer)
cmake_parse_arguments(ARG "XXX" "" "" ${ARGN})
message(STATUS "outer: ARG_XXX = ${ARG_XXX}")
inner()
endfunction()
outer()
outer(XXX)
在这种情况下,inner
依赖于 outer
来解析 XXX
选项。显然,如果 inner
可能被任意函数调用(并且将 ARG_XXX
设置为合理的值成为其合同的一部分),这将是相当脆弱的。