cmake - 如何使用变量并避免违反 CMP0054 策略?

标签 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 值、1 值或意外值。

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

CMake 已经在库中使用了两年。它占我们错误报告器中错误的 18%。它会给用户带来不成比例的问题。

最佳答案

有两种解决方案:

  • 刚刚设置政策 CMP0054NEW
    cmake_policy(SET CMP0054 NEW)
    

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

    暗示“政策的 OLD 行为已被定义弃用,可能会在 CMake 的 future 版本中被删除”只是意味着 CMake 开发人员将在 future 某个时候删除仍然支持 OLD 所需的遗留代码。行为。
  • 更改 - 正如@Tsyvarev 所评论的 - 所有 if只对变量名的语句,没有美元符号和大括号
    if (CRYPTOPP_AMD64 STREQUAL "1" OR CRYPTOPP_I386 STREQUAL "1")
        ...
    endif()        
    

    这也适用于旧版本的 CMake。

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

    注意:作为一种解决方法 CMake modules itself正在使用“x”前缀进行变量检查。但我觉得这看起来有点奇怪:
    if ("x${CRYPTOPP_AMD64}" STREQUAL "x1" OR "x${CRYPTOPP_I386}" STREQUAL "x1")
        ...
    endif()
    

    注意:您只能获得 CMP0054如果您的变量的上下文实际上再次被评估,则发出警告(因此这暗示您的 CMake 代码将无法在这些地方工作)。

    关于cmake - 如何使用变量并避免违反 CMP0054 策略?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45900159/

    相关文章:

    cmake - CMake 用于检测 Ninja 的 Visual C++ 编译器工具的环境变量

    cmake - 如何在 CMAKE 中将标志传递给 nvcc 编译器

    windows-installer - 在 CMake + CPack + NSIS 中创建 Windows 桌面图标

    include - 如何通过 CMake 查找特定/本地文件

    cmake - 目录属性和子目录

    c++ - 从文件夹名称获取 makefile 参数

    c++ - 无法使用Visual Studio生成CMake文件

    c++ - 使用 Make 包含一个 .cpp 文件

    c++ - CMAKE指定不同的源目录

    c++ - Conan + CMake + C++ : Linking against Boost. 记录静态库失败