我问这个问题是为了提醒自己下次使用CMake。它从来没有坚持过,谷歌的结果也不是很好。

在CMake中设置和使用变量的语法是什么?


当前回答

这里有几个基本的例子可以让你快速上手。

一项变量

设置变量:

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文档

其他回答

$ENV{FOO}用于使用,其中FOO是从环境变量中获取的。否则使用${FOO},其中FOO是其他变量。对于设置,SET(FOO " FOO ")将在CMake中使用。

在编写CMake脚本时,你需要了解很多关于语法以及如何在CMake中使用变量的知识。

的语法

使用set()的字符串:

set(MyString“Some Text”) set(MyStringWithVar "Some other Text: ${MyString}") set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")

或者使用string():

MyStringWithContent (${MyString})

使用set()列出:

set(MyList "a" "b" "c") (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:变量列表字符串 CMake:有用的变量 CMake set()命令 CMake字符串()命令 CMake list()命令 生成器表达式

作用域或“我的变量有什么值?”

首先是“正常变量”,你需要了解它们的范围:

Normal variables are visible to the CMakeLists.txt they are set in and everything called from there (add_subdirectory(), include(), macro() and function()). The add_subdirectory() and function() 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 setting set(${_resultVar} 1 PARENT_SCOPE) On the other hand everything you set in include() or macro() scripts will modify variables directly in the scope of where they are called from.

其次是“全局变量缓存”。关于缓存你需要知道的事情:

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 a docstring. I normally don't use the GUI so I use set(... CACHE INTERNAL "") to set my global and persistant values. Please note that the INTERNAL cache variable type does imply FORCE 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, just cmake -D var=value or with cmake -C CMakeInitialCache.cmake. You can unset entries in the Cache with unset(... CACHE).

缓存是全局的,你可以在CMake脚本的任何地方设置它们。但是我建议你在使用缓存变量时三思(它们是全局的并且是持久化的)。我通常更喜欢set_property(GLOBAL PROPERTY…)和set_property(GLOBAL APPEND PROPERTY…)语法来定义我自己的非持久化全局变量。

变量陷阱和“如何调试变量更改?”

为了避免陷阱,你应该了解以下关于变量的知识:

Local variables do hide cached variables if both have the same name The find_... commands - if successful - do write their results as cached variables "so that no call will search again" 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" and set(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 of macros() 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() and enable_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.

有时只有调试变量才有帮助。以下建议可能会对你有所帮助:

Simply use old printf debugging style by using the message() 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.

特殊的语法

Environment Variables You can can read $ENV{...} and write set(ENV{...} ...) environment variables 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 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. 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. 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 where CMAKE_CXX_COMPILER_ID is "MSVC" and MSVC is "1": if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") is true, because it evaluates to if("1" STREQUAL "1") if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") is false, because it evaluates to if("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 interpret if() arguments as variables or keywords when unquoted." The option() command Mainly just cached strings that only can be ON or OFF and they allow some special handling like e.g. dependencies But be aware, don't mistake the option with the set command. The value given to option 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.

参考文献

如何使用CMake ? cmake,迷失在全局变量的概念中(以及PARENT_SCOPE或add_subdirectory替代选项) 循环遍历字符串列表 如何存储CMake构建设置 用STREQUAL比较空字符串失败 什么时候我应该引用CMake变量?

这里有几个基本的例子可以让你快速上手。

一项变量

设置变量:

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文档