How to loop through all LCOV coverage projects in cmake - cmake

Using this link https://github.com/QianYizhou/gtest-cmake-gcov-example I was able to generate LCOV reports for my C++ project code coverage.
For example, I have 5 projects in my solution. 4 libraries and 1 executable. Each projects contains it's own CMakeLists.txt
As per the steps given in the above github link, I added
SETUP_TARGET_FOR_COVERAGE(
coverage_${PROJECT_NAME} # Name for custom target.
${PROJECT_NAME} # Name of the test driver executable that runs the tests.
# NOTE! This should always have a ZERO as exit code
# otherwise the coverage generation will not complete.
${CMAKE_PROJECT_ROOT_DIR}application/TestReports/coverage_${PROJECT_NAME}_dir # Name of output directory.
)
endif()
so when I completed my cmake build command when the make file is generated, I can see these 5 projects. so for example, if one of my project name is abc,
in command line if I type make space tab key I can see coverage_abc
Here my question comes. I am integrating this into my pipeline, so rather than giving these project names individually can I iterate the makefile and generate make command?

Related

Find a CMake file-generating add_custom_command example in which DEPENDS option is necessary

I want a simple example to illustrate the DEPENDS option of file generating add_custom_command(OUTPUT ...), that is, if we comment the DEPENDS part, the example will give different output or totally crash.
In the following example (there are files london and good.cpp in the current working directory), DEPENDS is dispensable:
cmake_minimum_required(VERSION 3.10)
project(Tutorial VERSION 1.0)
add_custom_command(OUTPUT foo
COMMAND cp london foo
#DEPENDS london
COMMENT "I'm testing the new method.")
add_executable(cake good.cpp foo)
I did read the documentation. I have little knowledge about building system, neither Make nor CMake. The first sentence Specify files on which the command depends. confuses me. I don't understand how a command depends on other files, in my casual example, the command line itself seems to locate everything. I want a CMake code example to show how command depends on other files, with the necessary help of DEPENDS.
The phrase in documentation
Specify files on which the command depends.
is better understandable as
Specify files on which content of the command's output file(s) depends.
As one could guess, a content of the output file of the command cp london foo depends only from london, so it is reasonable to specify option DEPENDS london for add_custom_command.
As a build system, CMake uses information in DEPENDS for decide, whether to run the command or not. If:
OUTPUT file has already been created on previous run, and
since previous run the DEPENDS file has not been updated,
then the command won't be run again. The reasoning is simple: no needs to run the command if it results with the same file(s).
Taking into account source (CMAKE_SOURCE_DIR) and build (CMAKE_BINARY_DIR) directories separation, the example could be rewritten as follows:
cmake_minimum_required(VERSION 3.10)
project(Tutorial VERSION 1.0)
add_custom_command(
OUTPUT foo # relative path denotes a file in the build directory
COMMAND cp ${CMAKE_SOURCE_DIR}/london foo # The command will be run from the build directory,
# so need to use absolute path for the file in the source directory
DEPENDS london # relative path is resolved in the source directory,
# assuming that corresponded file is already existed
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} # specifies a directory from which run the COMMAND
# build directory is used by default, so the option can be omitted
COMMENT "I'm testing the new method."
)
add_executable(cake
good.cpp # relative path is resolved in the source directory,
# assuming that corresponded file is already existed
foo # because given file is absent in the source directory,
# the path is resolved relative to the build directory.
)
When build the project the first time, both foo and executable will be built.
When build the project the second time (without changing in london) nothing will be rebuilt.
When change london file and build the project again, foo will be re-built (because it depends on london). As foo is rebuilt, the executable will be rebuilt too, because it depends on foo.

How to use glib-compile-resources with CMake

As any GTK project grows, GTK applications tend to be bundled with gresources to separate out code and UI design. This is very useful because UI/UX designers don't need to know code in order to... well design and ultimately contribute their skills and effort to the project.
Not only designers but programmers too benefit a lot! Because code becomes heavily "logic or problem solving" instead of maintaining both UI and logic code together in one single file.
However, to compile our GResource we need glib-compile-resources utility tool. The command usually goes like this:
glib-compile-resources --generate-source --target=<output-file> <input-file>
But how do I create a build script that compiles our gresource files and link it with our target project? I'm still a newbie learning CMake and I've gotten far enough to know what a target is, how to set a variable, how to link a target, and also how to pull in the required GTK packages for linking. But I don't have any clue how to proceed ahead with solving this :(
A solution to this is using add_custom_command() to compile your gresources. But first here's a breakdown of what you need for your CMake script:
Pull in glib-compile-resources as executable program - find_program()
Define how to compile your gresource - add_custom_command()
Then define your custom target - add_custom_target()
Tell CMake that resource is a generated file - set_source_files_properties()
Finally, add your custom target to your project target as a dependency - add_dependencies()
Here's a sample CMake script:
cmake_minimum_required(VERSION 3.15)
project(dummy)
# Step 1:
find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED)
set(GRESOURCE_C test.gresource.c)
set(GRESOURCE_XML test.gresource.xml)
# Step 2:
add_custom_command(
OUTPUT ${GRESOURCE_C}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${GLIB_COMPILE_RESOURCES}
ARGS
--target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}
${GRESOURCE_XML}
VERBATIM
MAIN_DEPENDENCY ${GRESOURCE_XML}
DEPENDS
for.glade
bar.glade
)
# Step 3:
add_custom_target(
dummy-resource
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}
)
# Step 4:
add_executable(${PROJECT_NAME} dummy.c ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C})
set_source_files_properties(
${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}
PROPERTIES GENERATED TRUE
)
# Step 5:
add_dependencies(${PROJECT_NAME} dummy-resource)
Brief explanation
add_custom_command()
OUTPUT - This is your generated resource file
WORKING_DIRECTORY - Where your XML and glade files are located
VERBATIM - Makes sure our COMMAND receives ARGS unchanged
MAIN_DEPENDENCY - for glib-compile-resources <input-file>
DEPENDS - Your glade file(s). If any of the file changes then your target build is triggered :)
add_custom_target()
dummy-resource - That's your custom target name
DEPENDS - The output your custom target needs in order to trigger your custom command
set_source_files_properties()
When you first generate your build files using cmake command, your resource file isn't generated yet. So CMake will run into error because it doesn't know where your resource file is or where it's coming from. We need to tell CMake "Don't fail, our resource file is generated later"
Use --generate-dependencies instead of hard-coding
Now you might notice we are duplicating our effort ie., when we add new glade files or remove existing ones (or any other resources such as icon, sounds, css files, etc) we have to edit both our XML and CMake script files. glib-compile-resources already provide dependency generation so we can use that in our CMake script and make it smart.
The trick is to change your .xml file to .xml.in as a configuration file. So when that configuration file changes, you call glib tool with --generate-dependencies, get new dependency output values, and send that to add_custom_command(... DEPENDS). Now we have an intelligent CMake :)
If you want to approach this method then the below post would be really helpful:
Use list as dependencies on add_custom_command
Good luck :)

CMake: Regenerate source file if target gets rebuilt

I am trying to embed the build date into a source file, so that every time a specific target gets built, the embedded date is refreshed, without regenerating every time the overall project built.
I.e. I have a header file builddate.h that is generated by a command that has a set of #defines. This header file is then included from other source files.
My first attempt was this:
add_custom_target(builddate COMMAND <command that generates header file>)
add_library(mylibrary ...)
add_dependencies(mylibrary builddate)
This correctly generates the header file, however the header file is generated every time, regardless of whether the mylibrary target needs to be rebuilt.
Trying with a custom command instead, i.e.
add_custom_command(OUTPUT builddate.h COMMAND <command that generates header file>)
add_library(mylibrary ... builddate.h)
correctly generates the header once, but if the mylibrary target is rebuilt, the header is not regenerated as builddate.h is already up to date.
This feels like something that should be reasonably common, but I cannot figure out what incantation of custom commands and targets will give me the desired effect. What I want is to call the command every time the mylibrary target is built, without spurious rebuilds if nothing has changed or if unrelated targets (such as executables using mylibrary) are built.
Using a PRE_BUILD custom command would sound like a good idea, but the docs state that this gets invoked just prior to PRE_LINK commands for generators other than Visual Studio, i.e. after sources are compiled. This seems like it would make this unsuitable for this purpose, as the header is needed while compiling the sources.
Found an old thread at https://cmake.org/pipermail/cmake/2010-October/040247.html suggesting to call CMake's --build for a target as a PRE_LINK command:
# This is the library that I want to build
add_library(mylibrary ...)
# Set up a library that contains the code depending on the build date
# Use an OBJECT library because we don't need it to be a full static lib
# we just want to build some source that would "normally" have been part of mylibrary
add_library(builddate OBJECT EXCLUDE_FROM_ALL codethatusesbuilddate.cpp)
# Add a PRE_LINK command for mylibrary so that prior to linking we
# 1. Generate the builddate.h header
# 2. Call CMake to build the builddate library we just set up
add_custom_command(
TARGET mylibrary PRE_LINK
COMMAND <command that generates builddate.h>
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target builddate
)
# We also need to link with the library
# NOTE: uses the generator expression to link with the output files rather than the target
# to avoid CMake setting up a dependency from builddate to mylibrary which I think
# would cause builddate to be built prior to building mylibrary, but at that point we
# haven't generated the header yet. Which we could fix, but then we'd just build it twice
target_link_libraries(mylibrary PRIVATE $<TARGET_OBJECTS:builddate>)
This feels a little awkward, but it seems to work.
Footnote: Generating the header is easily done using CMake, i.e. first configure_file or similar to create a CMake script that does the generation, then invoke ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/generated_cmake_file.cmake as the command to generate the header.
Some time ago, I wrote a cmake makro. It adds custom command to generate version.cpp in current build directory by executing Cversion.cmake.
The generation of file is executed only when dependencies have changed.
With cmake-generator-expressions dependencies are set to dependencies of target minus its own (files).
It could be improved by adding libs dependencies to also generate anew version file.
macro(add_versioning T)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
COMMAND ${CMAKE_COMMAND} "-DCMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-P "${PROJECT_SOURCE_DIR}/Version/CVersion.cmake"
MAIN_DEPENDENCY "${PROJECT_SOURCE_DIR}/Version/version.cpp.in"
DEPENDS "$<FILTER:$<TARGET_OBJECTS:${T}>,EXCLUDE,version.cpp.+$>")
target_include_directories(${T} PUBLIC "${PROJECT_SOURCE_DIR}/Version")
target_sources(${T} PUBLIC "${PROJECT_SOURCE_DIR}/Version/version.h" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
endmacro()

Building a tool immediately so it can be used later in same CMake run

I have an interesting chicken-and-egg problem and a potential solution to it (see my posted answer), but that solution uses CMake in an unusual way. Better alternatives or comments would be welcome.
THE PROBLEM:
The simple version of the problem can be described as a single CMake project with the following characteristics:
One of the build targets is a command-line executable which I'll call mycomp, the source of which is in a mycompdir and making any modifications to the contents of that directory is not possible.
The project contains text files (I'll call them foo.my and bar.my) which need mycomp run on them to produce a set of C++ sources and headers and some CMakeLists.txt files defining libraries built from those sources.
Other build targets in the same project need to link against the libraries defined by those generated CMakeLists.txt files. These other targets also have sources which #include some of the generated headers.
You can think of mycomp as being something like a compiler and the text files in step 2 as some sort of source files. This presents a problem, because CMake needs the CMakeLists.txt files at configure time, but mycomp is not available until build time and therefore isn't available on the first run to create the CMakeLists.txt files early enough.
NON-ANSWER:
Normally, an ExternalProject-based superbuild arrangement would be a potential solution to this, but the above is a considerable simplification of the actual project I am dealing with and I don't have the freedom to split the build into different parts or perform other large scale restructuring work.
The crux of the problem is needing mycomp to be available when CMake is run so that the generated CMakeLists.txt files can be created and then pulled in with add_subdirectory(). A possible way to achieve this is to use execute_process() to run a nested cmake-and-build from the main build. That nested cmake-and-build would use the exact same source and binary directories as the top level CMake run (unless cross compiling). The general structure of the main top level CMakeLists.txt would be something like this:
# Usual CMakeLists.txt setup stuff goes here...
if(EARLY_BUILD)
# This is the nested build and we will only be asked to
# build the mycomp target (see (c) below)
add_subdirectory(mycompdir)
# End immediately, we don't want anything else in the nested build
return()
endif()
# This is the main build, setup and execute the nested build
# to ensure the mycomp executable exists before continuing
# (a) When cross compiling, we cannot re-use the same binary dir
# because the host and target are different architectures
if(CMAKE_CROSSCOMPILING)
set(workdir "${CMAKE_BINARY_DIR}/host")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${workdir}")
else()
set(workdir "${CMAKE_BINARY_DIR}")
endif()
# (b) Nested CMake run. May need more -D... options than shown here.
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
-DEARLY_BUILD=ON
${CMAKE_SOURCE_DIR}
WORKING_DIRECTORY "${workdir}")
# (c) Build just mycomp in the nested build. Don't specify a --config
# because we cannot know what config the developer will be using
# at this point. For non-multi-config generators, we've already
# specified CMAKE_BUILD_TYPE above in (b).
execute_process(COMMAND ${CMAKE_COMMAND} --build . --target mycomp
WORKING_DIRECTORY "${workdir}")
# (d) We want everything from mycompdir in our main build,
# not just the mycomp target
add_subdirectory(mycompdir)
# (e) Run mycomp on the sources to generate a CMakeLists.txt in the
# ${CMAKE_BINARY_DIR}/foobar directory. Note that because we want
# to support cross compiling, working out the location of the
# executable is a bit more tricky. We cannot know whether the user
# wants debug or release build types for multi-config generators
# so we have to choose one. We cannot query the target properties
# because they are only known at generate time, which is after here.
# Best we can do is hardcode some basic logic.
if(MSVC)
set(mycompsuffix "Debug/mycomp.exe")
elseif(CMAKE_GENERATOR STREQUAL "Xcode")
set(mycompsuffix "Debug/mycomp")
else()
set(mycompsuffix "mycomp")
endif()
set(mycomp_EXECUTABLE "${workdir}/mycompdir/${mycompsuffix}")
execute_process(COMMAND "${mycomp_EXECUTABLE}" -outdir foobar ${CMAKE_SOURCE_DIR}/foo.my ${CMAKE_SOURCE_DIR}/bar.my)
# (f) Now pull that generated CMakeLists.txt into the main build.
# It will create a CMake library target called foobar.
add_subdirectory(${CMAKE_BINARY_DIR}/foobar ${CMAKE_BINARY_DIR}/foobar-build)
# (g) Another target which links to the foobar library
# and includes headers from there
add_executable(gumby gumby.cpp)
target_link_libraries(gumby PUBLIC foobar)
target_include_directories(gumby PUBLIC foobar)
If we don't re-use the same binary directory at (b) and (c) as we use for the main build, we end up building mycomp twice, which we obviously want to avoid. For cross compiling, we cannot avoid that, so in such cases we build the mycomp tool off to the side in a separate binary directory.
I've experimented with the above approach and indeed it appears to work in the real world project that prompted the original question, at least for the Unix Makefiles, Ninja, Xcode (OS X and iOS) and Visual Studio generators. Part of the attractiveness of this approach is that it only requires a modest amount of code to be added just to the top level CMakeLists.txt file. Nevertheless, there are some observations that should be made:
If the compiler or linker commands for mycomp and its sources are different in any way between the nested build and the main build, the mycomp target ends up getting rebuilt a second time at (d). If there are no differences, mycomp only gets built once when not cross compiling, which is exactly what we want.
I see no easy way to pass exactly the same arguments to the nested invocation of CMake at (b) as was passed to the top level CMake run (basically the problem described here). Reading CMakeCache.txt isn't an option since it won't exist on the first invocation and it would not give you any new or changed arguments from the current run anyway. The best I can do is to set those CMake variables I think are potentially going to be used and which may influence the compiler and linker commands of mycomp. This can be worked around by adding more and more variables as I encounter ones I discover I need, but that's not ideal.
When re-using the same binary directory, we are relying on CMake not starting to write any of its files to the binary directory until the generate stage (well, at least until after the build at (c) completes). For the generators tested, it appears we are okay, but I don't know if all generators on all platforms follow this behaviour too (and I can't test every single combination to find out!). This is the part that gives me the greatest concern. If anyone can confirm with reasoning and/or evidence that this is safe for all generators and platforms, that would be valuable (and worth an upvote if you want to address this as a separate answer).
UPDATE: After using the above strategy on a number of real world projects with staff of varying levels of familiarity with CMake, some observations can be made.
Having the nested build re-use the same build directory as the main build can occasionally lead to problems. Specifically, if a user kills the CMake run after the nested build completes but before the main build does, the CMakeCache.txt file is left with EARLY_BUILD set to ON. This then makes all subsequent CMake runs act like a nested build, so the main build is essentially lost until the CMakeCache.txt file is manually removed. It is possible that an error somewhere in one of the project's CMakeLists.txt file may also lead to a similar situation (unconfirmed). Performing the nested build off to the side in its own separate build directory has worked very well though with no such problems.
The nested build should probably be Release rather than Debug. If not re-using the same build directory as the main build (now what I'd recommend), we no longer care about trying to avoid compiling the same file twice, so may as well make mycomp as fast as possible.
Use ccache so that any costs due to rebuilding some files twice with different settings are minimised. Actually, we found using ccache typically makes the nested build very quick since it rarely changed compared to the main build.
The nested build probably needs to have CMAKE_BUILD_WITH_INSTALL_RPATH set to FALSE on some platforms so that any libraries mycomp needs can be found without having to set environment variables, etc.

Ninja equivalent of Make's "build from this directory down" feature (with CMake)?

When building a project using CMake and Make, you can execute make from a subdirectory of your build tree (i.e. from a directory below whatever directory contains your top-level Makefile), and make will (as far as I can tell) build all targets at or below that directory. This is because CMake generates a Makefile for every directory that contains targets, so when you're in a directory with targets, make finds the Makefile for building those targets.
When CMake generates Ninja files, however, it only generates one build.ninja file, which is at the top level of the build tree. So calling ninja from a directory other than the top-level directory fails (even the -f option doesn't work because ninja can't find the rules.ninja file).
Is there any way to emulate the "make-like" behavior of building targets at and below a directory? As far as I can tell, there are no Ninja targets that correspond to "all targets at and below a particular directory." (This could be emulated using phony targets named after each directory that depend on all targets at and below that directory, but CMake does not generate such targets by default.)
ninja <DIR>/all works with recent versions of Ninja (1.7.2). Version 1.3.4 does not allow this.
I could not find a reference to this on the manual. However, CMake has this documented here:
Recent versions of the ninja program can build the project through the “all” target. An “install” target is also provided.
For each subdirectory sub/dir of the project, additional targets are generated:
sub/dir/all
Depends on all targets required by the subdirectory.
sub/dir/install
Runs the install step in the subdirectory, if any.
sub/dir/test
Runs the test step in the subdirectory, if any.
sub/dir/package
Runs the package step in the subdirectory, if any.
This worked for me:
cd <build-root>
DIRECTORY=<path-relative-to-build-root>
ninja -t targets all | egrep "^${DIRECTORY}/" | egrep CXX_EXECUTABLE_LINKER | \
sed -e 's/:.*//g' | xargs ninja
ninja -t targets all - lists all targets (including target type)
egrep "^${DIRECTORY}/" - filters list of targets to only include those in desired directory
egrep CXX_EXECUTABLE_LINKER - limits the targets to just C++ executables. You can remove or tweak this to get the set of targets you're interested in.
sed -e 's/:.*//g' - removes the target type e.g. ": CXX_EXECUTABLE_LINKER"
xargs ninja - invokes ninja to build the targets
Good question. I would like to know the answer if you find it.
I am just in the process of transitioning to cmake+ninja myself.
I found that I could not create targets with the same name at different levels
(if there is a way I would be interested to know).
So I adopted a naming convention for different targets
E.g.
name - builds program or library
test.name - runs tests for the named program or library
doxygen.name - build doxygen for the named program or library
For deeper hierarchies you can do something like:
doxygen.subproject
doxygen.subproject.name
Using this pattern you can control precisely what is built but you have to issue the command from the top-level build directory.
I think after I get used to this I will find it more productive as there is no need to change directory before you build or run something and though there is sometimes a little extra typing required the shell history generally has it covered.
This is implemented under the hood by using add_custom_target() and adding appropriate dependencies. I use a macro to do this automatically so that
a macro "add_doxygen()" will add the doxygen target for the program and make the doxygen target at each higher level depend on it using add_dependencies().