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

时间:2017-08-26 22:27:27

标签: 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.

这是由于制作了如此的if语句:

if ("${CRYPTOPP_AMD64}" STREQUAL "1" OR "${CRYPTOPP_I386}" STREQUAL "1")
    ...
endif()

上面的陈述与What's the CMake syntax to set and use variables?一致,无论变量是否设置,是否为空,具有0值,具有1值,它是唯一似乎在任何地方“正常工作”的东西或者有其他价值。

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

if (${CRYPTOPP_AMD64} STREQUAL "1" OR ${CRYPTOPP_I386} STREQUAL "1")
    ...
endif()

if (${CRYPTOPP_AMD64} STREQUAL 1 OR ${CRYPTOPP_I386} STREQUAL 1)
    ...
endif()

if (${CRYPTOPP_AMD64} EQUAL 1 OR ${CRYPTOPP_I386} EQUAL 1)
    ...
endif()

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

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

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

  Unknown arguments specified

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

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

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

编辑 :我们现在正在Windows机器上捕获未引用变量的错误报告。还有Windows CMake failure when compiler path has a space的另一个该死的CMake错误。

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

2 个答案:

答案 0 :(得分:1)

有两种解决方案:

  1. 只需将政策CMP0054设为NEW

    即可
    cmake_policy(SET CMP0054 NEW)
    

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

    根据定义,不推荐使用"策略的OLD行为,并且可能会在未来版本的CMake中删除"只是意味着CMake开发人员将来会在某个时候删除仍然支持OLD行为所必需的遗留代码。

  2. 更改 - 正如@Tsyvarev所评论的 - 所有if语句只是变量名称而没有美元符号和大括号

    if (CRYPTOPP_AMD64 STREQUAL "1" OR CRYPTOPP_I386 STREQUAL "1")
        ...
    endif()        
    

    这也适用于旧版本的CMake。

  3. 在没有引号的情况下使用${ }变量解引用语法不是一种选择,因为它可能以空字符串结尾(导致那些if()语法错误)。

    注意:解决方法CMake modules itself正在使用" x"变量检查的前缀。但我觉得这看起来有点奇怪:

    if ("x${CRYPTOPP_AMD64}" STREQUAL "x1" OR "x${CRYPTOPP_I386}" STREQUAL "x1")
        ...
    endif()
    

    注意:如果您的变量的上下文再次被实际评估,则只会收到CMP0054警告(因此它暗示您的CMake代码在这些地方不起作用)

答案 1 :(得分:0)

您可以尝试通过添加以下命令(例如,版本3.15.1)将cmake最低必需版本设置为当前使用的版本:

cmake_minimum_required(VERSION 3.15.1)