Suppress link warnings with CMake - c++

I am aware of how to suppress compile warnings with CMake by doing (suppose I want to disable compile warning C4819):
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4819")
So how to suppress link warnings with CMake (say LNK4099)?

Try this:
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/ignore:4099")
It worked perfectly for me with Visual Studio 2015.

Another way to ignore linker warnings for all the targets in the current scope in CMake is by settings CMAKE_EXE_LINKER_FLAGS, CMAKE_SHARED_LINKER_FLAGS, CMAKE_STATIC_LINKER_FLAGS as it follows:
# Ignore warnings about missing pdb
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /ignore:4099")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4099")
It also exists a CMAKE_MODULE_LINKER_FLAGS, but it seems not related to C++ projects.

In case your library depends on some another library that doesn't have PDBs, you may want to add ignore flag only once instead of adding it to each executable. Consider the following:
add_library(my_lib my_lib.cpp)
find_library(EXT_LIBRARY no_pdb.lib REQUIRED)
target_link_libraries(my_lib PUBLIC ${EXT_LIBRARY})
add_executable(my_exe1 "src/exe1.cpp")
target_link_libraries(my_exe1 PUBLIC my_lib)
add_executable(my_exe2 "src/exe2.cpp")
target_link_libraries(my_exe2 PUBLIC my_lib)
So now both my_exe1 and my_exe2 cause LNK4099 error. To fix this, instead of doing this on the executable level like this:
set_target_properties(my_exe1 PROPERTIES LINK_FLAGS "/ignore:4099")
set_target_properties(my_exe2 PROPERTIES LINK_FLAGS "/ignore:4099")
You may want to add ignore flag to your library's interface only once:
target_link_options(my_lib INTERFACE "/ignore:4099")

Related

CMake: propagate compile options project-wide

Lets say I want to compile all the code with /W4 for a project with three libs/targets.
A -> B -> C
What is the best practice to apply the flag project-wide?
I can think of two approaches:
Set TARGET_COMPILE_OPTIONS(C PUBLIC "\W4") in C's CMake (which is a core library for the whole project) and every other library that depends on C will inherit the flag via: TARGET_LINK_LIBRARIES(B C)
Pro: new libraries will inherit the flag automatically.
Con: compile flags for a project are implicit.
Specify compile options for every target/lib separately.
Pro: the flags are explicitly specified and manageable separately for each lib.
Con: the flags need to be (not forgotten to be) set for a new lib.
Third option, change the compiler flags.
For instance, when I want to activate address sanitizer on the whole project, I do:
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address -static-libasan")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address -static-libasan")
The current idiomatic way of setting flags for the current folder and subfolder is to use
add_compile_options(-fsanitize=address)

How to resolve undefined reference when they are not used with GCC & CMAKE

I am trying to port some MSVC projects to Linux with help of CMAKE.
In one of the Library project there are some functions which are just declared and not being defined anywhere or used anywhere.
for ex:
int fun_a();
int fun_unsed() /*This function is never used in project*/
{
fun_a();
}
Now when I try to do make in Linux, I am observing undefined reference to the declared functions. But same code works on MSVC with same CMAKE files.
I tried to use below flags in my CMAKE files(from here), but it doesn't seems to help.
SET(GCC_COVERAGE_COMPILE_FLAGS "-unresolved-symbols=ignore-all")
SET(GCC_COVERAGE_LINK_FLAGS "-unresolved-symbols=ignore-all")
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}" )
am I missing something?
Below is cmake file for executable
#Add Library Projects to the test application
add_subdirectory ("${PROJECT_BINARY_DIR}/../../src/build/vc/" "${PROJECT_BINARY_DIR}/../../src/build/vc/")
#set additional search paths for libraries
#set(CMAKE_LIBRARY_PATH ${PROJECT_BINARY_DIR}/../../lib/Debug)
link_directories(${PROJECT_BINARY_DIR}/../../lib ${OPENCV_BUILD}/lib)
#set ignore undefined & unused functions errors. It seems GCC by defalt looks for them.
SET(GCC_COVERAGE_LINK_FLAGS "-unresolved-symbols=ignore-all")
SET(GCC_COVERAGE_COMPILE_FLAGS "-ffunction-sections")
SET(GCC_COVERAGE_LINK_FLAGS "-Wl,-gc-sections -flto")
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}" )
#Get the exicutable for source files
add_executable (FaceAnalysis ${sources})
target_link_libraries (FaceAnalysis faceDetect.a libopencv_core.so libopencv_imgproc.so libopencv_imgcodecs.so libopencv_videoio.so libopencv_objdetect.so libopencv_highgui.so libopencv_video.so libopencv_ml.so SDL2)
add_dependencies(FaceAnalysis faceDetect)
If they were indeed unreferenced, you wouldn't get an "undefined reference" error.
The linker error should tell you where the symbol is used.
Edit: revised question
This can be worked around by asking the compiler to put each function into a separate section, so they are kept apart inside the object files until the final link, and then instructing the linker to discard sections that are unreferenced.
Add -ffunction-sections to CFLAGS and/or CXXFLAGS as appropriate, and -Wl,--gc-sections to LDFLAGS.
The link-time optimizer (-flto) can also do this, but AFAIK requires optimization to be enabled, so it would fail in Debug builds.
If you have no implementation for the function in your project, then it must be implemented in another library. In your visual studio project, right-click on the project, select "Properties", then under "Linker" take a look at the linked libraries and link directories. You'll see at least one library defined there. Then in CMAKE you just need to target_link_libraries to the same lib.
The flags which remove death code are, as Simon said in his answer:
-ffunction-sections and -Wl,--gc-sections1
But, GCC does not support them in some targets, like Windows and Linux on X86 and 64, with ELF file format.
My solution was to reduce the visibility of all functions, by also using the following flags:
-fvisibility=hidden and -fvisibility-inlines-hidden 2
All the flags together, removed the link time error.
1 -ffunction-sections puts each function in a different section
-Wl,--gc-sections should remove all the sections that are unused.
2 This flags change the visibility of all functions from default (public) to hidden. So the linker now know that the functions are not needed anymore if they are not used inside the executable or library, so it is free to remove them.

What's the proper way to enable AddressSanitizer in CMake that works in Xcode

I've added AddressSanitizer flag as follow:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
Everything builds and runs fine when using Unix Makefiles.
The problem comes when generating the Xcode project, it just doesn't want to link because it cannot find the ASan library.
I already found two solutions, but decided not to use them because they cannot be automated using just CMake:
Adding -Wl,-undefined,dynamic_lookup to the linked flags, so it skips linking to dynamic libraries.
Link with libclang_rt.asan_osx_dynamic.dylib directly.
So what's the problem with these two solutions?
When using solution #1, I have to manually open the target scheme in Xcode and add DYLD_INSERT_LIBRARIES environment variable pointing to libclang_rt.asan_osx_dynamic.dylib.
When using solution #2, the path for the ASan library varies between computers.
Additionally as another solution, I tried enabling Address Sanitizer flag from the Xcode target scheme but interestingly it didn't detect the issues I added, so I didn't list this as a solution because it failed my test.
Any help will be much appreciated.
Since the top-voted answer is the wrong way to do it these days and I did not get the proper cmake solution for this reading this thread, I thought I would mention the correct way at the time of writing this so that the next reader does not need to spend much time with this.
The idea of this solution is to pass -fsanitize=address to the compiler and linker flags.
If you would like to enable this for all your targets at the same time, you can use add_compile_options and add_link_options. This makes sense if you have multiple, potentially a large of, targets.
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
Alternatively, you can also use target_compile_options and target_link_options to set these for a particular target. This might make more sense if you do not want this to apply to all the targets.
target_compile_options(asan-target PRIVATE -fsanitize=address)
target_link_options(asan-target PRIVATE -fsanitize=address)
You need to provide the flag(s) to the linker too. I'm doing it like this:
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
I propose create your own Asan profile.
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig)
if(NOT "Asan" IN_LIST CMAKE_CONFIGURATION_TYPES)
list(APPEND CMAKE_CONFIGURATION_TYPES Asan)
endif()
else()
set(allowedBuildTypes Asan Debug Release RelWithDebInfo MinSizeRel)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${allowedBuildTypes}")
if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE IN_LIST allowedBuildTypes)
message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}")
endif()
endif()
set(CMAKE_C_FLAGS_ASAN
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
"Flags used by the C compiler for Asan build type or configuration." FORCE)
set(CMAKE_CXX_FLAGS_ASAN
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
"Flags used by the C++ compiler for Asan build type or configuration." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_ASAN
"${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
"Linker flags to be used to create executables for Asan build type." FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_ASAN
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
"Linker lags to be used to create shared libraries for Asan build type." FORCE)
Notes:
AddressSanitizer (ASan) for Windows with MSVC is under experimental stage thus I didn't provided the MSVC way here.
CMAKE_BUILD_TYPE isn't used by multi-configuration generators (Xcode, Visual Studio, etc), thus I provided an example to check this first.
The default value for CMAKE_BUILD_TYPE is an empty string. And user can set CMAKE_BUILD_TYPE to any value at the cmake command line. Therefore, we check both cases, and make sure that we are dealing with a known build type (if provided).
There is also CMAKE_MODULE_LINKER_FLAGS you may want to configure.
Usage:
$ cmake \
-DCMAKE_BUILD_TYPE=Asan \
...
...
cmake 3.13
introduce configuration for xcode schema
in CMake
cmake_minimum_required(VERSION 3.13)
set(CMAKE_XCODE_GENERATE_SCHEME ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN ON)
When Build
xcodebuild -enableAddressSanitizer YES
First ensure with debug info, such as setting CMAKE_BUILD_TYPE to Debug passing -g flag for GCC/Clang.
Then, if your target is an executable or an shared library, then you may set those cmake variables:
CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS_DEBUG
CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS_DEBUG
i.e. When your target is an executable:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
When your target is an shared library:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
However, when your executable relies on an static library and you'd like to use asan to check your static library, then you have to set like this:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
The simplest solution that I currently found is
cmake -DCMAKE_BUILD_TYPE=ASAN .
I prefer this option since it expresses the intent (run sanitizers) rather than modifies a number of flags.
I do not know when this option was added. I also cannot find any documentation to it.
I found that the other answers didn't work, you need to set the init variables in your toolchain file:
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address -fno-omit-frame-pointer")

How to change a compiler flag for just one executable in CMake?

I have a CMake project that supports multiple processor compilation in Visual Studio through the \MP flag.
Since in just one of the many executable that the project builds, I need to set the \MP flag to false (or disable it because I get errors importing a .tlb file), how can I set the flags for this target different?
add_executable(MyProgram myprogram.cpp)
target_link_libraries(MyProgram MyLibraries)
Should I give some set_target_properties to cmake or specifically remove the flag from the whole project?
Thank you!
You can use set_source_files_properties to add COMPILE_FLAGS for myprogram.cpp. For example:
add_executable(MyProgram myprogram.cpp)
# Add the -std=c++11 flag as an example
set_source_files_properties( myprogram.cpp PROPERTIES COMPILE_FLAGS "-std=c++11" )
target_link_libraries(MyProgram MyLibraries)
If you need those flags for all source files in the MyProgram target, you could use set_target_properties with the target property COMPILE_FLAGS:
add_executable(MyProgram myprogram.cpp)
# Add the -std=c++11 flag as an example
target_link_libraries(MyProgram MyLibraries)
set_target_properties( MyProgram PROPERTIES COMPILE_FLAGS "-std=c++11" )
Update: To remove a single property, you can first get all the properties and manually remove the offending flag from the list. For example with get_source_file_property:
get_source_file_property( MYPROPS myprogram.cpp COMPILE_FLAGS )
STRING( REPLACE "/MP1" "" MYPROPS ${MYPROPS} )
set_source_files_properties( myprogram.cpp COMPILE_FLAGS ${MYPROPS} )
However, I would recommend splitting your source files in two. One with all the source files with the \MP flag and another with only myprogram.cpp
New approach
# Simply add the opposite flag to the target
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${TARGET_NAME} PRIVATE "/GR")
else()
target_compile_options(${TARGET_NAME} PRIVATE "-frtti") # works even if -fno-rtti is set to CXX_FLAGS
endif()
Old approach:
You can disable it by removing the flag from the default compiler flags first, than set it to your target. In my case I wanted to remove enable RTTI because it was disabled by default:
function(enable_RTTI target_name)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(NO_RTTI "/GR-")
set(WITH_RTTI "/GR")
else()
set(NO_RTTI "-fno-rtti")
endif()
string(REPLACE "${NO_RTTI}" "${WITH_RTTI}" COMPILE_FLAGS_RTTI_ENABLED "${CMAKE_CXX_FLAGS}")
set_target_properties(${target_name} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS_RTTI_ENABLED}")
endfunction()
...
# Do this on your specific target
enable_RTTI(${TARGET_NAME}
This works like a charm with CMake 3!

Does set_target_properties in CMake override CMAKE_CXX_FLAGS?

At the beginning of my CMake project, I'm setting general compilation flags in the variable CMAKE_CXX_FLAGS, like
set(CMAKE_CXX_FLAGS "-W -Wall ${CMAKE_CXX_FLAGS}")
Later on, I need to append additional configuration-specific compilation flags (stored in BUILD_FLAGS). Can I use the following command for this:
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})
or do I have to add the CMAKE_CXX_FLAGS manually:
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BUILD_FLAGS}")
to prevent CMAKE_CXX_FLAGS being overriden by BUILD_FLAGS?
The accepted answer is still working but outdated since 2013.
This answer is based and new functions from CMake v2.8.12, v3.3 and v3.13.
Since CMake-2.8.12 (2013)
Two new commands to set CMAKE_CXX_FLAGS:
target_compile_options() (for one single target)
add_compile_options() (for all targets)
The documentation of last version has not changed a lot since cmake-2.8.12:
target_compile_options()
add_compile_options()
In you case you can use:
target_compile_options(${TARGET} PRIVATE ${BUILD_FLAGS})
Or simply if you have a single target:
add_compile_options(${BUILD_FLAGS})
More examples
target_compile_options(mylib PRIVATE -O2) # only internal
target_compile_options(mylib INTERFACE -gl) # only external
target_compile_options(mylib PUBLIC -g) # same as PRIVATE + INTERFACE
# multiple targets and flags
target_compile_options(mylib1 mylib2 PRIVATE -Wall -Wextra)
target_compile_options( mylib PUBLIC -DUSEXX) # Bad
target_compile_definitions(mylib PUBLIC -DUSEXX) # OK
add_compile_options(-Wall -Wextra) # for all targets in current directory
add_compile_options(-DUSEXX) # Bad
add_definitions(-DUSEXX) # OK
Deprecated COMPILE_FLAGS
cmake-3.0 documentation flags COMPILE_FLAGS as deprecated:
COMPILE_FLAGS
Additional flags to use when compiling this target’s sources.
The COMPILE_FLAGS property sets additional compiler flags used to
build sources within the target. Use COMPILE_DEFINITIONS to pass
additional preprocessor definitions.
This property is deprecated. Use the COMPILE_OPTIONS property or the
target_compile_options command instead.
If you still want to use set_target_properties() you may use COMPILE_OPTIONS instead of COMPILE_FLAGS:
set_target_properties(${TARGET} PROPERTIES COMPILE_OPTIONS ${BUILD_FLAGS})
Since CMake-3.3 (2015)
Anton Petrov suggests to use generator expressions as presented in an answer of ar31.
The CMake generator expressions applies your ${BUILD_FLAGS} to:
C++ language using $<COMPILE_LANGUAGE:CXX> (can also be C, CUDA...)
Clang compiler using $<CXX_COMPILER_ID:Clang>
(can also be GNU for gcc, or MSVCfor Visual C++... see full list)
(use $<C_COMPILER_ID:Clang> instead if language is C)
and more as supported C++ feature or compiler version... (see documentation)
In you case you can use:
target_compile_options(${TARGET} PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${BUILD_FLAGS_FOR_CXX}>
$<$<COMPILE_LANGUAGE:C>:${BUILD_FLAGS_FOR_C}>)
or about compilers:
target_compile_options(${TARGET} PRIVATE
$<$<CXX_COMPILER_ID:Clang>:${BUILD_FLAGS_FOR_CLANG}>
$<$<CXX_COMPILER_ID:GNU>:${BUILD_FLAGS_FOR_GCC}>
$<$<CXX_COMPILER_ID:MSVC>:${BUILD_FLAGS_FOR_VISUAL}>)
Since CMake-3.13 (2018)
A new function target_link_options() allow to pass options to the linker, as mentioned by Craig Scott.
Different options for C and C++ files
The best way is to distinguish C files and C++ files using two different targets.
Use the first one:
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})
The flags stored in BUILD_FLAGS are appended after CMAKE_CXX_FLAGS when compiling the sources of TARGET. The documentation hints at this, but I've just tried it to make sure.
COMPILE_FLAGS
Additional flags to use when compiling this target's sources.
The COMPILE_FLAGS property sets additional compiler flags used to
build sources within the target. Use COMPILE_DEFINITIONS to
pass additional preprocessor definitions.
The full command line will be the equivalent of:
${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS} -o foo.o -c foo.cc
And as Ramon said, you can always check with make VERBOSE=1.