How to use DEBUG macro with cmake? - c++

I'm new to cmake, so up front, my apologies this question is too basic ..
Question is,
I have logs under #ifdef DEBUG which I want to print only for debug build.
Something like this ..
void func () {
// some code here
#ifdef DEBUG
print_log(...) // this portion should execute only for debug builds
#endif
// some code here
}
How can I achieve this with cmake ?
I have already looked at #ifdef DEBUG with CMake independent from platform and cmakelists debug flag not executing code within "ifdef DEBUG", suggestions here don't seem to work for me.
(project is on Linux platform)

Modern CMake uses a target-based approach which allows you to specify settings that are restricted to a target as opposed to being global (and affecting all targets). This then gives you the control to specify how the state from targets propagates transitively to dependent targets so as to reduce the visible scope of the state (include paths, library dependencies, compiler defines, compiler flags, etc) to dependent targets. The approach you decide to go with will depend largely on how complex your application is, for instance, how many targets (executable & libraries) exist in the system. The more complex the system the more benefits you in terms of reduced complexity and compile time that you will get from using the target-based approach. In the simplest case to set this up with the modern target based CMake approach you could use the following (where exe is the name of your executable:
add_executable(exe "")
target_sources(exe
PRIVATE
main.cpp
)
target_compile_definitions(exe
PRIVATE
# If the debug configuration pass the DEBUG define to the compiler
$<$<CONFIG:Debug>:-DDEBUG>>
)

Added set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") to CMakeLists.txt
Created Debug/ directory & cd Debug
cmake -DCMAKE_BUILD_TYPE="Debug" ../
Worked !

Related

How to set executable to Win32 in release mode

I've read on CMake's documentation that when calling add_executable, you can set the executable type to be Win32 by doing add_executable(target WIN32 source.cpp). I also know that you should use CMake generator expressions to check for build configurations like so:
target_compile_definitions(target PUBLIC
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:Release>:RELEASE>
)
However this won't work with add_executable. It treats it as a source file when I do add_executable(target $<$<CONFIG:Release>:WIN32> source.cpp) and so it fails. What is the correct way of doing setting the executable type to WIN32 only in release mode?
I am not really sure it makes sense given a WIN32 executable and a non-WIN32 executable do not have the same entry point, so the code would need to change as well.
Still, here is how you would do it on CMake side:
add_executable(target source.cpp)
set_target_properties(target PROPERTIES WIN32_EXECUTABLE $<CONFIG:Release>)
Key point is the WIN32 flag in add_executable is just a shortcut to set the WIN32_EXECUTABLE property.
Note: I cannot test this sample atm so it depends on me having read those links properly ;)

CMake Interface dependency with custom build type

So, I've found really strange behaviour in CMake creating dependency on target_link_library..
It's hard to explain in one sentence, so here is a list of requirements (I hope this all will make sence in the end)
your project must have custom build type defined through CMAKE_CONFIGURATION_TYPES ('Tools' in this example)
you must have at least 3 targets:
executable (or simply main target) (test-exe in this example)
interface library which link to main target (this could be something other than INTERFACE library, but the next target must be linked to it via interface property only) (test-env in this example)
static library which links to the interface library with specific generator expression, which is depends on custom build type (something like that 'target_link_libraries(test-env INTERFACE $<$CONFIG:Tools:test-lib>)') (test-lib in this example)
Here is the code of the CMakeLists.txt file to make it little bit clearer:
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(multiconfiguration-test LANGUAGES CXX)
set(CMAKE_CONFIGURATION_TYPES Debug Release Tools)
set(CMAKE_CXX_FLAGS_TOOLS ${CMAKE_CXX_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS_TOOLS ${CMAKE_EXE_LINKER_FLAGS_DEBUG})
set(CMAKE_STATIC_LINKER_FLAGS_TOOLS ${CMAKE_STATIC_LINKER_FLAGS_DEBUG})
add_library(test-env INTERFACE)
# EXCLUDE_FROM_ALL used to not build this target by default
add_library(test-lib STATIC EXCLUDE_FROM_ALL "test-lib.cpp")
target_link_libraries(test-env INTERFACE $<$<CONFIG:Tools>:test-lib>)
add_executable(test-exe "test-exe.cpp")
target_link_libraries(test-exe PRIVATE test-env)
(Files test-exe.cpp and test-lib.cpp are trivial, test-lib.cpp has a simple function, and test-exe.cpp declares this function and then calls it from main.)
When you would try to build this project with visual studio 2019/2017 generators (with "Tools" as configuration type of course: cmake --build . --config Tools), you will have next error:
LINK : fatal error LNK1104: cannot open file 'Tools\test-lib.lib' [<none_important_path_to_the_project>\test-exe.vcxproj]
And, what is important, you will not see in the terminal target test-lib being build.
So, what happened is target test-exe knows it must be linked against test-lib, but the build system doesn't know that target test-exe is dependent on target test-lib.
And now the most strange thing! If we will link this library like that: target_link_libraries(test-env INTERFACE $<$<CONFIG:Debug>:test-lib>) (so build type must be Debug), and still build project with Tools as a build type, you will see in the terminal that target test-lib is now building! (yes we have link error because test-exe can't find the function which is defined in test-lib, but this is at least expected)
So, what actually happens, the link flag of the target test-exe is correctly depends on the generator expression BUT, the actual build dependency, somehow, transforms any custom build type in this generator expression to the Debug.
Again this only happens with requirements I pointed up above, so it's not only the fault of generator expression, it's also connected to the interface dependency as well..
If we can't break any of the requirements, one possible solution will be to add direct dependency of test-lib target to test-env (like that: add_dependecies(test-env test-lib)), but this is not perfect, because even if we will use test-lib only then where is Tools as build type, we still will build this library each time, which can be undesired behavior.
I'm not really asking for solution here (but if you have one please share), I'm asking for the explanation why this even happening? Is this a bug or a really strange feature?
EDIT Small update I've found just now:
It must not even be the custom build type. The same bug can be encountered even with Release build type, so the final code can look as simple as this:
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(multiconfiguration-test LANGUAGES CXX)
add_library(test-env INTERFACE)
add_library(test-lib STATIC EXCLUDE_FROM_ALL "test-lib.cpp")
target_link_libraries(test-env INTERFACE $<$<CONFIG:Release>:test-lib>)
add_executable(test-exe "test-exe.cpp")
target_link_libraries(test-exe PRIVATE test-env)
and be build with next command: cmake --build . --config Release
Looks like a bug with the Visual Studio generator to me. I've just tested the Ninja Multi-Config generator both on Linux and on Windows and there cmake --build <build-dir> --config Release works just fine.

CMake: compilation speed when including external makefile

I have a c++ cmake project. In this project I build (among other) one example, where I need to use another project, call it Foo. This Foo project does not offer a cmake build system. Instead, it has a pre-made Makefile.custom.in. In order to build an executable that uses Foo's features, one needs to copy this makefile in his project, and modify it (typically setting the SOURCES variable and a few compiler flags). Basically, this Makefile ends up having the sources for your executable and also all the source files for the Foo project. You will not end up using Foo as a library.
Now, this is a design I don't like, but for the sake of the question, let's say we stick with it.
To create my example inside my cmake build I added a custom target:
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/Makefile.custom.in Makefile.custom)
ADD_CUSTOM_TARGET(my_target COMMAND $(MAKE) -f Makefile.custom
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
This works. I can specify some variables to cmake, which get resolved in the call to CONFIGURE_FILE, and I end up with a working Makefile.custom. Then, invoking make my_target from the build directory, I can build the executable. I can even add it to the all target (to save me the effort of typing make my_target) with
SET_TARGET_PROPERTIES(my_target PROPERTIES EXCLUDE_FROM_ALL FALSE)
Sweet. However, cmake appears to assign a single job to the custom target, slowing down my compilation time (the Foo source folder contains a couple dozens cpp files). On top of that, the make clean target does not forward to the custom makefile. I end up having to add another target:
ADD_CUSTOM_TARGET(really-clean COMMAND "$(MAKE)" clean
COMMAND "$(MAKE)" -f Makefile.custom clean
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
which, unlike my_target with all, I can't include in the clean target (can I?).
Now, I know that a cleaner solution would be to have the Foo project be built as an external project, and then link to it. However, I've been 'recommended' to use their Makefile.custom.in makefile, modifying the few lines I need (adding my sources, specifying compiler flags, and few other minor modifications). So, regardless of how neat and clean this design pattern is, my questions are:
is there a way to tell cmake that make should use more than 1 job when making the target my_target?
is there a cleaner way to include a pre-existing makefile in a cmake project? Note that I don't want (can't?) use Foo as a library (and link against it). I want (need?) to compile it together with my executable using a makefile not generated by cmake (well, cmake can help a bit, through CONFIGURE_FILE, by resolving some variables, but that's it).
Note: I am aware of ExternalProject (as suggested also in this answer), but I think it's not exactly what I need here (since it would build Foo and then use it as a library). Also, both my project and Foo are written exclusively in C++ (not sure this matter at all).
I hope the question makes sense (regardless of how ugly/annoying/unsatisfactory the resulting design would be).
Edit: I am using cmake version 3.5.2
First, since you define your own target, you can assign more cores to the build process for the target my_target, directly inside your CMakeLists.txt.
You can include the Cmake module ProcessCount to determine the number of cores in your machine and then use this for a parallel build.
include(ProcessorCount)
ProcessorCount(N)
if(NOT N EQUAL 0)
# given that cores != 0 you could modify
# math(EXPR N "${N}+1") # modify (increment/decrement) N at your will, in this case, just incrementing N by one
set(JOBS_IN_PARALLEL -j${N})
endif(NOT N EQUAL 0)
and when you define your custom target have something like the following:
ADD_CUSTOM_TARGET(my_target
COMMAND ${CMAKE_MAKE_PROGRAM} ${JOBS_IN_PARALLEL} -f Makefile.custom
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
by the way, I don't think there's the need for you to include also CMAKE_BUILD_TOOL among the COMMANDs in your target.
I believe that instead of modifying the lines as above, you could call
make -j8 my_target
and it might start 8 jobs (just an example) without modifying the CMakeLists.txt, but I cannot guarantee this works having defined the COMMAND the way you have, just try if that's enough.
For the second point, I cannot think right now of a "cleaner" way.

Clion: How to define debug level?

I have the following debug statements in my code:
#if (DEBUG_LEVEL > 0)
printf("ITER %d\n", iter);
#endif
How can I define debug level in Clion debugger? And do I need to use CMAKE?
Add the following to your CMakeLists.txt:
if (DEBUG_LEVEL)
add_definitions(-DDEBUG_LEVEL=${DEBUG_LEVEL})
endif()
It basically says: "If you have "DEBUG_LEVEL" CMake variable defined, pass the DEBUG_LEVEL=X preprocessor definition to the compiler"
Pass the desired value of the variable (e.g. -DDEBUG_LEVEL=1) to CMake (in CLion it can be done via Options | Build, Execution, Deployment | CMake | CMake options).
This way you need to edit your CMakeLists.txt once, but then you can change the actual value without touching the source code.
I guess you can hack it around without touching CMakeLists.txt at all, but the approach above seems more straightforward and idiomatic.

Linking different libraries for Debug and Release builds in Cmake on windows?

So I've got a library I'm compiling and I need to link different third party things in depending on if it's the debug or release build (specifically the release or debug versions of those libraries). Is there an easy way to do this in Cmake?
Edit: I should note I'm using visual studio
According to the CMake documentation:
target_link_libraries(<target> [lib1 [lib2 [...]]] [[debug|optimized|general] <lib>] ...)
A "debug", "optimized", or "general"
keyword indicates that the library
immediately following it is to be used
only for the corresponding build
configuration.
So you should be able to do this:
add_executable( MyEXE ${SOURCES})
target_link_libraries( MyEXE debug 3PDebugLib)
target_link_libraries( MyEXE optimized 3PReleaseLib)
Somehow the answer from #Mike Willekes got CMake linking in the same target both release and debug for me :(
I only got this working by setting both configurations in one line, as suggested by #sakra in a related question - and doing so for every library that needed to be linked:
target_link_libraries ( app
debug ${Boost_FILESYSTEM_LIBRARY_DEBUG}
optimized ${Boost_FILESYSTEM_LIBRARY_RELEASE} )
target_link_libraries ( app
debug ${Boost_LOG_LIBRARY_DEBUG}
optimized ${Boost_LOG_LIBRARY_RELEASE} )
target_link_libraries ( app
debug ${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG}
optimized ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE} )
# ...
I would like to add a few notes to the previous answers.
If you need to create a list of multiple files you want to link and store that in a cache variable then you need to add the optimized or debug specified before each and every library. This can be especially useful for larger makefiles/projects.
So for example you could do something like this:
set( MyFavLib_LIBRARIES
debug debug/module1.lib optimized release/module1.lib
debug debug/module2.lib optimized release/module2.lib )
target_link_libraries( app ${MyFavLib_LIBRARIES} )
What worked for me was to use $(Configuration) macro in a lib path provided to cmake.
So, assuming libs are stored in separate, correctly named folders, e.g.:
C:\boost\lib\Debug\libfoo.lib
C:\boost\lib\Release\libfoo.lib
You can then call cmake with:
cmake -G "Visual Studio 10 2010" -DBOOST_LIBRARYDIR=C:\boost\lib\$(Configuration)\libfoo.lib
That'll generate .vcxproj with Additional Dependencies including C:\boost\lib\$(Configuration)\libfoo.lib, what is evaluated to either C:\boost\lib\Release\libfoo.lib or C:\boost\lib\Debug\libfoo.lib depending on a chosen Configuration.
target_link_libraries with optimize and debug doesn't work for me. I follow the post of Mike Willekes, but release config also import debug library file in visual studio. Then, I use the following cmake code to solving this problem
add_library(BoostLib STATIC IMPORTED)
set_target_properties(BoostLib PROPERTIES
IMPORTED_LOCATION_DEBUG ${BoostLibPath}/debug/module1.lib
IMPORTED_LOCATION_RELEASE ${BoostLibPath}/release/module1.lib)
target_link_libraries(AppTarget BoostLib)