Answers:
在编写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})
首先是“普通变量”以及您需要了解的有关其范围的内容:
CMakeLists.txt
,他们在设置和一切所谓的从那里(add_subdirectory()
,include()
,macro()
和function()
)。add_subdirectory()
和function()
命令是特殊的,因为他们的开拓自己的范围。
set(...)
仅在此处可见,并且它们会复制从中调用的范围级别的所有普通变量(称为父范围)。set(... PARENT_SCOPE)
function(xyz _resultVar)
是设置set(${_resultVar} 1 PARENT_SCOPE)
include()
或macro()
脚本都将直接在调用它们的范围内修改变量。其次是“全局变量缓存”。您需要了解的有关缓存的信息:
CMakeCache.txt
二进制输出目录中的文件中。缓存中的值可以在生成之前在CMake的GUI应用程序中进行修改。因此,与普通变量相比,它们具有a type
和a docstring
。我通常不使用GUI,因此可以set(... CACHE INTERNAL "")
用来设置全局值和持久性值。
请注意,INTERNAL
缓存变量类型确实暗示FORCE
在CMake脚本中,如果使用set(... CACHE ... FORCE)
语法,则只能更改现有的缓存条目。此行为是通过CMake本身来利用的,因为它通常不会强制缓存条目本身,因此您可以使用另一个值对其进行预定义。
cmake -D var:type=value
just cmake -D var=value
或语法设置Cache中的条目cmake -C CMakeInitialCache.cmake
。unset(... CACHE)
。缓存是全局的,您可以在CMake脚本中的几乎任何位置设置它们。但我建议您三思而后行地考虑使用Cache变量(它们是全局变量,并且是持久性的)。通常,我更喜欢使用set_property(GLOBAL PROPERTY ...)
and 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()
调用设置的。因此,在使用这些命令之前设置一些变量可能很重要。有时,只有调试变量才有帮助。以下内容可能对您有帮助:
printf
通过使用message()
命令,只需使用旧的调试样式即可。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
,或一个非零数。0
,OFF
,NO
,FALSE
,N
,IGNORE
,NOTFOUND
,空字符串,或后缀结尾-NOTFOUND
。if(MSVC)
,但对于不了解此语法快捷方式的人可能会造成混淆。set(CMAKE_${lang}_COMPILER ...)
if()
。这是CMAKE_CXX_COMPILER_ID
is "MSVC"
和MSVC
is 的示例"1"
:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
是正确的,因为它评估为 if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
是错误的,因为它的计算结果为 if("MSVC" STREQUAL "1")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
为“仅if()
在不加引号的情况下将参数解释为变量或关键字”。option()
命令
if (MyString ...)
(如果您的代码给出警告)。
这里有一些基本示例,可以帮助您快速入门。
设置变量:
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}")
if ("${MyString}" ...)
我会看到警告:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
。参见,例如,Build 367。有任何想法吗?