34

I've been searching a portable way to force CMake to enable the compiler's C99 features in order to avoid the following gcc error for instance:

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

I also wouldn't like to check for which compiler and append something like:

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

So I found this post: Enabling C99 in CMake and the associated feature request: 0012300: CMake has no cross-platform way to ask for C99. In this Mantis bug I learned about target_compiler_features and after that I found these SOF answers on it: How to activate C++11 in CMake? and How to detect C++11 support of a compiler with CMake.

So my questions are: this target_compiler_features will provide a way to require a C feature as well as a C++ one? What is the most portable way to achive this by now - I'm currently using CMake 2.8.12.2. The target_compiler_features isn't in CMake's most recent release version (3.0.0). Do you know when it is being released?

Community
  • 1
  • 1
Tarc
  • 3,214
  • 3
  • 29
  • 41
  • 1
    What's so bad about `-std=c99`? That's the way I'd do it. You probably don't have more than two different ways you need to support for different compilers (e.g. Clang and GCC are the same). – John Zwinck Jul 19 '14 at 12:42
  • I would like something that would work for both gcc and MSVC without having to check for CMAKE_C_COMPILER_ID. By the way, I also use -std=c99, but it seems that there is / there will be a better approach with target_compiler_features. – Tarc Jul 19 '14 at 12:47
  • 1
    Maybe someday there will be something better. I'm not sure what your question is then. This isn't a release-date forecasting site for CMake. – John Zwinck Jul 19 '14 at 12:52
  • Well, I was wondering if there would be a chance some cmake dev notices this question. Also, as the bug report I cite is already three years old I was also hoping that someone have already figured out some better approach. Also, there are some answers on this future feature but only dealing with C++11, so I'm asking if it will apply also to C (as I'm not willing to read the code and/or draft documentation of it). – Tarc Jul 19 '14 at 13:14
  • It sounds like you should ask the CMake devs directly using their preferred method of contact (perhaps a mailing list), rather than hoping one of them stumbles upon this. – John Zwinck Jul 19 '14 at 13:15
  • 3
    As far as I know MSVC simply doesn't implement C99. – Jens Gustedt Jul 19 '14 at 13:25
  • @Jens Gustedt [This](http://blogs.msdn.com/b/vcblog/archive/2013/07/19/c99-library-support-in-visual-studio-2013.aspx) may help – chux - Reinstate Monica Jun 23 '15 at 21:27
  • @chux, this only talks about C library support, not about the core language or the preprocessor. – Jens Gustedt Jun 23 '15 at 22:03

7 Answers7

33

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 ()
    
starball
  • 20,030
  • 7
  • 43
  • 238
David Grayson
  • 84,103
  • 24
  • 152
  • 189
6

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.

Tarc
  • 3,214
  • 3
  • 29
  • 41
0

In libevent, add the following in CMakeLists.txt

set (CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}")
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
杨佩文
  • 49
  • 1
  • 1
    Please explain in more detail, why that is the correct answer. – Geshode Jun 18 '18 at 01:41
  • This does not work for all compilers and might clash with user setting, leading to multiple std commands in the compiler invocation - which is very confusing. – usr1234567 May 07 '23 at 06:08
-1

Edit CMakeLists

add on line > 2

set (CMAKE_C_STANDARD 99)

then

cmake 3 ..
Digital Human
  • 1,599
  • 1
  • 16
  • 26
-1

The C_STANDARD property will allow use to apply the C standard to a specific target, rather than globally. The following will apply C99 to mytarget.

set_property(TARGET mytarget PROPERTY C_STANDARD 99)
RobLoach
  • 2,066
  • 1
  • 12
  • 5
-2

From CMake 3.0.2, it is possible to use add_compile_options (https://cmake.org/cmake/help/latest/command/add_compile_options.html#command:add_compile_options), it is one of the most portable way I found to set C standart.

Take care to use this command before to declare target (with add_library or add_executable).

Below is a CMake script example setting C standart to C99:

add_compile_options(-std=c99)
add_executable(my_exe ${SOURCES})
quent
  • 1,936
  • 1
  • 23
  • 28
  • 1
    Maybe you're considering only CMake version 3.0? Because this cannot be the most portable way starting with CMake 3.8, which enable setting `target_compile_features` to c_std_99. For instance -std=c99 will break MSVC builds, for which there's no analog way of requiring C99 standard (but accept a C11 specification with /std:c11). – Tarc Nov 19 '20 at 23:56
  • @Tarc : The problem of target_compile_features and more in general Cmake Compile Features is that these properties don't work with all compiler. They works only with these compiler: A. For C++ standard: Cray Compiler Environment version 8.1+, PGI version 12.10+, IBM XL version 10.1+. B. For C standard: all compilers and versions listed above with only meta-features for C++, Texas Instruments compiler. [source](https://cmake.org/cmake/help/v3.18/manual/cmake-compile-features.7.html#supported-compilers) – quent Nov 25 '20 at 15:15
-3

Add the following to your CMakeLists.txt file and run cmake again

set(CMAKE_C_FLAGS "std=c99")
  • 1
    @SeanBurton good point, at the same time, I think a lot of people use SO like I do, skipping directly to the answers, so FWIW I found the answer here, not in OP :) (of course I would have scrutinized OP eventually!) – JimLohse Dec 26 '17 at 00:18