CMake IF with multiple conditions - if-statement

How to make if function with multiple conditions? I know CMake support if with 2 conditions, but how to make more than 3?
I need something like this:
if(WIN32 OR APPLE OR IOS)
set(LIBS)
endif()
Thanks

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 check what compiler cmake is using?

I'm surprised I couldn't find this googling. I only found this, but I want to known how to find what compiler is cmake using in general? I also found this but I assume there is some variable in cmake that just holds the compiler name, right?
You can see what variables are available in your CMake's binary output directory CMakeFiles/[your CMake's version]/CMakeCXXCompiler.cmake.
If you just want to print it, your are looking for CMAKE_CXX_COMPILER_ID and CMAKE_CXX_COMPILER_VERSION. Those are available cross-platform.
Here are two examples of what CMake detects and generates from my projects:
set(CMAKE_CXX_COMPILER_ID "GNU")
set(CMAKE_CXX_COMPILER_VERSION "4.6.3")
Or
set(CMAKE_CXX_COMPILER_ID "MSVC")
set(CMAKE_CXX_COMPILER_VERSION "19.0.24215.1")
Other kind of variables are there to check for platforms/toolchains like CMAKE_COMPILER_IS_GNUCXX.
I am not quite sure if I understood your question precisely, but if you just want to know which compiler is being used, enable a verbose build with the CMAKE_VERBOSE_MAKEFILE option:
cmake .. -DCMAKE_VERBOSE_MAKEFILE=ON
and then run make as usual. This will show which commands are used for building your code.

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

How to configure DBus dependencies with CMake

I am new to CMake and DBus. I am following along the guide here and make a basic program compile and execute.
The first problem that I ran into was my program will not find
<dbus/dbus.h>
I got around that issue by adding some include directories to my CMakeList.txt.
Currently, my CMakeLists.txt looks like this:
...
include_directories(/usr/lib/)
include_directories(/usr/include/dbus-1.0/)
include_directories(/usr/lib/x86_64-linux-gnu/dbus-1.0/include)
include_directories(/usr/include/glib-2.0)
include_directories(/usr/lib/x86_64-linux-gnu/glib-2.0/include/)
set (LIBS
dbus-1
dbus-glib-1
)
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${LIBS} )
Now, my program is complaining about not being able to find dbus-arch-deps.h
/usr/include/dbus-1.0/dbus/dbus.h:29:33: fatal error: dbus/dbus-arch-deps.h: No such file or directory
#include <dbus/dbus-arch-deps.h>
I know that the solution for this is to use proper command line flags or pkg-config. As discussed here and numerous other posts.
However, I do not know how to configure CMakeLists.txt to have similar effect.
My guess would be to add something like find_package(dbus-1) to CMakeLists.txt. And if that is correct, I am going to have to write my own Finddbus-1.cmake. Does this sound correct? Or is there an easier way?
I will appreciate any pointers.
You may get an existing FindDBus.cmake script (e.g., this one), copy it into your project, and use as
find_package(DBus REQUIRED)
# Use results of find_package() call.
include_directories(${DBUS_INCLUDE_DIRS})
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${DBUS_LIBRARIES})
Alternatively, as you know pkgconfig can find DBus, you may use CMake module PkgConfig. Actually, FindDBus.cmake script, referenced above, uses PkgConfig module in its implementation. Possible usage could be:
find_package(PkgConfig REQUIRED) # Include functions provided by PkgConfig module.
pkg_check_modules(DBUS REQUIRED dbus-1) # This calls pkgconfig with appropriate arguments
# Use results of pkg_check_modules() call.
include_directories(${DBUS_INCLUDE_DIRS})
link_directories(${DBUS_LIBRARY_DIRS})
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${DBUS_LIBRARIES})
However, using link_directories is not recommended, it is better to use absolute paths to libraries in target_link_libraries() call. That is why it is better to combine pkg_check_modules with find_library, as it is done in the referenced Find script. That answer describes generic way for use result of pkgconfig in CMake.

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

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