Documentation for Cmake -std parameters - cmake

I am using Clion which uses Cmake which uses a CMakeLists.txt that looks like this:
cmake_minimum_required(VERSION 3.3)
project(Thesis)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c99")
set(SOURCE_FILES main.cpp graph.h graph.c shared.h shared.c)
add_executable(Thesis ${SOURCE_FILES})
I have been searching and searching for an explanation on -std=c99. The default was -std=c++11 and I changed it because I am writting a C program, by intuition, I didn't see that keyword anywhere, I just guessed it. However, I don't fully understand what this parameter does, and I want to. What other parameters can it take ?
Where is that documentation exactly ?

First of all. If you are writing a C program, name your files .c - not .cpp to be sure that CMake identifies them as C code. This is the reason you see -std=c++11 by default.
You can then use SET(CMAKE_C_FLAGS ...) to add compiler flags even though this isn't the recommended way. You shall never assume that GCC will be called.
As #zaufi said. You can use:
set_property(TARGET Thesis PROPERTY C_STANDARD 99)
https://cmake.org/cmake/help/v3.1/prop_tgt/C_STANDARD.html#prop_tgt:C_STANDARD
The -std flag is a GCC compiler flag that determine which language features GCC shall enable. Read more here:
http://linux.die.net/man/1/gcc
-std=
Determine the language standard.
This option is currently only supported when compiling C or C ++ .
The compiler can accept several base standards, such as c89 or c++98,
and GNU dialects of those standards, such as gnu89 or gnu++98. By
specifying a base standard, the compiler will accept all programs
following that standard and those using GNU extensions that do not
contradict it. For example, -std=c89 turns off certain features of
GCC that are incompatible with ISO C90, such as the "asm" and
"typeof" keywords, but not other GNU extensions that do not have a
meaning in ISO C90, such as omitting the middle term of a "?:"
expression. On the other hand, by specifying a GNU dialect of a
standard, all features the compiler support are enabled, even when
those features change the meaning of the base standard and some
strict-conforming programs may be rejected.

Related

How to error out cleanly in CMake if CMAKE_CXX_STANDARD cannot be met?

CMake provides CMAKE_CXX_STANDARD for specifying the required C++ Standard.
set (CMAKE_CXX_STANDARD 17)
However, if your compiler is old... say gcc4... it will still attempt to compile the sources, and it will of course fail with bizarre error messages, due to missing compiler features.
Is there a clean way to make CMake detect this missing support, and fail in a more obvious way?
From https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_STANDARD.html :
See the cmake-compile-features(7) manual for information on compile features and a list of supported compilers.
From https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html#manual:cmake-compile-features(7) :
The CMAKE_C_KNOWN_FEATURES, CMAKE_CUDA_KNOWN_FEATURES, and CMAKE_CXX_KNOWN_FEATURES global properties contain all the features known to CMake, regardless of compiler support for the feature. The CMAKE_C_COMPILE_FEATURES, CMAKE_CUDA_COMPILE_FEATURES , and CMAKE_CXX_COMPILE_FEATURES variables contain all features CMake knows are known to the compiler, regardless of language standard or compile flags needed to use them.
From https://cmake.org/cmake/help/latest/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES :
cxx_std_17
Compiler mode is at least C++ 17.
Check:
if ("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
Using target_compile_features for more control
As KamilCuk mentioned in their answer, you can check for cxx_std_17.
Additionally, you can set the requirement on a target with:
target_compile_features(my_example_library PUBLIC cxx_std_17)
Source https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html#requiring-language-standards
This is more verbose, but it allows you to specify that only some targets need certain standards. The same syntax can also be used to require only specific features, full list found in CMAKE_CXX_KNOWN_FEATURES.
Simpler option for CMAKE_CXX_STANDARD, set CXX_STANDARD_REQUIRED
However, if you're using CMAKE_CXX_STANDARD, it's much easier to just set CMAKE_CXX_STANDARD_REQUIRED, e.g.:
# will affect any library/target defined after this
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
# also recommended, uses -std=c++17 instead of -std=gnu++17
# if you code is compatible with non-GCC compilers too
# set(CMAKE_CXX_EXTENSIONS OFF)
You'll get an error that looks something like:
CMake Error in CMakeLists.txt:
Target "my_example_library" requires the language dialect "C17" (with
compiler extensions). But the current compiler "GNU" does not support
this, or CMake does not know the flags to enable it.

How to detect C++11-... support of a compiler with CMake and react without failing generation

I did read this question: How to detect C++11 support in CMake. It basically tells me that CMake's support for detecting C++ features is very sophisticated when you want to fail generation if a certain compiler does NOT support the feature you are using in your code but also extremely limited when you want to react on this at generation time without failing.
What I would like to be able to do is not to fail but e.g. to define a different set of source files if certain features are not available in order to allow compilation of old c++03 code if needed and use the newer c++11-... ones if possible. Something like this would be great:
set(TARGET MyTarget)
if(CPP_STANDARD_VERSION GREATER_EQUAL 11)
set(SOURCE myModernFile.cpp)
else()
set(SOURCE myLegacyFile.cpp)
endif()
add_executable(${TARGET} ${SOURCE })
if(CPP_STANDARD_VERSION GREATER_EQUAL 11)
# Here failing would be fine if lambdas are not supported!
target_compile_features(${TARGET} PRIVATE cxx_lambdas)
endif()
When following this approach as recommended in the linked question:
foreach(i ${CMAKE_CXX_COMPILE_FEATURES})
message("${i}")
endforeach()
e.g. with Visual Studio 2013 with CMake 3.13.2 I am getting the following output:
cxx_std_98
cxx_std_11
cxx_std_14
cxx_std_17
cxx_std_20
cxx_alias_templates
cxx_auto_type
cxx_contextual_conversions
cxx_decltype
cxx_default_function_template_args
cxx_defaulted_functions
cxx_delegating_constructors
cxx_enum_forward_declarations
cxx_explicit_conversions
cxx_extended_friend_declarations
cxx_extern_templates
cxx_final
cxx_generalized_initializers
cxx_lambdas
cxx_local_type_template_args
cxx_long_long_type
cxx_nullptr
cxx_override
cxx_range_for
cxx_raw_string_literals
cxx_right_angle_brackets
cxx_rvalue_references
cxx_static_assert
cxx_strong_enums
cxx_template_template_parameters
cxx_trailing_return_types
cxx_uniform_initialization
cxx_variadic_macros
cxx_variadic_templates
To me the list makes sense for the specific features, but the general ones with the supported C++ standards apparently cannot be right as VS 2013 does not support C++20. Am I missing something?
Right now I ended up with more or less the same approach as described in the linked question: I check various compiler versions manually and then depending on that I set my CPP_STANDARD_VERSION property, but this seems very fragile to me. Is there really no other way?

"Rosetta" for switching to native CMake CUDA support

I want to switch a CMake-based project of mine to using CMake 3.8 and up's native support for CUDA. I know that, basically, I enable_language(CUDA), then use the regular add_target and add_library instead of the cuda_xxx variants of the same.
However, I'm not sure how to rewrite my code exactly. How do I...:
Set of global CUDA-related CMake variables , e.g. separable compilation, propagation of host flags?
Invoke the CUDA equivalent of CMAKE_CXX_STANDARDand friends?
Add dependencies on CUDA libraries which are not required by default (e.g. NVTX)
... and everything else?
Is there some uniform method to all this, or do I just have to memorize a bunch of new commands?
CMake's native CUDA support works very much in the same way as it does for C and C++ projects. Using CUDA instead of C++ is a similar process to using C instead of C++.
First of all, you should enable CUDA support in your project by adding:
project(myproject LANGUAGES CUDA)
This way, you shouldn't need to run enable_language, and your CMake cache will not be cluttered with the C and C++ compiler configuration generated by the default implied project(myproject LANGUAGES C CXX) you get when you write just project(myproject).
The equivalent of CMAKE_CXX_STANDARD for CUDA is CMAKE_CUDA_STANDARD, much like how there is also CMAKE_C_STANDARD. Additionally, there is CMAKE_CUDA_EXTENSIONS which can be configured to enable / disable compiler specific extensions (i.e. whether to choose -std=c++14 or -std=gnu++14). It's generally the case that if you see CMake variables of the form CMAKE_CXX_..... or CMAKE_C_....., there is an equivalent CMAKE_CUDA_...... And in general, where you see CXX or C in variables and properties, there may be a CUDA equivalent.
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
One thing to note however, is that these particular variables have target-specific equivalents in the form of target properties (both for C++ and CUDA):
set_target_properties(
myprojectlibrary PROPERTIES
CUDA_STANDARD 11
CUDA_STANDARD_REQUIRED ON
CUDA_EXTENSIONS OFF)
As for CUDA-specific features like in the old FindCUDA, you should find these as more target properties just like those in the previous example:
set_target_properties(
myprojectlibrary PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
CUDA_RESOLVE_DEVICE_SYMBOLS ON)
Information about these target properties can be found here, searching on the page for "CUDA".
As for linking to third-party libraries, this can be done the same way as it is done for regular C++ projects:
target_link_libraries(myprojectlib nvtx)
Or if your library isn't defined as a first-class CMake target:
target_link_libraries(myprojectlib ${NVTX_LIBRARY})
target_include_directories(myprojectlib PRIVATE ${NVTX_INCLUDE_DIR})
target_compile_definitions(myprojectlib PRIVATE ${NVTX_DEFINES})
Lastly, if there are any specific nvcc flags required to build your project, these can be set as follows:
target_compile_options(myprojectlib PRIVATE --default-stream=per-thread)
Note that the global user-configurable nvcc flags are also available as the variable CMAKE_CUDA_FLAGS.
Also note that you may have to change PRIVATE to PUBLIC in places where you want particular flags / include directories / compile definitions to also be propagated to targets linking to your library, in the case that myprojectlib is a library and not an executable, which may or may not be desired depending on how your project is structured.

CMake Fortran compiler-dependent flags

I'm using CMake for a moderate-sized Fortran project; sometimes I build it with gfortran, other times with ifort. When I want to do a debug build, the compiler flags are different; I'd like to have CMake automatically check which compiler is being used and set the flags accordingly.
It looks like this answer shows how to do the same thing for different C++ compilers. There's an example of how to check compilers with Fortran, using
if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
However, this fails to invoke the conditional, because CMake has decided to use f95. Of course, f95 happens to alias to gfortran, but CMake doesn't detect that.
What's the right way to do this?
You can use also use CMAKE_Fortran_COMPILER_ID:
if ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "Intel")
# something
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
# something else
endif
Best way is to read file CMakeDetermineFortranCompiler.cmake and related files referenced from it.
Rather than trying to special case for different compilers you should actually test that your compiler supports the flags you want to set using check_fortran_compiler_flag like so:
include(CheckFortranCompilerFlag)
check_fortran_compiler_flag("-my-flag" _my_flag)
if(_my_flag)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -my-flag")
endif()
This is both safer and (I think) simpler because you don't need the implied knowledge of which compiler (and version) supports which flag.
It's simple. Only indicate the full path of compiler installed e.g.gfortran. the code: cmake -DCMAKE_fortran_PATH=/usr/bin/gfortran

What are the possible values for the LANGUAGE variable in CMAKE

I haven't been able to find a list of possible values for the LANGUAGE variable on the CMAKE.org site or anywhere else. Would someone please enumerate the values CMAKE recognises? I specifically need to specify Objective C++.
Just take a look at all the CMakeDetermine<Language>Compiler.cmake scripts CMake ships with.
This would result - in alphabetic order - in the following you could put in the enable_language() call:
ASM
ASM-ATT
ASM-MASM
ASM-NASM
C
CSharp
CUDA
CXX
Fortran
Java
OBJC (Objective C)
OBJCXX (Objective C++)
RC (Windows Resource Compiler)
Swift
Evaluated with CMake Version 3.16
References
enable_language()
Generic rule from makefile to CMake
Update for CMake 3.16 and later: CMake added native support for Objective-C in version 3.16. The corresponding language strings are OBJC and OBJCXX. Thanks to squareskittles for pointing this out.
Original answer: The support for languages varies across platforms.
Currently CMake supports C, CXX and Fortran out of the box on most platforms. There is also support for certain Assemblers on some platforms. For a complete list, check out the contents of the Modules/Platform folder.
The idea is that the language given to the LANGUAGE field of the project command or the enable_language command is just a string, which will then be used by CMake together with the language dependent variables to setup the build system. The Platform scripts shipping with CMake do this configuration for C and C++. In theory, one can add their own language simply by setting the correct variables (although this is quite involved and I do not know of anyone ever successfully doing this).
As for adding support for Objective-C: Since most toolchains use the same compiler for C and Objective-C, you do not need to configure a new language. Simply compile your code as if it was plain C and add the appropriate compiler flags for Objective-C support.
Unfortunately, this is not very comfortable to use and can easily break in corner cases. But until CMake adds explicit support for Objective-C as a first class language, I'm afraid this is as good as it gets.