Different CMAKE_BUILD_TYPE per target

假装没事ソ 提交于 2021-02-18 17:09:53

问题


I am working on a really large project, which I'm in the process of moving from using custom Makefiles to using cmake instead, but I'm still missing a functionality that was implemented with the Makefiles.

The project has many sub-directories, each one of which is compiled into a static library, and then linked into the final executable.

Here is a small example

src/
  lib1/
  lib2/
  lib3/
  main.cpp
  CMakeLists.txt

and in CMakeLists.txt might be something like this:

add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(lib3)
add_executable(test main.cpp)
target_link_libraries(test PUBLIC lib1 lib2 lib3)

I want to debug the final executable, but I don't want to build all static libraries with debug symbols and no optimizations, because then the debugging becomes too slow.

So I want to build lib2 with CMAKE_BUILD_TYPE=Release and lib1 and lib3 with CMAKE_BUILD_TYPE=Debug.

Please bear in mind that instead of three libraries, there are actually ~10, and I want to be able to do that for each one of them, and for a number of them at the same time.

Is there a way to do that from the main CMakeLists.txt?

What I would prefer would be something that would make this possible from the command line:

cmake -DDEBUG_LIBS={lib1,lib3} /path/to/src
cmake --build .

回答1:


Don't set CMAKE_BUILD_TYPE keep it blank or make a custom one where you set exactly what you want the base flags to be. Then add the additional debug and optimizations for the libraries that you want. I would suggest creating a function (or macro) that each library target calls that checks to see if it shows up in DEBUG_LIBS and then call target_compile_options with the correct values. But you should set is as -DDEBUG_LIBS=lib1;lib3 so that list handling works.

function(check_debug libname)
  if(${libname} IN_LIST DEBUG_LIBS)
    target_compile_options(${libname} PRIVATE -g -O0)
  endif()
end_function()



回答2:


You can use ExternalProject instead of add_subdirectory for your dependencies, tell it to install into a subdirectory of ${CMAKE_CURRENT_BINARY_DIR}, then use find_package to find it there. This lets you use any combination of build options that you desire.

This does require a two-stage process when you first build it: run cmake, then make to build the dependencies, then cmake again to detect the dependencies, then make again to build your own targets. There are ways around that if you want, too.

For example, here's how I'm building OpenCV as part of my project (simplified):

# Build OpenCV from source.
include(ExternalProject)
ExternalProject_Add(opencv
    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/opencv
    CMAKE_ARGS
        -DBUILD_LIST=core,imgproc
        -DBUILD_SHARED_LIBS=OFF
        -DCMAKE_BUILD_TYPE=Release
        -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/deps/opencv
)

# Find it in the directory where we just built it.
find_package(OpenCV
    PATHS ${CMAKE_CURRENT_BINARY_DIR}/deps/opencv
    NO_DEFAULT_PATH
)

# Abort if we weren't able to find it.
if(NOT OpenCV_FOUND)
    message(STATUS "OpenCV was not found. This means it still needs to be built from source. To build it, run:")
    message(STATUS "")
    message(STATUS "    cmake --build ${CMAKE_CURRENT_BINARY_DIR} --target all")
    message(STATUS "")
    message(STATUS "Then re-run cmake to detect the built library.")
    return()
endif()

# Consume it in the usual way.
add_binary(my_binary ...)
target_link_libraries(my_binary ${OpenCV_LIBS})

No idea if this is "best practice" or not, but it works for me.




回答3:


Debug symbols do not usually affect speed. You can probably keep it for all targets. If the symbols are a problem, they can be stripped from the executable/library afterwards. This approach has the benefit that you can still debug the library that you didn't expect the need to debug (although if it is optimised, it may not necessarily be ideal experience).

You could enable or disable optimisation for single target with target_compile_options so that it is always or never optimised.


Specifying a different CMAKE_BUILD_TYPE can be problematic because it can affect macros which can affect the ABI of the program if you do things like add members based on NDEBUG macro. If you mix build types, then you must make sure that debug macros are not used in headers.

Simplest way to achieve that is to build the libs in separate projects and import the built libs into the final program that depends on the libraries.



来源:https://stackoverflow.com/questions/60636141/different-cmake-build-type-per-target

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!