Search code examples
c++cmake

How to add compile options to an external library in C++?


Overview

Context

  • I'm using Clion, and I try to use the C++ google's benchmark library in my project.

My problem

  • My project has a build type Debug, when I compile it, the benchmark library is also compiled as Debug. BUT I need the library to be build as Release for it to work properly.

The (not good enough) solution

  • I have to add '-DCMAKE_BUILD_TYPE=Release' to Clion's Cmake options, however it's now the whole project witch is in Release

How do I impose to one library to compile with different options ?

My code (cmake)

#My target (I wnat it to run in debug)
add_executable(benchmark_test
        thread/benchmark_test.cpp
        thread/benchmark_test.h)

# prevent lib to run tests
set(BENCHMARK_ENABLE_TESTING NO)

# Importing the lib (source code at the root of the project)
# I want it to run in release
add_subdirectory(benchmark)

# Linking the target and the lib
target_link_libraries(benchmark_test benchmark)

What didn't work so far


# I would have thought this one to put everything in release but no (maybe because of Clion)
add_compile_options(-DCMAKE_BUILD_TYPE=Release)

#===================================================================

# This was my most advanced try so far 
set(GCC_COMPILE_OPTIONS "-DCMAKE_BUILD_TYPE=Release")
target_compile_options(benchmark_main PUBLIC "$<$<CONFIG:Debug>:${GCC_COMPILE_DEBUG_OPTIONS}>")
target_compile_options(benchmark PUBLIC "$<$<CONFIG:Debug>:${GCC_COMPILE_DEBUG_OPTIONS}>")


I'm kinda new here, just tell me if there is any lack of information ^^


Solution

  • How to do this (general case)

    There are effectively two ways to do this:

    1. Option 1: Install and compile the 3rd party library separately, in release mode. Then, find it via find_package. From there you can link against it as normal.
    2. Option 2: Alternatively, use add_compile_options to add the -O3 build flag to google benchmark. You will need to add it in an intermediary directory (eg, one holding all 3rd party depedencies). Do this to ensure that this compile flag applies uniformly to all cmake targets added in that directory, and it's subdirectories.

    Note that if you're using MSVC rather than GCC or Clang, you will need to use the /Ox compile option, rather than -O3.

    YourProject
    ├── CMakeLists.txt          # CMakeLists for your project
    └── 3rd
        ├── CMakeLists.txt      # Intermediary CMakeLists (add -O3 here)
        └── benchmark           # Google Benchmark Repo
            └── CMakeLists.txt
            └── ... (other google benchmark files   
    

    Should you do this?

    Not for Google Benchmark. There's no reason for you to do this. Benchmarks should be run in release mode; they're basically meaningless in debug mode.

    Compiling Google Benchmark in release mode won't even make the benchmarks run faster, because the code being benchmarked is still compiled in debug mode.

    Instead, when you want to run benchmarks, just build the whole project in Release Mode.

    When should you do this?

    This is primarily useful if you're using a third party library to do some of the heavy lifting, and the third party library either rarely needs to be debugged, or needs to run quickly for the application to be usable or testable.

    For example, if you're using a 3rd party library to encode or decode video, and you're not planning on debugging it, it probably makes sense to always compile it in release mode. Most of the time when you're linking against a system library, or against a library found via find_package, it will also be compiled in release mode.

    It's only in this particular case (with Google Benchmark) that it doesn't make sense to build it in release mode, when the rest of the application is built in debug mode.