如何使用变量并避免CMP0054策略违规?

jww*_*jww 9 cmake

我们在测试CMP0054策略违规期间捕获错误.可以在Build 367在线找到一个例子.

cmake : CMake Warning (dev) at CMakeLists.txt:364 (if):
At line:8 char:5
+     cmake -G "Visual Studio 15 2017" -DCMAKE_BUILD_TYPE=$env:configur ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (CMake Warning (...s.txt:364 (if)::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

  Policy CMP0054 is not set: Only interpret if() arguments as variables or
  keywords when unquoted.  Run "cmake --help-policy CMP0054" for policy
  details.  Use the cmake_policy command to set the policy and suppress this
  warning.
  Quoted variables like "MSVC" will no longer be dereferenced when the policy
  is set to NEW.  Since the policy is not set the OLD behavior will be used.
This warning is for project developers.  Use -Wno-dev to suppress it.
Run Code Online (Sandbox Code Playgroud)

这是由于制作if语句如下:

if ("${CRYPTOPP_AMD64}" STREQUAL "1" OR "${CRYPTOPP_I386}" STREQUAL "1")
    ...
endif()
Run Code Online (Sandbox Code Playgroud)

上面的陈述与设置和使用变量的CMake语法是什么一致?,无论变量是否已设置,是否为空,具有0值,具有1值还是具有其他值,它是唯一似乎在任何地方"正常工作"的东西.

我们从变量中删除了引号,以满足该死的政策,一切都崩溃了.现在我们很幸运能够在没有错误的情况下完成CMake配置.我们尝试了:

if (${CRYPTOPP_AMD64} STREQUAL "1" OR ${CRYPTOPP_I386} STREQUAL "1")
    ...
endif()
Run Code Online (Sandbox Code Playgroud)

和:

if (${CRYPTOPP_AMD64} STREQUAL 1 OR ${CRYPTOPP_I386} STREQUAL 1)
    ...
endif()
Run Code Online (Sandbox Code Playgroud)

和:

if (${CRYPTOPP_AMD64} EQUAL 1 OR ${CRYPTOPP_I386} EQUAL 1)
    ...
endif()
Run Code Online (Sandbox Code Playgroud)

它们主要导致"CMakeLists.txt的CMake错误......如果给出参数......".例如,这是Solaris 11上的测试:

CMake Error at CMakeLists.txt:507 (if):
  if given arguments:

    "EQUAL" "1" "AND" "NOT" "DISABLE_SSSE3"

  Unknown arguments specified
Run Code Online (Sandbox Code Playgroud)

我们不控制用户计算机,因此更改策略和运行cmake_policy等命令对我们来说是不可能的.我们不希望用户做任何特别的事情.用户只需要创建一个目录,cd进入该目录,然后运行cmake.而已.

考虑到CMake的最新变化,我们应该使用什么语法来处理各种变量?

当我们说到处时,我们的意思是从Cmake 2.8到Current,以及可能处于任何状态的变量,包括set,empty,0值,1值或意外值.


编辑:我们现在正在Windows机器上捕获未引用变量的错误报告.当编译器路径有空格时, Windows CMake失败的另一个该死的CMake错误.

CMake已经在图书馆工作了两年.它占我们的bug报告者中18%的错误.它会给用户带来不成比例的问题.

Flo*_*ian 8

有两种解决方案:

  1. 只需将策略设置CMP0054为NEW

    cmake_policy(SET CMP0054 NEW)
    
    Run Code Online (Sandbox Code Playgroud)

    这将阻止 CMake 版本 >= 3.1 再次尝试将引号中的变量解释为变量名称(另请参阅此处的讨论,没有人真正想要这种OLD行为)。

    “OLD策略的行为根据定义已被弃用,并且可能会在 CMake 的未来版本中被删除”这一提示仅意味着 CMake 开发人员将在将来的某个时候删除仍然支持该行为所需的遗留代码OLD。

  2. 更改 - 正如 @Tsyvarev 评论的那样 - 所有if语句仅更改为变量名称,不带美元符号和大括号

    if (CRYPTOPP_AMD64 STREQUAL "1" OR CRYPTOPP_I386 STREQUAL "1")
        ...
    endif()        
    
    Run Code Online (Sandbox Code Playgroud)

    这也适用于旧版本的 CMake。

不能选择使用${ }不带引号的变量取消引用语法,因为它可能以空字符串结尾(导致这些if()语法错误)。

注意:作为解决方法,CMake 模块本身使用“x”前缀进行变量检查。但我觉得这看起来有点奇怪:

if ("x${CRYPTOPP_AMD64}" STREQUAL "x1" OR "x${CRYPTOPP_I386}" STREQUAL "x1")
    ...
endif()
Run Code Online (Sandbox Code Playgroud)

注意:只有CMP0054当变量的上下文实际上被再次求值时,您才会收到警告(因此这暗示您的 CMake 代码在这些地方将无法工作)。