CMake Fortran compiler-dependent flags - cmake

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

Related

Set preprocessor symbol in QtCreator code model only using CMake

I'm working on a CMake-based project that contains both C++ and CUDA source files, and has some headers meant to be included by both languages.
For these header files, I'd like to see the result of highlighting and syntax checking as close as possible to what NVCC, the CUDA compiler, would see, so for example, I'd like to have the preprocessor symbol __CUDACC__ be defined.
It's important to me that CMake does not have such a symbol defined, because it's really an internal symbol of the NVCC toolchain that I need for syntax-checking purposes.
I've tried "Tools->C++->Additional preprocessor directives" and it seems to have no effect. I've also tried a file named CMakeLists.txt.config which seems to have no effect either.
I'd love a suggestion for this.
To reiterate, I'm looking for a way to set a define (CPP symbol) visible to to the syntax-checking system only.
After further digging I found an attribute specific to the Clang analyzer that is defined during the analysis performed for syntax checking but not during compilation.
Note that this is purely because my project compiles with GCC, while QT Creator's syntax checking runs through Clang.
// GCC and NVCC don't have __has_feature(), so we provide a fallback
#ifndef __has_feature
# define __has_feature(x) 0
#endif
#if __has_feature(attribute_analyzer_noreturn)
# define IN_CLANG_ANALYZER 1
#else
# define IN_CLANG_ANALYZER 0
#endif
This allows a clumsy hack as follows, which may or may not be useful, depending on one's needs. Pretty much the idea is that much like you'd
have Clang observe your code even if you compile with GCC, this achieves
something similar for files inteded to be used with NVCC.
#if IN_CLANG_ANALYZER and !defined(__CUDACC__)
# define __CUDACC__
# include <cuda_device_runtime_api.h>
# include <optix_device.h>
#endif
However the substantial problem remains that when compiling with Clang, all the above falls flat on its face, because clang++, the compiler, also defines the same feature as enabled.
What's needed to fix this is some kind of macro defined in the analyzer but not in Clang, and so far I've found none like this.
At first I had hoped __clang_analyzer__ would fit this need,
but according to my version of Qt Creator (6.0.2) the macro is not defined
during syntax checking, so we're back to square one.

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.

Change toolchain in a subfolder with cmake [duplicate]

It seems like CMake is fairly entrenched in its view that there should be one, and only one, CMAKE_CXX_COMPILER for all C++ source files. I can't find a way to override this on a per-target basis. This makes a mix of host-and-cross compiling in a single CMakeLists.txt very difficult with the built-in CMake facilities.
So, my question is: what's the best way to use multiple compilers for the same language (i.e. C++)?
It's impossible to do this with CMake.
CMake only keeps one set of compiler properties which is shared by all targets in a CMakeLists.txt file. If you want to use two compilers, you need to run CMake twice. This is even true for e.g. building 32bit and 64bit binaries from the same compiler toolchain.
The quick-and-dirty way around this is using custom commands. But then you end up with what are basically glorified shell-scripts, which is probably not what you want.
The clean solution is: Don't put them in the same CMakeLists.txt! You can't link between different architectures anyway, so there is no need for them to be in the same file. You may reduce redundancies by refactoring common parts of the CMake scripts into separate files and include() them.
The main disadvantage here is that you lose the ability to build with a single command, but you can solve that by writing a wrapper in your favorite scripting language that takes care of calling the different CMake-makefiles.
You might want to look at ExternalProject:
http://www.kitware.com/media/html/BuildingExternalProjectsWithCMake2.8.html
Not impossible as the top answer suggests. I have the same problem as OP. I have some sources for cross compiling for a raspberry pi pico, and then some unit tests that I am running on my host system.
To make this work, I'm using the very shameful "set" to override the compiler in the CMakeLists.txt for my test folder. Works great.
if(DEFINED ENV{HOST_CXX_COMPILER})
set(CMAKE_CXX_COMPILER $ENV{HOST_CXX_COMPILER})
else()
set(CMAKE_CXX_COMPILER "g++")
endif()
set(CMAKE_CXX_FLAGS "")
The cmake devs/community seems very against using set to change the compiler since for some reason. They assume that you need to use one compiler for the entire project which is an incorrect assumption for embedded systems projects.
My solution above works, and fits the philosophy I think. Users can still change their chosen compiler via environment variables, if it's not set then I do assume g++. set only changes variables for the current scope, so this doesn't affect the rest of the project.
To extend #Bill Hoffman's answer:
Build your project as a super-build, by using some kind of template like the one here https://github.com/Sarcasm/cmake-superbuild
which will configure both the dependencies and your project as an ExternalProject (standalone cmake configure/build/install environment).

Pass target file name as compile definition in cmake

I have CMakeLists.txt with many targets and the targets have configuration-specific suffixes defined. Additionally I want to know the name of the executable inside the program.
Under MSVC++ I do this by defining
add_definitions("-DTARGET_FILE_NAME=\"$(TargetFileName)\"")
But this does not work in other generators. Now that CMake got generator expressions, is there a way that would work with any generator?
I tried something like
add_definitions(-DTARGET_FILE_NAME=$<TARGET_FILE_NAME:$<TARGET_PROPERTY:NAME>>)
but even
add_definitions(-DTARGET_FILE_NAME=$<TARGET_PROPERTY:NAME>)
just places the unescaped $<TARGET_PROPERTY:NAME> in the buildfile. I also tried with just$`, but no luck either.
Note that the compile build command does not know the name of the linker output in many build files, so there does not seem to be any generator-specific hack for some of them either.
compile_definitions does not support generator expressions. Use target_compile_definitions, which does:
target_compile_definitions(somelib PRIVATE NAME=$<TARGET_FILE_NAME:somelib>)
http://www.cmake.org/cmake/help/v3.1/command/target_compile_definitions.html

CMake and clang_complete

I'm wanting to setup my CMakeLists.txt file so that it can generate the .clang_complete file required by the vim plugin clang_complete.
Ordinarily, you would do this by passing a parameter to the python script it supplies with the compiler and all of the parameters for compilation. Note that I am omitting the actual directory cc_args.py is in to save on space.
cc_args.py gcc test.c -o test -I~/IncludeDirs/
You can also do this during the make phase...
make CC='cc_args.py gcc' CXX='cc_args.py g++'
However, I am unsure of how to (if it is possible to) set this up within a CMakeLists.txt file. It's really annoying to have to type this in every time I want to setup clang_complete. The reason why I want to do it this way, is because I have multiple projects that I use a custom script to build the CMakeLists.txt file, so having to write a script for each one or manually place a generic one is a step I'd like to avoid.
I've tried a couple of things that have so far have come up with errors.
I've tried setting CMAKE_CC_COMPILER and CMAKE_CXX_COMPILER to lines similar to the first i.e. "cc_args.py g++". The errors that come up here say that It can't find the compiler (which is understandable).
The next thing I tried was setting the Compiler variables just to the cc_args.py and adding a flag for the actual compiler: suffice to say, that failed horribly. CMake said that it couldn't compile a test program (considering the script isn't a compiler, and the tests don't use the flags I set, I'm not surprised at this).
So without writing any other external scripts that require moving around, is there anyone that can think of a way that can do this?
The solution is to set the CXX environment variable before executing cmake. Something like that:
CXX="$HOME/.vim/bin/cc_args.py clang++" cmake ..
make
See http://www.guyrutenberg.com/2013/01/29/vim-creating-clang_complete-using-cmake/ for more details.
I know you said "without writing any other external scripts," but it seems like you just need a one-liner:
exec cc_args.py g++
And then set that file as your CMAKE_CXX_COMPILER. You could even use CMake's file() function to write the one-liner at build time if you don't want to have to distribute it.