【问题标题】:Forcing C99 in CMake (to use 'for' loop initial declaration)在 CMake 中强制使用 C99(使用“for”循环初始声明)
【发布时间】:2014-09-10 11:29:21
【问题描述】:

我一直在寻找一种可移植的方式来强制 CMake 启用编译器的 C99 功能,以避免出现以下 gcc 错误,例如:

error: ‘for’ loop initial declarations are only allowed in C99 mode
for (int s = 1; s <= in_para->StepNumber; s++){
^

我也不想检查哪个编译器并附加如下内容:

set(CMAKE_C_FLAGS "-std=c99") # that would be bad

所以我找到了这篇文章:Enabling C99 in CMake 和相关的功能请求:0012300: CMake has no cross-platform way to ask for C99。在这个 Mantis 错误中,我了解了 target_compiler_features,之后我在上面找到了这些 SOF 答案:How to activate C++11 in CMake?How to detect C++11 support of a compiler with CMake

所以我的问题是:这个target_compiler_features 将提供一种既需要C 功能又需要C++ 功能的方法?到目前为止,实现这一目标的最便携方式是什么——我目前正在使用 CMake 2.8.12.2。 target_compiler_features 不在 CMake 的最新版本 (3.0.0) 中。你知道它什么时候发布吗?

【问题讨论】:

  • -std=c99 有什么不好?我就是这样做的。您可能没有超过两种不同的方式来支持不同的编译器(例如,Clang 和 GCC 是相同的)。
  • 我想要一些既适用于 gcc 又适用于 MSVC 而无需检查 CMAKE_C_COMPILER_ID 的东西。顺便说一句,我也使用-std=c99,但似乎有/会有更好的方法与target_compiler_features。
  • 也许有一天会有更好的东西。我不确定你的问题是什么。这不是 CMake 的发布日期预测网站。
  • 好吧,我想知道是否会有一些 cmake 开发人员注意到这个问题。另外,由于我引用的错误报告已经三年了,我还希望有人已经找到了一些更好的方法。此外,还有一些关于这个未来特性的答案,但只处理 C++11,所以我问它是否也适用于 C(因为我不愿意阅读它的代码和/或草稿文档) .
  • 据我所知 MSVC 根本没有实现 C99。

标签: c++ c cmake c99


【解决方案1】:

创建库或可执行文件等目标后,在 CMakeLists.txt 文件中添加如下一行:

set_property(TARGET tgt PROPERTY C_STANDARD 99)

tgt 是目标的名称。

我认为这是在 CMake 3.1 中添加的,文档在这里:

http://www.cmake.org/cmake/help/v3.1/prop_tgt/C_STANDARD.html

如果你需要支持 3.1 之前的 CMake 版本,你可以使用这个宏:

macro(use_c99)
  if (CMAKE_VERSION VERSION_LESS "3.1")
    if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
      set (CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}")
    endif ()
  else ()
    set (CMAKE_C_STANDARD 99)
  endif ()
endmacro(use_c99)

将该宏放入您的顶级文件以使其在任何地方都可见后,您只需在任何定义包含 C99 代码的目标的 CMakeLists 文件的顶部写入 use_c99()

针对 macOS 的 clang 用户的 CMake 问题 #15943

如果您使用 CMake 和 clang 来定位 MacOS,则有一个 bug 可能导致 CMAKE_C_STANDARD 功能根本不起作用(不添加任何编译器标志)。确保您执行以下操作之一:

  • 使用 cmake_minimum_required 要求 CMake 3.0 或更高版本,或者
  • project 命令之前,在 CMakeLists.txt 文件顶部使用以下代码将策略 CMP0025 设置为 NEW:

    # Fix behavior of CMAKE_C_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
    

【讨论】:

    【解决方案2】:

    随着这个问题不断受到关注,我在这里总结一下我认为当今最好的选择。

    以下命令将 C99 设置为 target 的最低要求:

    target_compile_features(target PUBLIC c_std_99)
    

    我认为这是首选方式,因为它是针对每个目标的,并且提供了一种通过 PUBLICINTERFACEPRIVATE 关键字控制可见性的方法 - 请参阅 the reference。虽然target_compile_features命令是在3.1版本上引入的,但c_std_99至少需要CMake 3.8

    与上述类似,另一种将 C99 设置为 target 标准的方法如下:

    set_property(TARGET target PROPERTY C_STANDARD 99)
    

    这从 CMake 3.1 开始可用。一个可能的缺点是它不强制执行标准(请参阅the reference)。出于这个原因,设置C_STANDARD_REQUIRED 属性可能很有用:

    set_property(TARGET target PROPERTY C_STANDARD_REQUIRED ON)
    

    以上两个属性默认分别为CMAKE_C_STANDARDCMAKE_C_STANDARD_REQUIRED的值。

    因此,使所有目标都默认使用 C99 的一种可能方法是:

    set(CMAKE_C_STANDARD 99)
    set(CMAKE_C_STANDARD_REQUIRED TRUE)
    

    附带说明,扩展target_compile_features 方法,如果您只关心某些特定功能,则可能不需要某些特定语言标准。例如通过设置:

    target_compile_features(target PUBLIC c_variadic_macros)
    

    CMake 会注意选择适当的标志来强制可变参数宏的可用性。然而,目前只有少数此类功能可用于 C 语言 - 请参阅 CMAKE_C_KNOWN_FEATURES 以获取完整列表 - 循环初始声明不在其中。

    【讨论】:

      【解决方案3】:

      在 libevent 中,在 CMakeLists.txt 中添加以下内容

      set (CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}")
      

      【讨论】:

      • 请详细解释一下,为什么这是正确答案。
      【解决方案4】:

      编辑 CMakeLists

      在线添加 > 2

      set (CMAKE_C_STANDARD 99)
      

      然后

      cmake 3 ..
      

      【讨论】:

        【解决方案5】:

        C_STANDARD property 将允许将 C 标准应用于特定目标,而不是全局。以下将C99应用于mytarget

        set_property(TARGET mytarget PROPERTY C_STANDARD 99)
        

        【讨论】:

          【解决方案6】:

          从 CMake 3.0.2 开始,可以使用 add_compile_options (https://cmake.org/cmake/help/latest/command/add_compile_options.html#command:add_compile_options),这是我发现设置 C 标准的最便携的方法之一。

          在声明目标之前请注意使用此命令(使用 add_library 或 add_executable)。

          下面是一个将 C 标准设置为 C99 的 CMake 脚本示例:

          add_compile_options(-std=c99)
          add_executable(my_exe ${SOURCES})
          

          【讨论】:

          • 也许您只考虑 CMake 3.0 版?因为这不是从 CMake 3.8 开始的最便携的方式,它可以将 target_compile_features 设置为 c_std_99。例如 -std=c99 将破坏 MSVC 构建,没有类似的方法需要 C99 标准(但接受带有 /std:c11 的 C11 规范)。
          • @Tarc :target_compile_features 和更多一般 Cmake 编译功能的问题是这些属性不适用于所有编译器。它们仅适用于以下编译器: A. 对于 C++ 标准:Cray 编译器环境版本 8.1+、PGI 版本 12.10+、IBM XL 版本 10.1+。 B. 对于 C 标准:上面列出的所有编译器和版本仅具有 C++ 的元功能,德州仪器编译器。 source
          【解决方案7】:

          将以下内容添加到您的 CMakeLists.txt 文件中并再次运行 cmake

          set(CMAKE_C_FLAGS "std=c99")
          

          【讨论】:

          • @SeanBurton 好点,同时,我认为很多人都像我一样使用 SO,直接跳到答案,所以 FWIW 我在这里找到了答案,而不是在 OP 中 :) (当然,我最终会仔细检查 OP!)
          猜你喜欢
          • 2015-07-21
          • 2011-08-18
          • 2013-01-19
          • 2017-10-28
          • 2010-09-06
          • 2016-05-08
          • 2013-10-28
          相关资源
          最近更新 更多