315

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.

4

8 Answers 8

308

Please be aware that due to the evolution of CMake since the writing of this answer in 2012, the majority of the recommendations provided here are now obsolete or no longer recommended, with improved alternatives available.


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 compiler 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.

Sign up to request clarification or add additional context in comments.

5 Comments

why is add_definitions() unclean?
@leinaD_natipaC: The official documentation says: This command can be used to add any flags, but it is intended to add preprocessor definitions. I think that's why.
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
string(APPEND CMAKE_EXE_LINKER_FLAGS "new_value") is shorter and cleaner than set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} new_value")
outdated advice
261

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 clearer.

12 Comments

I've tried to use it: target_compile_options(main_static PRIVATE --static) but it doesn't seem to work, any idea why?
-static is probably a linker, not compiler option. Try passing it to target_link_libraries.
Oh, target_link_libraries I've missed that part of doc: "Specify libraries or flags to use when linking a given target.". Thanks.
A recent addition: CMake 3.13 introduces 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.
|
62

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.

4 Comments

i tried that but it still gives error. Is set(CMAKE_CXX_FLAGS "-fexceptions") the only way to specify compiler flag.
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 ..
-DCMAKE_CXX_FLAGS= "-fexceptions" There should NOT be a space between the = and "
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.
10

Edit: My general advice is to avoid adding compiler flags explicitly via CMake altogether. Toolchain files are for configuring novel toolchains, not customising an existing GCC toolchain. A project's CMake is more clean, portable, and future-proof when it is toolchain-agnostic. Separate the concern of describing how your artefacts are constituted (using CMake) from the concern of customising compiler flags. I find environment variables, such as CXXFLAGS are much better at maintaining this separation of concerns. However, in answer to the OP...

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

5 Comments

In general, in CMake, the variables CMAKE_<LANG>_FLAGS[_<CONFIG>] are meant to be set by the client building your app/library. They should never be programatically set. Appended to, rarely.
@AlexReinking updated, plus CMAKE_EXE_LINKER_FLAGS_INIT.
This was the answer, after much searching thank you @JohnMcFarlane !
@AlexReinking passing -DCMAKE_<LANG>_FLAGS to cmake appears to override CMAKE_<LANG>_FLAGS_INIT. For this reason, I'm tempted to use a custom flag and set it explicitly in CMakeLists.txt.
5

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.

Comments

4

Since CMake 3.13 there is the add_link_options command.

It applies to all subsequent add_library and add_executable commands in the same scope and sub-scopes.

This can be useful for project-wide settings. For example:

add_link_options("-fexceptions") add_executable(first-test first.cpp) 

With that said, modern CMake best practices often favor per-target settings via target_link_options:

add_executable(first-test first.cpp) target_link_options(first-test PUBLIC "-fexceptions") 

PUBLIC|PRIVATE|INTERFACE as usual determines how the option is propagated to downstream dependencies.

There's also a BEFORE flag for cases when the option needs to be prepended instead of appended.

1 Comment

I thought this was discouraged in favor of target specific options
2

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 ..... 

2 Comments

That's what add_definitions is for.
Prefer using add_compile_options("-std=c++14") and add_compile_definitions("NO_DEBUG")
-1

With CMake 3.4+, APPEND can be used with the string command to add flags.

string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions") 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.