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

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?

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 ()

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.

In libevent, add the following in CMakeLists.txt
set (CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}")

Edit CMakeLists
add on line > 2
set (CMAKE_C_STANDARD 99)
then
cmake 3 ..

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)

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})

Add the following to your CMakeLists.txt file and run cmake again
set(CMAKE_C_FLAGS "std=c99")

Related

Alternatives for CMake commands

I am new to CMake and was going through the CMake documentations and tutorials. I was able to understand that the target_include_directories command is just the -I option for the compiler (gcc for me). I tried doing it adding the directories manually by using set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I <Path>") and it worked perfectly fine!!
My CMakeLists.txt looks something like this:
cmake_minimum_required(VERSION 3.6)
project(Project VERSION 1.0 DESCRIPTION "C Project" LANGUAGES C)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I <path-to-header>")
add_library(basic file1.c file2.c)
#target_include_directories(basic PUBLIC "path-to-header")
#target_include_directories() is commented out as CMAKE_C_FLAGS have been set
add_executable(main.out main.c)
target_link_libraries(main.out PRIVATE basic)
I wanted to know if there any similar and alternative for the target_link_libraries command using which we can pass -L and -l options to linker in CMake??
To answer your question literally: There is the variable CMAKE_EXE_LINKER_FLAGS and its specializations CMAKE_EXE_LINKER_FLAGS_<CONFIG> for certain configurations like RELEASE or DEBUG or whatever configurations you might have defined. See the CMake documentation for more.
BUT, I highly disrecommend to use these unless you need to pass a very special compiler/linker option CMake does not know about, because these are specific to your compiler.
The point of using CMake is to describe the build process independent of the concrete compiler and platform, such that you can easily switch to another one or at least update your compiler without having to refactor your build code. So, better stick with the generic target_include_directories, target_link_libraries, and similar commands as much as possible.
If you really have to use CMAKE_C_FLAGS or CMAKE_EXE_LINKER_FLAGS I'd recommend to wrap them into an if clause making sure that you are building with the expected compiler on the expected platform and put a fatal error message into the else clause to make future users aware of a possible problem.

How to bump the C++ standard from the CMake command line?

Currently I have a project that needs C++17, therefore in the CMakeLists.txt I have this line pretty early on:
set(CMAKE_CXX_STANDARD 17)
From the command line (cmake) once in a while I want to test that the project also compiles with C++20. (to avoid surprises).
How can I choose to compile with C++20 from command line?
If I do cmake -DCMAKE_CXX_STANDARD=20 then it is later overwritten by the configuration instead of 17 being interpreted as just a minimum requirement.
I could check if the variable is predefined to avoid overwritting but I was looking for a more declative way to specify this.
(I am using cmake around 3.18.)
The solution is to remove that set command and use target properties instead:
# set(CMAKE_CXX_STANDARD 17)
target_compile_features(myexecutable PUBLIC cxx_std_17)
Then, setting -DCMAKE_CXX_STANDARD=20 on the terminal should work again.
Make CMAKE_CXX_STANDARD a cache variable. This allows you to easily specify a default that can be overwritten via the command line. Note that you need to make sure no "normal" CMAKE_CXX_STANDARD variable is available, since this value would take precedence over the cache variable.
set(CMAKE_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for this project")
add_library(...)
Using cmake -D CMAKE_CXX_STANDARD=20 binary_dir should allow you to update the standard now, cmake -U CMAKE_CXX_STANDARD binary_dir should revert back to the default.
Alternatively you could create a custom cache variable. This would make a reuse easier, since it would allow you to overwrite the property, even if someone else sets CMAKE_CXX_STANDARD before using add_subdirectory to add your project.
set(MYPROJECT_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for myproject")
# overwrite possibly preexisting value for this directory and subdirectories
set(CMAKE_CXX_STANDARD ${MYPROJECT_CXX_STANDARD})
add_library(...)

Appending CXX_FLAGS in cmake invocation [duplicate]

This question already has answers here:
Passing compiler options in CMake
(6 answers)
Closed 5 years ago.
I am wondering if it is possible to append to inferred variables when calling cmake. Due either the compiler or the app supplied CMakeLists.txt C++11 support isn't detected by cmake even though it is supported and the application requires it. If I do:
cmake-DCMAKE_CXX_FLAGS='-std=c++11' ../source_dir
The flags get overwritten and I wouldn't like to lose the inferred flags. I could manually run without overwriting and just copy the flags and append c++11 but I think there must be a better solution.
I have found a number of posts on adding c++11 support to CMakeLists.txt but not in cmake call, so I am wondering if this is possible at all. Please let me know.
Yes, this is possible. First, create a variable called MY_FLAGS in the command line with the flags you want.
cmake -DMY_FLAGS='-std=c++11' ../source_dir
Then, in your CMakeLists.txt, do the following:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_FLAGS}")
This will effectively amend your flags to the flags that CMake generates. However, if you want to set the C++ standard to C++11, you can just do the following without directly dealing with flags:
cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD_REQUIRED=ON ../source_dir
On a side note, make sure that the ../source_dir is after the CMake options, since otherwise CMAKE_CXX_STANDARD_REQUIRED would not work. (Read)
I recently did this, when building a dependency for one of the applications I work to.
There are 2 CMake variables that you can make use of, namely:
-DCMAKE_BUILD_TYPE=Debug/Release
-DCMAKE_CXX_FLAGS_[DEBUG/RELEASE]
When specifying a build type, cmake will add to the compiler flags the flags that are specified in that second variable. So for me, using:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE=-fPIC
did the thing.
In your case, you can try the following approaches:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS_RELEASE=-std=c++11
or
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS_DEBUG=-std=c++11
Of course, this will work if the variables are not overwritten in the script. Try both approaches.
You are probably looking for
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
Or via command line:
cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD_REQUIRED=ON
That being said, CMAKE_CXX_FLAGS is not overridden by cmake, so your CMakeLists.txt must be doing it somewhere.
The polite way of setting the flags from within a script is to append to the variable, that is:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} stuff")

CMake: Can subdirectories inherit compile features?

I have a C++ project that consists of a main program (main.cpp), a header that defines an abstract class (algorithm.hpp), and a subdirectory (algorithms/) full of classes that implement the abstract class. I've configured CMake to build the subdirectory as an object library:
# algorithms/CMakeLists.txt
add_library(algorithms_lib OBJECT
algo1.cpp
algo2.cpp
# etc.
)
In my project's root directory, I use this object library as one of the application's sources:
# Top-level CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(MyApp CXX)
add_subdirectory(algorithms)
add_executable(my-app
main.cpp
$<TARGET_OBJECTS:algorithms_lib>
)
My application is written in C++14, so I need to tell CMake to use the correct compile options for that. I don't want to require CMake version 3.8 (since it's not packaged in some recent Linux distros that I want to support), so I can't use the cxx_std_14 compile feature; instead, I've listed a bunch of individual language features that I use:
# Top-level CMakeLists.txt (cont.)
target_compile_features(my-app PUBLIC
cxx_auto_type
cxx_constexpr
cxx_defaulted_functions
# ...14 more lines...
)
The problem is, these features only apply to the top-level my-app target, not the algorithms_lib target, so the sources in the subdirectory don't get compiled as C++14.
I know I could copy the whole big target_compile_features block into algorithms/CMakeLists.txt, but I'd rather not do that — especially since this example is simplified and I actually have nine such subdirectories, each building its own object library. That'd be a lot of duplication of boilerplate code.
Is there a way to set compile features globally for all C++ targets in the project, including subdirectories? Or would it be better to get rid of add_subdirectory and the object library, and just list all the individual subdirectory files in the top-level add_executable command? I'm new to CMake, so I don't know what the "best practices" are for this sort of thing.
It sounds like you want to put the following at the top of your CMakeLists.txt file:
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
These set defaults for the same-named target properties without the leading CMAKE_. The equivalent target properties do the following:
CXX_STANDARD yy sets the desired minimum C++ standard your code wants to use.
CXX_STANDARD_REQUIRED bb says whether CXX_STANDARD is a requirement (bb is YES or some other boolean equivalent) or whether it is just desirable (bb is NO or equivalent).
CXX_EXTENSIONS bb enables (bb = YES) or disables (bb = NO) compiler extensions.
You don't need to specify individual compiler features to achieve what you're ultimately trying to do (enable C++14 for your targets). You can find a full discussion of this whole area here.

CMake 3.0 add_library of type INTERFACE breaks get_target_property

I want to add a header only directory to a cmake project which I am using in Windows 7 with Visual Studio 2013 Update 2. I did some research and came up with this Cmakelists.txt file:
add_library(AAA_lib INTERFACE)
target_include_directories(AAA_lib
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
This appears to work however in some of our internal cmake code we call get_target_property:
get_target_property(target_libraries ${target} LINK_LIBRARIES)
This generates a CMake error:
CMake Error at x_common_libs/xml/xsdmap.cmake:41 (get_target_property):
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property "LINK_LIBRARIES" is not allowed.
It seems like an odd error since a get should only return targets with the appropriate property. Is this a bug in CMake? Or is there some other way that this should be implemented?
Why do we need to call get_target_property?
We have a cmake helper function which recursively goes through all of dependencies of a project building up a list of all dependent projects that require some custom post processing. So if project X uses project B and C and C uses D, then we get a list of X, B, C, D and then check to see which directories match a requirement and then call a custom_command.
Thanks,
Jason
Seems that it is CMake bug. There is new target type in CMake 3.0 called INTERFACE_LIBRARY. You are supposed to use only some of properties for this type. However, I don't think it was expected to raise an error in case of reading other properties.
I came out with the following workaround:
get_target_property(_TARGET_TYPE ${target} TYPE)
if(_TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
unset(target_libraries)
else()
get_target_property(target_libraries ${target} LINK_LIBRARIES)
endif()
This is a restriction that was lifted in CMake 3.19.
See https://gitlab.kitware.com/cmake/cmake/-/issues/19145 for details.