238

I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).

This is for an Android device, and I only want to use CMake, not ndk-build.

For example - first.cpp

#include <iostream>

using namespace std;

int main()
{
   try
   {
   }
   catch (...)
   {
   }
   return 0;
}

./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions

It works with no problem...

The problem ... I am trying to compile the file with a CMake file.

I want to add the -fexceptions as a flag. I tried with

set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )

and

set ( CMAKE_C_FLAGS "fexceptions")

It still displays an error.

Blacktempel
  • 3,707
  • 3
  • 24
  • 48
solti
  • 3,720
  • 2
  • 28
  • 43
  • right now I'm having the same problem, and I'm trying different things. Hang a little and I post an answer. For compile flags, there is an unclean but easy way : add_definitions("-truc") – Offirmo Aug 03 '12 at 13:43
  • For a more up-to-date discussion on this question (especially if you are using CMake 3.x or newer): [What is the modern method for setting general compile flags in CMake?](http://stackoverflow.com/questions/23995019/what-is-the-modern-method-for-setting-general-compile-flags-in-cmake/23995391#23995391). – ComicSansMS Jul 09 '15 at 07:35
  • If the link flags you want aim at configuring **rpath** then have a look at the specific CMake rpath commands https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling – Gabriel Devillers Apr 19 '19 at 14:59

6 Answers6

263

Suppose you want to add those flags (better to declare them in a constant):

SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS    "-lgcov")

There are several ways to add them:

  1. The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):

    add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
    
  2. Appending to corresponding CMake variables:

    SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
    SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
    
  3. Using target properties, cf. doc CMake compile flag target property and need to know the target name.

    get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
    if(TEMP STREQUAL "TEMP-NOTFOUND")
      SET(TEMP "") # Set to empty string
    else()
      SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
    endif()
    # Append our values
    SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
    set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
    

Right now I use method 2.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Offirmo
  • 16,196
  • 8
  • 69
  • 90
  • 4
    why is add_definitions() unclean? – leinaD_natipaC Oct 09 '14 at 16:15
  • 16
    @leinaD_natipaC: The [official documentation](http://www.cmake.org/cmake/help/v3.0/command/add_definitions.html) says: _This command can be used to add any flags, but it is intended to add preprocessor definitions_. I think that's why. – Benoit Blanchon Nov 21 '14 at 17:01
  • 2
    While this is the accepted answer this really show very old style CMAKE, refer to the answer by @vitaut for how any new CMAKE code should be structured with regard to compile time parameters – Harald Scheirich Apr 29 '20 at 13:35
  • 1
    `string(APPEND CMAKE_EXE_LINKER_FLAGS "new_value")` is shorter and cleaner than `set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} new_value")` – bloody Apr 30 '20 at 13:21
  • outdated advice – apmccartney Mar 17 '21 at 15:09
194

In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):

target_compile_options(first-test PRIVATE -fexceptions)

The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.

As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.

vitaut
  • 37,224
  • 19
  • 144
  • 248
  • 2
    I've tried to use it: `target_compile_options(main_static PRIVATE --static)` but it doesn't seem to work, any idea why? – Paweł Szczur Nov 05 '16 at 00:12
  • 2
    `-static` is probably a linker, not compiler option. Try passing it to `target_link_libraries`. – vitaut Nov 05 '16 at 14:25
  • 11
    Oh, `target_link_libraries` I've missed that part of doc: "Specify libraries **or flags** to use when linking a given target.". Thanks. – Paweł Szczur Nov 05 '16 at 14:32
  • 5
    A recent addition: CMake 3.13 introduces [`target_link_options`](https://cmake.org/cmake/help/latest/command/target_link_options.html#command:target_link_options) as a cleaner way to specify linker flags. You should avoid using `target_link_libraries` for linker flags in the future and use `target_link_options` instead. – ComicSansMS Oct 23 '18 at 06:59
  • 2
    There is also [add_compile_options](https://cmake.org/cmake/help/v3.0/command/add_compile_options.html) - see https://stackoverflow.com/questions/39501481/difference-between-add-compile-options-and-setcmake-cxx-flags and more recently [add_link_options](https://cmake.org/cmake/help/v3.13/command/add_link_options.html) – Bruce Adams Dec 07 '18 at 14:50
  • 1
    how do you specify multiple linker options? – m4l490n Mar 27 '19 at 17:22
  • @m4l490n you pass multiple arguments to `target_link_options`. – vitaut Mar 27 '19 at 17:57
  • 1
    @BruceAdams But please, never use them in modern target-based CMake. – val is still with Monica Jun 21 '19 at 15:54
  • @val I agree, but qualified with an almost. There are some valid uses for global project settings where cmake doens't have them yet. So not for enabling C++11 but maybe for enabling certain sanitisers when debugging. – Bruce Adams Jun 21 '19 at 17:06
  • 1
    While this is better than the accepted answer, it is still missing a generator expression to prevent that flag from being added to an incompatible compiler. But since this flag is only meant to be used in a specific compiler, it should be added to a tool chain file in the variable CMAKE_CXX_FLAGS_INIT – Alex Reinking Jun 19 '20 at 07:09
  • @AlexReinking I wrote an answer involving toolchains. I wasn't aware of the `_INIT` variants however. Thanks – John McFarlane Aug 21 '20 at 17:37
52

Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:

set (CMAKE_CXX_FLAGS "-fexceptions")

The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.

Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.

sakra
  • 53,539
  • 13
  • 152
  • 136
  • i tried that but it still gives error. Is set(CMAKE_CXX_FLAGS "-fexceptions") the only way to specify compiler flag. – solti Aug 02 '12 at 19:50
  • 3
    i solved the problem but not in a good way its a poor workaround .. i made -DCMAKE_CXX_FLAGS= "-fexceptions" in the command line. for some reason cmake is not reading flags from the .cmake file. :( .. thank you sakra for your answer .. – solti Aug 02 '12 at 21:59
  • 8
    -DCMAKE_CXX_FLAGS= "-fexceptions" There should NOT be a space between the = and " – evandrix Dec 05 '12 at 08:05
  • 1
    Regarding what you said: "for some reason cmake is not reading flags from the .cmake file." Make sure you clear up the existing cache. This can be done by deleting everything from the build directory before cmake again. – zaizen Jul 15 '16 at 05:32
5

The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:

  • instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
  • details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.

Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.

Steps to add a toolchain:

  1. Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:

    set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
    set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
    

    (You can find an example Linux cross-compiling toolchain file here.)

  2. When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:

    mkdir android-arm-build && cd android-arm-build
    cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
    

    (Note: you cannot use a relative path.)

  3. Build as normal:

    cmake --build .
    

Toolchain files make cross-compilation easier, but they have other uses:

  • Hardened diagnostics for your unit tests.

    set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
    
  • Tricky-to-configure development tools.

    # toolchain file for use with gcov
    set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
    
  • Enhanced safety checks.

    # toolchain file for use with gdb
    set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
    set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
    
John McFarlane
  • 4,081
  • 2
  • 28
  • 33
  • 1
    Don't set `CMAKE__FLAGS` in a toolchain. And there's no such thing as `CMAKE_CXX_DEBUG_FLAGS`. It's `CMAKE_CXX_FLAGS_DEBUG`. And you shouldn't use _that_ either. Only set `CMAKE__FLAGS[_]_INIT` in a toolchain – Alex Reinking Aug 21 '20 at 17:42
  • See docs for [CMAKE__FLAGS__INIT](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_CONFIG_INIT.html) and [CMAKE__FLAGS_INIT](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html) – Alex Reinking Aug 21 '20 at 17:44
  • In general, in CMake, the variables `CMAKE__FLAGS[_]` are meant to be set by the client building your app/library. They should never be programatically set. Appended to, rarely. – Alex Reinking Aug 21 '20 at 17:45
  • 1
    @AlexReinking updated, plus `CMAKE_EXE_LINKER_FLAGS_INIT`. – John McFarlane Aug 21 '20 at 18:09
  • 1
    This was the answer, after much searching thank you @JohnMcFarlane ! – CodeMonkey Nov 03 '20 at 12:59
2

You can also add linker flags to a specific target using the LINK_FLAGS property:

set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")

If you want to propagate this change to other targets, you can create a dummy target to link to.

kaveish
  • 826
  • 8
  • 19
0

This worked for me when I needed a precompile definition named "NO_DEBUG":

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")

Then from code

#ifdef NO_DEBUG
.....
myuce
  • 1,103
  • 1
  • 17
  • 26