Forcing C99 in CMake (to use 'for' loop initial declaration)

As this question keeps getting attention I'm summarizing here what I think are the best options today.

The following command sets C99 as a minimum requirement for target:

target_compile_features(target PUBLIC c_std_99)

I consider this the preferred way, as it is per target and exposes a way to control the visibility through the PUBLIC, INTERFACE and PRIVATE keywords - see the reference. Although the target_compile_features command was introduced on the 3.1 version, c_std_99 requires at least CMake 3.8.

Similar to the above, another way to set C99 as the standard for target is the following:

set_property(TARGET target PROPERTY C_STANDARD 99)

This is available since CMake 3.1. A possible drawback is that it doesn't enforce the standard (see the reference). For this reason setting the C_STANDARD_REQUIRED property may be useful:

set_property(TARGET target PROPERTY C_STANDARD_REQUIRED ON)

The above two properties are defaulted to the values of CMAKE_C_STANDARD and CMAKE_C_STANDARD_REQUIRED respectively.

So a possible way to make C99 default for all targets is:

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED TRUE)

As a side note, expanding on the target_compile_features approach, there may be no need to require some specific language standard if all you care about is some specific feature. For instance by setting:

target_compile_features(target PUBLIC c_variadic_macros)

CMake will take care to pick the proper flags that enforce the availability of variadic macros. However currently there are only a few such features available for the C language - see CMAKE_C_KNOWN_FEATURES for the complete list - and loop initial declarations is not among them.


After creating a target such as a library or executable, put a line like this in your CMakeLists.txt file:

set_property(TARGET tgt PROPERTY C_STANDARD 99)

where tgt is the name of your target.

I think this was added in CMake 3.1, and the documentation is here:

http://www.cmake.org/cmake/help/latest/prop_tgt/C_STANDARD.html

If you need to support versions of CMake older than 3.1, you can use this macro:

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)

After putting that macro in your top-level file so it is visible everywhere, you can just write use_c99() at the top of any CMakeLists file that defines a target with C99 code in it.

CMake issue #15943 for clang users targeting macOS

If you are using CMake and clang to target MacOS there is a bug that can cause the CMAKE_C_STANDARD feature to simply not work (not add any compiler flags). Make sure that you do one of the following things:

  • Use cmake_minimum_required to require CMake 3.0 or later, or

  • Set policy CMP0025 to NEW with the following code at the top of your CMakeLists.txt file before the project command:

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

In libevent, add the following in CMakeLists.txt

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

Tags:

C++

C

C99

Cmake