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=valuejust 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_IDis "MSVC"和MSVCis 的示例"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。有任何想法吗?