我问这个问题是为了提醒我自己下次使用CMake。它从来没有坚持下来,谷歌的结果也不好。在CMake中设置和使用变量的语法是什么?
nhaq1z211#
在编写CMake脚本时,您需要了解很多有关语法以及如何在CMake中使用变量的知识。
使用set()的字符串:
set()
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
或者使用string():
string()
string(APPEND MyStringWithContent " ${MyString}")
使用set()的列表:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
或者更好地使用list():
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})
首先是“常规变量”以及您需要了解的有关其作用域的信息:
CMakeLists.txt
add_subdirectory()
include()
macro()
function()
set(...)
set(... PARENT_SCOPE)
function(xyz _resultVar)
set(${_resultVar} 1 PARENT_SCOPE)
第二个是“全局变量缓存”。关于该高速缓存你需要知道的事情:
CMakeCache.txt
type
docstring
set(... CACHE INTERNAL "")
INTERNAL
FORCE
set(... CACHE ... FORCE)
cmake -D var:type=value
cmake -D var=value
cmake -C CMakeInitialCache.cmake
unset(... CACHE)
该高速缓存是全局的,你可以在CMake脚本中的任何地方设置它们。但是我建议你在使用Cache变量的时候三思而后行(它们是全局的,也是持久的)。我通常更喜欢用set_property(GLOBAL PROPERTY ...)和set_property(GLOBAL APPEND PROPERTY ...)语法来定义我自己的非持久全局变量。
set_property(GLOBAL PROPERTY ...)
set_property(GLOBAL APPEND PROPERTY ...)
为了避免陷阱,您应该了解以下有关变量的信息:
find_...
set(MyVar a b c)
"a;b;c"
set(MyVar "a b c")
"a b c"
functions()
macros()
project()
enable_language()
有时只有调试变量才有帮助。以下内容可能会对您有所帮助:
message()
printf
cmake --trace ...
环境变量
您可以读取$ENV{...}和写入set(ENV{...} ...)环境变量
$ENV{...}
set(ENV{...} ...)
生成器表达式
生成器表达式$<...>仅在CMake的生成器写入make环境时才被求值(它与被解析器“就地”替换的普通变量相比)
$<...>
非常方便,例如在编译器/链接器命令行和多配置环境中
参考文献
使用${${...}}可以在变量中给予变量名并引用其内容。
${${...}}
通常在将变量名作为函数/宏参数时使用。
常数值(请参阅if()指令)
if()
使用if(MyVariable),您可以直接检查变量的true/false(这里不需要使用封闭的${...})
if(MyVariable)
${...}
如果常数是1、ON、YES、TRUE、Y或非零的数字,则为True。
1
ON
YES
TRUE
Y
如果常数为0、OFF、NO、FALSE、N、IGNORE、NOTFOUND、空字串,或以后置字符-NOTFOUND结尾,则传回False。
0
OFF
NO
FALSE
N
IGNORE
NOTFOUND
-NOTFOUND
此语法通常用于if(MSVC)之类的内容,但对于不了解此语法快捷方式的人来说,可能会感到困惑。
if(MSVC)
递归替换
您可以使用变量构造变量名。CMake替换变量后,它会再次检查结果是否是变量本身。这是CMake本身使用的非常强大的功能,例如作为模板set(CMAKE_${lang}_COMPILER ...)
set(CMAKE_${lang}_COMPILER ...)
但是,* 请注意 *,在if()命令中,这会给予您感到头疼。下面是一个示例,其中CMAKE_CXX_COMPILER_ID是"MSVC",MSVC是"1":
CMAKE_CXX_COMPILER_ID
"MSVC"
MSVC
"1"
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")为true,因为它的计算结果为if("1" STREQUAL "1")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")为false,因为它的计算结果为if("MSVC" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
if("MSVC" STREQUAL "1")
因此,这里最好的解决方案是(参见上文)直接检查if(MSVC)
好消息是这个问题在CMake 3.1中通过引入policy CMP0054得到了解决。我建议总是将cmake_policy(SET CMP0054 NEW)设置为“仅在不加引号时将if()参数解释为变量或关键字”。
cmake_policy(SET CMP0054 NEW)
option()命令
option()
主要是缓存只能是ON或OFF的字符串,它们允许一些特殊处理,例如dependencies
但是 * 请注意 *,不要将option与set命令混淆。option的值实际上只是“初始值”(在第一个配置步骤中传输到该高速缓存一次),之后将由用户通过CMake's GUI进行更改。
option
set
wr98u20j2#
这里有几个基本的例子,让你快速入门。
设置变量:
SET(INSTALL_ETC_DIR "etc")
使用变量:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
SET(PROGRAM_SRCS program.c program_utils.c a_lib.c b_lib.c config.c )
add_executable(program "${PROGRAM_SRCS}")
CMake变量文档
jc3wubiy3#
$ENV{FOO}以取得使用方式,其中FOO是从环境变量取得的。否则使用为${FOO},其中FOO是其他变数。若要设定,SET(FOO "foo")会在CMake中使用。
$ENV{FOO}
FOO
${FOO}
SET(FOO "foo")
3条答案
按热度按时间nhaq1z211#
在编写CMake脚本时,您需要了解很多有关语法以及如何在CMake中使用变量的知识。
语法
使用
set()
的字符串: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})
个文档
set()
Commandstring()
Commandlist()
Command范围或“我的变量有什么值?”
首先是“常规变量”以及您需要了解的有关其作用域的信息:
CMakeLists.txt
和从那里调用的所有内容(add_subdirectory()
、include()
、macro()
和function()
)都是可见的。add_subdirectory()
和function()
命令很特殊,因为它们打开了自己的作用域。set(...)
只在那里可见,并且它们复制了调用它们的作用域级别(称为父作用域)的所有普通变量。set(... PARENT_SCOPE)
修改父作用域中已经存在的变量function(xyz _resultVar)
is settingset(${_resultVar} 1 PARENT_SCOPE)
include()
或macro()
脚本中设置的所有内容都将直接在调用变量的作用域中修改变量。第二个是“全局变量缓存”。关于该高速缓存你需要知道的事情:
CMakeCache.txt
文件中。type
和一个docstring
。我通常不使用GUI,所以我使用set(... CACHE INTERNAL "")
来设置我的全局值和持久值。INTERNAL
缓存变量类型不隐含FORCE
*set(... CACHE ... FORCE)
语法,您只能更改现有的缓存条目。例如,CMake本身使用此行为,因为它通常不会强制缓存条目本身,因此您可以使用另一个值预定义它。cmake -D var:type=value
、仅cmake -D var=value
或cmake -C CMakeInitialCache.cmake
来设置该高速缓存中的条目。unset(... CACHE)
来unset该高速缓存中的项目。该高速缓存是全局的,你可以在CMake脚本中的任何地方设置它们。但是我建议你在使用Cache变量的时候三思而后行(它们是全局的,也是持久的)。我通常更喜欢用
set_property(GLOBAL PROPERTY ...)
和set_property(GLOBAL APPEND PROPERTY ...)
语法来定义我自己的非持久全局变量。变量陷阱和“如何调试变量更改?”
为了避免陷阱,您应该了解以下有关变量的信息:
find_...
命令-如果成功-将其结果作为缓存变量写入,“这样就不会有调用再次搜索”set(MyVar a b c)
是"a;b;c"
,而set(MyVar "a b c")
是"a b c"
list()
命令来处理列表functions()
而不是macros()
,因为你不希望你的局部变量出现在父作用域中。project()
和enable_language()
调用设置的。因此,在使用这些命令之前设置一些变量可能很重要。有时只有调试变量才有帮助。以下内容可能会对您有所帮助:
message()
命令使用旧的printf
调试风格即可。CMake本身附带了一些现成的模块:CMakePrintHelpers.cmake、CMakePrintSystemInformation.cmakeCMakeCache.txt
文件。即使make环境的实际生成失败,也会生成此文件。cmake --trace ...
来查看CMake的完整解析过程,这是最后一个保留,因为它会生成大量输出。特殊语法
环境变量
您可以读取
$ENV{...}
和写入set(ENV{...} ...)
环境变量生成器表达式
生成器表达式
$<...>
仅在CMake的生成器写入make环境时才被求值(它与被解析器“就地”替换的普通变量相比)非常方便,例如在编译器/链接器命令行和多配置环境中
参考文献
使用
${${...}}
可以在变量中给予变量名并引用其内容。通常在将变量名作为函数/宏参数时使用。
常数值(请参阅
if()
指令)使用
if(MyVariable)
,您可以直接检查变量的true/false(这里不需要使用封闭的${...}
)如果常数是
1
、ON
、YES
、TRUE
、Y
或非零的数字,则为True。如果常数为
0
、OFF
、NO
、FALSE
、N
、IGNORE
、NOTFOUND
、空字串,或以后置字符-NOTFOUND
结尾,则传回False。此语法通常用于
if(MSVC)
之类的内容,但对于不了解此语法快捷方式的人来说,可能会感到困惑。递归替换
您可以使用变量构造变量名。CMake替换变量后,它会再次检查结果是否是变量本身。这是CMake本身使用的非常强大的功能,例如作为模板
set(CMAKE_${lang}_COMPILER ...)
但是,* 请注意 *,在
if()
命令中,这会给予您感到头疼。下面是一个示例,其中CMAKE_CXX_COMPILER_ID
是"MSVC"
,MSVC
是"1"
:if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
为true,因为它的计算结果为if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
为false,因为它的计算结果为if("MSVC" STREQUAL "1")
因此,这里最好的解决方案是(参见上文)直接检查
if(MSVC)
好消息是这个问题在CMake 3.1中通过引入policy CMP0054得到了解决。我建议总是将
cmake_policy(SET CMP0054 NEW)
设置为“仅在不加引号时将if()
参数解释为变量或关键字”。option()
命令主要是缓存只能是
ON
或OFF
的字符串,它们允许一些特殊处理,例如dependencies但是 * 请注意 *,不要将
option
与set
命令混淆。option
的值实际上只是“初始值”(在第一个配置步骤中传输到该高速缓存一次),之后将由用户通过CMake's GUI进行更改。参考
wr98u20j2#
这里有几个基本的例子,让你快速入门。
一个项目变量
设置变量:
使用变量:
多项变量(即列表)
设置变量:
使用变量:
CMake变量文档
jc3wubiy3#
$ENV{FOO}
以取得使用方式,其中FOO
是从环境变量取得的。否则使用为${FOO}
,其中FOO
是其他变数。若要设定,SET(FOO "foo")
会在CMake中使用。