什么是CMake语法来设置和使用variables?
我在下一次使用CMake时提醒自己。 它从来没有坚持,谷歌的结果不是很好。
在CMake中设置和使用variables的语法是什么?
在编写CMake脚本时,需要了解很多关于CMake语法和如何使用variables的知识。
语法
使用set()
string:
-
set(MyString "Some Text")
-
set(MyStringWithVar "Some other Text: ${MyString}")
-
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
或用string()
:
-
string(APPEND MyStringWithContent " ${MyString}")
使用set()
列表:
-
set(MyList "a" "b" "c")
-
set(MyList ${MyList} "d")
或者用list()
更好:
-
list(APPEND MyList "a" "b" "c")
-
list(APPEND MyList "d")
文件名称列表:
-
set(MySourcesList "File.name" "File with Space.name")
-
list(APPEND MySourcesList "File.name" "File with Space.name")
-
add_excutable(MyExeTarget ${MySourcesList})
文档
- CMake /语言语法
- CMake:variables列表string
- CMake:有用的variables
- CMake
set()
命令 - CMake
string()
命令 - CMake
list()
命令 - Cmake:生成器expression式
范围或“我的variables有什么价值?”
首先是“正常variables”和你需要知道的范围:
- 正常variables对于它们设置的
CMakeLists.txt
以及从那里调用的所有东西(add_subdirectory()
,include()
,macro()
和function()
)是可见的。 -
add_subdirectory()
和function()
命令是特殊的,因为它们打开了自己的范围。- 意义variables
set(...)
仅在那里可见,并且它们作为从其调用范围级别(称为父范围)的所有正常variables的副本。 - 所以,如果你在一个子目录或者一个函数中,你可以使用
set(... PARENT_SCOPE)
修改父范围中已经存在的variables, - 你可以使用这个例如在函数中传递variables名作为函数参数。 一个例子是
function(xyz _resultVar)
是设置set(${_resultVar} 1 PARENT_SCOPE)
- 意义variables
- 另一方面,你在
include()
或者macro()
脚本中设置的所有东西都会直接在它们被调用的范围内修改variables。
其次是“全局variablescaching”。 你需要知道的有关caching的事情:
- 如果在当前范围中没有定义具有给定名称的正常variables,CMake将查找匹配的Cache条目。
- caching值存储在二进制输出目录中的
CMakeCache.txt
文件中。 -
Cache中的值可以在CMake的GUI应用程序生成之前修改。 因此,它们与正常variables相比具有
type
和docstring
。 我通常不使用GUI,所以我使用set(... CACHE INTERNAL "")
来设置我的全局和持久值。请注意,
INTERNAL
cachingvariablestypes意味着FORCE
-
在CMake脚本中,如果使用
set(... CACHE ... FORCE)
语法,只能更改现有的caching条目。 这种行为是由例如CMake自己使用的,因为它通常不会强制Cache条目本身,因此可以用另一个值预先定义它。 - 您可以使用命令行在
cmake -D var:type=value
设置caching中的条目,只需cmake -D var=value
或使用cmake -C CMakeInitialCache.cmake
。 - 您可以使用
unset(... CACHE)
caching中的条目。
caching是全球性的,你可以在你的CMake脚本的任何地方设置它们。 但是我build议你考虑一下使用Cachevariables的地方(它们是全局的,它们是持久的)。 我通常更喜欢set_property(GLOBAL PROPERTY ...)
和set_property(GLOBAL APPEND PROPERTY ...)
语法来定义我自己的非set_property(GLOBAL APPEND PROPERTY ...)
性全局variables。
可变的陷阱和“如何debuggingvariables的变化?
为了避免陷阱,您应该了解以下variables:
- CMake中的列表只是带有分号分隔符的string,因此引号很重要
-
set(MyVar abc)
是"a;b;c"
,set(MyVar "abc")
是"abc"
- build议您总是使用引号,但有一个例外,当您要列出一个列表
- 一般更喜欢
list()
命令来处理列表
-
- 上述的整个范围问题。 特别是build议使用
functions()
而不是macros()
因为您不希望本地variables显示在父范围中。 - CMake使用的很多variables都是通过
project()
和enable_language()
调用来设置的。 所以在使用这些命令之前设置一些variables会变得很重要。 - 环境variables可能与CMake生成make环境以及make文件被使用的地方不同。
- 环境variables的更改不会重新触发生成过程。
- 尤其是生成的IDE环境可能与您的命令行不同,因此build议将您的环境variables转换为caching的内容。
有时只有debuggingvariables有帮助。 以下可能会帮助你:
- 只需使用
message()
命令即可使用旧的printf
debugging样式。 还有一些随CMake自带的准备使用的模块: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake - 查看二进制输出目录中的
CMakeCache.txt
文件。 如果make环境的实际生成失败,甚至会生成该文件。 - 使用variable_watch()来查看variables的读/写/删除位置。
- 查看目录属性CACHE_VARIABLES和VARIABLES
- 调用
cmake --trace ...
来查看CMake完整的parsing过程。 这是最后一个储备,因为它产生了很多输出。
特殊语法
- 环境variables
- 您可以读取
$ENV{...}
并写入set(ENV{...} ...)
环境variables
- 您可以读取
- 生成器expression式
- 生成器expression式
$<...>
仅在CMake的生成器写入make环境时进行计算(与正常variables相比,parsing器“in-place”replace了正常variables) - 在编译器/链接器命令行和多configuration环境中非常方便
- 生成器expression式
- 参考
- 使用
${${...}}
您可以在variables中给variables名称并引用其内容。 - 在给variables名称作为函数/macros参数时经常使用。
- 使用
- 常量值(请参阅
if()
命令)- 用
if(MyVariable)
你可以直接检查一个variables是否为true / false(这里不需要包含${...}
) - 如果常数为
1
,ON
,YES
,TRUE
,Y
或非零数字,则为TRUE
。 - 如果常量为
0
,OFF
,NO
,FALSE
,N
,IGNORE
,NOTFOUND
,空string,或者以-NOTFOUND
结尾,-NOTFOUND
。 - 这个语法通常用于
if (MSVC)
类的东西,但是对于不知道这个语法快捷方式的人来说,这可能会让人困惑。
- 用
- recursionreplace
- 您可以使用variables构造variables名称。 CMake替代variables后,会再次检查结果本身是否为variables。 这是CMake本身使用的非常强大的function,例如,作为一种模板
set(CMAKE_${lang}_COMPILER ...)
- 但是请注意,这可以让你头疼
if ()
命令。 这是一个CMAKE_CXX_COMPILER_ID
为"MSVC"
,MSVC
为"1"
的示例:-
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
为真,因为它评估为if ("1" STREQUAL "1")
-
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
为假,因为它评估为if ("MSVC" STREQUAL "1")
- 所以这里最好的解决scheme是 – 见上面 – 直接检查
if (MSVC)
-
- 好消息是,在CMake 3.1中引入了策略CMP0054 ,这个问题得到了解决。 我会build议总是将
cmake_policy(SET CMP0054 NEW)
为“仅if()
参数作为variables或关键字解释引号时解释”。
- 您可以使用variables构造variables名称。 CMake替代variables后,会再次检查结果本身是否为variables。 这是CMake本身使用的非常强大的function,例如,作为一种模板
-
option()
命令- 主要只是caching的string,只能是
ON
或OFF
,他们允许一些特殊的处理,如依赖 - 但请注意 ,不要将该
option
与set
命令相混淆。 赋予option
的值实际上只是“初始值”(在第一个configuration步骤中一次传送到caching),之后将由用户通过CMake的GUI进行更改。
- 主要只是caching的string,只能是
参考
- CMake如何使用?
- cmake,在全局variables的概念(和PARENT_SCOPE或add_subdirectory替代)
- 在一个string列表中循环
- 如何存储CMake构build设置
- CMake与STREQUAL的空string比较失败
- cmake:何时引用variables?
这里有几个基本的例子,开始快速和肮脏。
一个项目variables
设置variables:
SET(INSTALL_ETC_DIR "etc")
使用variables:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
多项variables(即列表)
设置variables:
SET(PROGRAM_SRCS program.c program_utils.c a_lib.c b_lib.c config.c )
使用variables:
add_executable(program "${PROGRAM_SRCS}")
CMake文档的variables
$ENV{FOO}
的用法,其中FOO正从环境variables中拾取。 否则用作${FOO}
,其中FOO是其他variables。 对于设置,将在cmake中使用SET(FOO "foo")
。