问题
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