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.
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
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:
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}) 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}") 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.
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.
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
.
target_link_libraries
I've missed that part of doc: "Specify libraries or flags to use when linking a given target.". Thanks.
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.
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.
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:
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.) 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.) 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")
CMAKE_<LANG>_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_<LANG>_FLAGS[_<CONFIG>]_INIT
in a toolchain
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.
CMAKE_EXE_LINKER_FLAGS_INIT
.
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.
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
.....
With CMake 3.4+, APPEND
can be used with the string
command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")
Success story sharing
string(APPEND CMAKE_EXE_LINKER_FLAGS "new_value")
is shorter and cleaner thanset(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} new_value")