什么是CMake语法设置和使用变量? [英] What's the CMake syntax to set and use variables?
问题描述
我要求这是一个提醒自己下一次我使用CMake。
在CMake中设置和使用变量的语法是什么?
当编写CMake脚本时,你需要知道很多关于语法和如何使用CMake中的变量。
语法
字符串:
-
set(MyStringSome Text)
-
文本:$ {MyString})
-
set(MyStringWithQuotSome quote:\$ {MyStringWithVar} \ )
列表:
-
set(MyListabc)
-
MyList $ {MyList}d)
):
-
列表(APPEND MyListabc )
-
ul>
。
文件名列表:
-
File.nameFile with Space.name)
-
add_excutable(MyExeTarget $ {MySourcesList})
文档
- a href =http://www.cmake.org/Wiki/CMake/Language_Syntax> CMake /语言语法
- CMake:变量列出字符串
- CMake:有用的变量
- CMake
set()
命令 - CMake
list()
命令 - Cmake:生成器表达式
范围或我的变量有什么值?
首先是正常变量
- 正常变量对
CMakeLists.txt $ c可见$ c>它们被设置,并从那里调用(
add_subdirectory()
,include()
,macro()
和function()
)。 -
add_subdirectory()
和function()
命令是特殊的,因为它们打开了自己的范围。
- 含义变量
set(...)
只有在那里可见, - 所以如果你在一个子目录或一个函数中,你可以修改父类中已经存在的变量范围与
set(... PARENT_SCOPE)
- 您可以使用这个例如在函数中通过传递变量名作为函数参数。一个例子是
function(xyz _resultVar)
设置set($ {_ resultVar} 1 PARENT_SCOPE)
- 含义变量
- 另一方面,您在
中设置的一切include()
或macro()
脚本将直接在它们调用的范围内修改变量。
其次是全局变量缓存。
- 如果没有在当前作用域中定义具有给定名称的正常变量,CMake将查找
- 缓存值存储在二进制输出目录中的
CMakeCache.txt
文件中。 -
可以在 CMake的GUI 应用程序,然后生成它们。因此,与正常变量相比,它们具有
类型
和docstring
。我通常不使用GUI,所以我使用set(... CACHE INTERNAL)
设置我的全局和持久值。
请注意,
INTERNAL
缓存变量类型意味着FORCE
-
在CMake脚本中,只能使用
set ... CACHE ... FORCE)
语法。这种行为是利用例如。 - 您可以使用命令行来设置条目,以使用CMake自身,因为它通常不会强制Cache条目本身,因此您可以使用另一个值预定义它。使用语法
cmake -D var:type = value
,只是cmake -D var = value
code> cmake -C CMakeInitialCache.cmake
-
- 您可以设置缓存中的 c> cset b
缓存是全局的,你可以在CMake脚本中的任何地方设置它们。但我建议你三思考在哪里使用缓存变量(它们是全局的,它们是持久的)。我通常喜欢 set_property(GLOBAL PROPERTY ...)
和 set_property(GLOBAL APPEND PROPERTY ...)
定义我自己的非持久性全局变量。
变量陷阱和如何调试变量更改?
为避免陷阱,您应该知道以下有关变量的信息:
- CMake中的列表只是带有分号分隔符的字符串,因此引号是重要的
-
set(MyVar abc)
是a; b; c
)是abc
- 建议您始终使用引号, $
-
functions()
而不是 macros()
,因为你不想显示局部变量在父作用域中。 project()
和 enable_language() code>调用。因此,在使用这些命令之前设置一些变量很重要。
- 环境变量的更改不会重新触发生成过程。
- 特别是生成的IDE环境不同于您的命令行,因此建议将您的环境变量转换为已缓存的内容。
有时只有调试变量有帮助。以下可能会帮助您:
- 只需使用旧的
printf
message()
命令。还有一些随时可以使用CMake自带的模块: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake - 查看
CMakeCache.txt
文件。 - 使用
- 查看目录属性 CACHE_VARIABLES 和变体
- 调用
cmake --trace ...
查看CMake的完整解析过程。这是最后一个储备,因为它产生了大量的输出。
特殊语法
- 环境变量
- 您可以阅读
$ ENV {...} / code>并写入
set(ENV {...} ...)
环境变量
- 您可以阅读
- 生成器表达式
- 生成器表达式
$< ...>
仅当CMake的生成器写入make环境(它与解析器替换为in-place的正常变量的比较)时才进行评估。 - 非常方便在编译器/链接器命令行和多配置环境中。
- 生成器表达式
- 引用
- 使用
$ {$ {...}}
,您可以在变量中赋予变量名称并引用其内容。 - 通常在将变量名称指定为函数/宏参数时使用。
- 使用
- 常量值(请参阅
if()
命令)
- 通过
if(MyVariable)
,你可以直接检查一个变量是否为true / false(这里不需要包含$ {...}
) - 如果常数
1
> ON ,YES
,TRUE
,Y
,或非零数。 - False如果常数
0
,OFF
,NO
,FALSE
,N
,code>,
NOTFOUND
,空字符串或结尾-NOTFOUND
。 - 此语法通常用于
if(MSVC)
,但对于不知道此语法快捷方式的人可能会感到困惑。 li>
- 通过
- 递归替换
- 您可以使用变量构建变量名称。在CMake替换了变量后,它将再次检查结果是否是一个变量本身。这是CMake本身使用的非常强大的功能。作为模板类型
set(CMAKE _ $ {lang} _COMPILER ...)
- 但 >这可以让你头痛在
if()
命令。下面是一个示例CMAKE_CXX_COMPILER_ID
是MSVC
和MSVC
1
:
-
if($ {CMAKE_CXX_COMPILER_ID} STREQUALMSVC)
是真的,因为它的计算结果为if(1STREQUAL1)
-
if(CMAKE_CXX_COMPILER_ID STREQUALMSVC)
为假,因为它的计算结果为if(MSVCSTREQUAL1 code>
- 因此,最好的解决方案是 - 如上所示 - 直接检查
if(MSVC)
li>
-
- 好消息是,这是在CMake 3.1中修复的,引入政策CMP0054 。我建议始终将
cmake_policy(SET CMP0054 NEW)
设置为只解释if()
参数作为变量或关键字时, /command/option.html> - 主要是刚刚缓存字符串,但它们允许一些特殊的处理,例如依赖
- 但请注意,不要将
选项与
set
命令混淆。给予选项
的值实际上只是初始值(在第一个配置步骤期间传输一次到缓存),后来意味着由用户通过< a href =http://www.cmake.org/cmake/help/v3.3/manual/cmake-gui.1.html> CMake的GUI 。
option()
命令
ul> - 您可以使用变量构建变量名称。在CMake替换了变量后,它将再次检查结果是否是一个变量本身。这是CMake本身使用的非常强大的功能。作为模板类型
参考资料
- CMake如何使用?
- cmake,丢失在全局变量的概念中和PARENT_SCOPE或add_subdirectory备用项)
- 循环通过字符串列表
- 如何存储CMake构建设置
- CMake与STREQUAL失败的空字符串
I'm asking this as a reminder to myself the next time I use CMake. It never sticks, and Google results aren't great.
What's the syntax to set and use variables in CMake?
When writing CMake scripts there is a lot you need to know about the syntax and how to use variables in CMake.
The Syntax
Strings:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
Lists:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
Or better with list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Lists of File Names:
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
The Documentation
- CMake/Language Syntax
- CMake: Variables Lists Strings
- CMake: Useful Variables
- CMake
set()
Command - CMake
list()
Command - Cmake: Generator Expressions
The Scope or "What value does my variable have?"
First there are the "Normal Variables" and things you need to know about their scope:
- Normal variables are visible to the
CMakeLists.txt
they are set in and everything called from there (add_subdirectory()
,include()
,macro()
andfunction()
). - The
add_subdirectory()
andfunction()
commands are special, because they open-up their own scope.- Meaning variables
set(...)
there are only visible there and they make a copy of all normal variables of the scope level they are called from (called parent scope). - So if you are in a sub-directory or a function you can modify an already existing variable in the parent scope with
set(... PARENT_SCOPE)
- You can make use of this e.g. in functions by passing the variable name as a function parameter. An example would be
function(xyz _resultVar)
is settingset(${_resultVar} 1 PARENT_SCOPE)
- Meaning variables
- On the other hand everything you set in
include()
ormacro()
scripts will modify variables directly in the scope of where they are called from.
Second there is the "Global Variables Cache". Things you need to know about the Cache:
- If no normal variable with the given name is defined in the current scope, CMake will look for a matching Cache entry.
- Cache values are stored in the
CMakeCache.txt
file in your binary output directory. The values in the Cache can be modified in CMake's GUI application before they are generated. Therefore they - in comparison to normal variables - have a
type
and adocstring
. I normally don't use the GUI so I useset(... CACHE INTERNAL "")
to set my global and persistant values.Please note that the
INTERNAL
cache variable type does implyFORCE
In a CMake script you can only change existing Cache entries if you use the
set(... CACHE ... FORCE)
syntax. This behavior is made use of e.g. by CMake itself, because it normally does not force Cache entries itself and therefore you can pre-define it with another value.- You can use the command line to set entries in the Cache with the syntax
cmake -D var:type=value
, justcmake -D var=value
or withcmake -C CMakeInitialCache.cmake
. - You can unset entries in the Cache with
unset(... CACHE)
.
The Cache is global and you can set them virtually anywhere in your CMake scripts. But I would recommend you think twice about where to use Cache variables (they are global and they are persistant). I normally prefer the set_property(GLOBAL PROPERTY ...)
and set_property(GLOBAL APPEND PROPERTY ...)
syntax to define my own non-persistant global variables.
Variable Pitfalls and "How to debug variable changes?"
To avoid pitfalls you should know the following about variables:
- Lists in CMake are just strings with semicolons delimiters and therefore the quotation-marks are important
set(MyVar a b c)
is"a;b;c"
andset(MyVar "a b c")
is"a b c"
- The recommendation is that you always use quotation marks with the one exception when you want to give a list as list
- Generally prefer the
list()
command for handling lists
- The whole scope issue described above. Especially it's recommended to use
functions()
instead ofmacros()
because you don't want your local variables to show up in the parent scope. - A lot of variables used by CMake are set with the
project()
andenable_language()
calls. So it could get important to set some variables before those commands are used. - Environment variables may differ from where CMake generated the make environment and when the the make files are put to use.
- A change in an environment variable does not re-trigger the generation process.
- Especially a generated IDE environment may differ from your command line, so it's recommended to transfer your environment variables into something that is cached.
Sometimes only debugging variables helps. The following may help you:
- Simply use old
printf
debugging style by using themessage()
command. There also some ready to use modules shipped with CMake itself: CMakePrintHelpers.cmake, CMakePrintSystemInformation.cmake - Look into
CMakeCache.txt
file in your binary output directory. This file is even generated if the actual generation of your make environment fails. - Use variable_watch() to see where your variables are read/written/removed.
- Look into the directory properties CACHE_VARIABLES and VARIABLES
- Call
cmake --trace ...
to see the CMake's complete parsing process. That's sort of the last reserve, because it generates a lot of output.
Special Syntax
- Environment Variables
- You can can read
$ENV{...}
and writeset(ENV{...} ...)
environment variables
- You can can read
- Generator Expressions
- Generator expressions
$<...>
are only evaluated when CMake's generator writes the make environment (it comparison to normal variables that are replaced "in-place" by the parser) - Very handy e.g. in compiler/linker command lines and in multi-configuration environments
- Generator expressions
- References
- With
${${...}}
you can give variable names in a variable and reference its content. - Often used when giving a variable name as function/macro parameter.
- With
- Constant Values (see
if()
command)- With
if(MyVariable)
you can directly check a variable for true/false (no need here for the enclosing${...}
) - True if the constant is
1
,ON
,YES
,TRUE
,Y
, or a non-zero number. - False if the constant is
0
,OFF
,NO
,FALSE
,N
,IGNORE
,NOTFOUND
, the empty string, or ends in the suffix-NOTFOUND
. - This syntax is often use for something like
if (MSVC)
, but it can be confusing for someone who does not know this syntax shortcut.
- With
- Recursive substitutions
- You can construct variable names using variables. After CMake has substituted the variables, it will check again if the result is a variable itself. This is very powerful feature used in CMake itself e.g. as sort of a template
set(CMAKE_${lang}_COMPILER ...)
- But be aware this can give you a headache in
if ()
commands. Here is an example whereCMAKE_CXX_COMPILER_ID
is"MSVC"
andMSVC
is"1"
:if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
is true, because it evaluates toif ("1" STREQUAL "1")
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
is false, because it evaluates toif ("MSVC" STREQUAL "1")
- So the best solution here would be - see above - to directly check for
if (MSVC)
- The good news is that this was fixed in CMake 3.1 with the introduction of policy CMP0054. I would recommend to always set
cmake_policy(SET CMP0054 NEW)
to "only interpretif()
arguments as variables or keywords when unquoted."
- You can construct variable names using variables. After CMake has substituted the variables, it will check again if the result is a variable itself. This is very powerful feature used in CMake itself e.g. as sort of a template
- The
option()
command- Mainly just cached strings, but they allow some special handling like e.g. dependencies
- But be aware, don't mistake the
option
with theset
command. The value given tooption
is really only the "initial value" (transferred once to the cache during the first configuration step) and is afterwards meant to be changed by the user through CMake's GUI.
References
- How is CMake used?
- cmake, lost in the concept of global variables (and PARENT_SCOPE or add_subdirectory alternatives)
- Looping over a string list
- How to store CMake build settings
- CMake compare to empty string with STREQUAL failed
这篇关于什么是CMake语法设置和使用变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!