I am struggling to find a proper way to propagate correct compiler flags for all targets.
Let's imagine that there is a project which contains a library and unit tests.
ProjectFolder
|-WorkerLibFolder
  |-Worker.cpp
  |-Worker.hpp
  |-CMakeLists.txt  (2)
|-main.cpp
|-CMakeLists.txt (1)
|-TestsFolder
  |-UnitTests.cpp
  |-CMakeLists.txt  (3)
In CMakeLists.txt (1) I'd like to set compile options globally because I assume that optimization level and other flags should be the same for all libraries of the project. 
add_compile_options(-Wall -Werror -Wno-error=maybe-uninitialized) is used to achieve it.
Also I use CMAKE_BUILD_TYPE feature which automatically sets needed optimization level with help of CMAKE_CXX_FLAGS_RELEASE or CMAKE_CXX_FLAGS_DEBUG flags.
Also the fact that afterwards one of these variables is implicitly passed to the compiler seems to be annoying, becaues I anyway have to set these variables in advance for needed optimization flags set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG -DBOOST_DISABLE_ASSERTS") only because -O3 is by defaut set with Release configuration.
Anyway everything is ok up to the moment when I want to alway have -O0 being set when compiling test environment (UniTests.cpp). CMakeLists.txt (3) produces project_ut executable. I want WorkerLib to be compiled with configured optimization level (taked from CMAKE_BUILD_TYPE), but it automatically means that CMAKE_CXX_FLAGS_RELEASE with -Ofast is propagated to UnitTest.cpp
I guess that I might be doing something strange here and there is a better way to deal with an issue.
One option here is to pass optimization flags without help of CMAKE_BUILD_TYPE feature but it seems to be a wrong (as I do not want to maintain lists of flags for every target).
EDIT:
#CMakeLists.txt(1):
cmake_minimum_required(VERSION 3.14.1)
project(TestProject LANGUAGES CXX C)
#####  common comp flags #####
add_compile_options(-Wall -Werror -Wno-error=maybe-uninitialized)
##############################
set(RELEASE_FLAGS "-Ofast -DNDEBUG -DBOOST_DISABLE_ASSERTS")
set(DEBUG_FLAGS "-O0 -ggdb3")
set(CMAKE_CXX_FLAGS_RELEASE ${RELEASE_FLAGS})
set(CMAKE_C_FLAGS_RELEASE ${RELEASE_FLAGS})
set(CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS})
set(CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS})
add_subdirectory(WorkerLibFolder)
add_subdirectory(TestsFolder)
add_executable(mainExec main.cpp)
target_link_libraries(mainExec PRIVATE worker)
#CMakeLists.txt(3):
add_executable(tests UnitTests.cpp)
target_link_libraries(tests PRIVATE worker)
#I want sommehow fix optimization flags for that particular target, while for worker library left them as they were set
#CMakeLists.txt(2):
add_library(worker Worker.cpp)
target_include_directories(worker PUBLIC ${CMAKE_CURRENT_LIST_DIR})
                The proper way to set flags is with set_compile_options and target_compile_options and macros with add_compile_definitions and target_compile_definitions. You should not (or rarely) touch CMAKE_*_FLAGS yourself and with the creation of generator expressions, you rarely should touch CMAKE_*_FLAGS_*, too. Using $<CONFIG:RELEASE> is simpler, because you don't need to care about case (-DCMAKE_BUILD_TYPE=Release and -DCMAKE_BUILD_TYPE=rElEaSe are both release builds) and for my eyes much cleaner to read.
Do in your main CMakeLists.txt:
add_compile_options(
       -Wall -Werror -Wno-error=maybe-uninitialized
       $<$<CONFIG:RELEASE>:-Ofast>
       $<$<CONFIG:DEBUG>:-O0>
       $<$<CONFIG:DEBUG>:-ggdb3>
)
add_compile_definitions(
        $<$<CONFIG:RELEASE>:NDEBUG>
        $<$<CONFIG:RELEASE>:BOOST_DISABLE_ASSERTS>
)
add_subdirectory(WorkerLibFolder)
add_subdirectory(TestsFolder)
add_executable(main ...)
I want to alway have -O0 being set when compiling test environment
So do exactly that. Inside TestsFolder do:
add_compile_options(-O0)
add_library(test_environment  ....)
Or better:
add_library(test_environment ..
target_compile_options(test_environment PRIVATE -O0)
Because compile options are accumulated, the options added in TestsFolder will be suffixed/the last options on the compile line so it will work, I mean ex. gcc -O3 -Ofast -O0 will compile the same as gcc -O0.
target_include_directories(worker PUBLIC ${CMAKE_CURRENT_LIST_DIR})
The CMAKE_CURRENT_LIST_DIR is usually used from include(this_files) files to indicate from where the file is. To include current directory the CMAKE_CURRENT_SOURCE_DIR is more commonly used which, well, indicates the current source directory cmake is processing.
PS: I wouldn't unittest a program/library with different optimize options then the release is build with. I unittest with exactly the same compile options as the release builds. Some bugs show up only with optimizations enabled. The way I preferably unittest a (previous) library is to compile and unittest with both optimization disabled and enabled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With