Report target failure in addition to translation unit compilation failure - cmake

Suppose I have hundreds of targets and some of them are not critical for the build to succeed (and for example I am using --keep-going on make or -k 9000 on ninja) and I need to figure out which cmake targets failed.
With add_custom_command() a post-build command can be added to a cmake target that prints its name like this:
success: myTarget.dll
But what about failures?
If linking fails then I can parse the verbose output of whatever I am using (ninja/make/msbuild) and see which target has failed.
However if compilation of a translation unit fails the only error I get is that a particular source file does not compile and figuring out which cmake target exactly has failed is harder.
The only thing I have come up with is running this after the build has failed: ninja -nv which will make a verbose dry run and I can intercept the link commands and parse the cmake targets that have failed that way...
Any other ideas?

I ended up using dry runs of make/ninja and parsing their output

Related

How can I make colcon output a plain CMake project's output with the ninja generator?

Ninja redirects the stderr output to stdout. When used with colcon and its colcon-cmake extension, the error log is therefore not displayed when a ninja package build is failing.
How can I see the build error messages?
There is no direct solution to the problem (see Colcon does not show failed build output if using Ninja generator).
This GitHub issue mentions a workaround, though: Add --event-handlers console_cohesion+ to the colcon build call, either systematically, or only on a build failure, depending on how clean you want your build output to be. It reveals the stdout output (and thus the errors issued by ninja).

CMake Error: Unknown argument --clean-first

When running the follow CMake command, I am receiving an error. I am working with CMake version 3.20.5.
cmake --clean-first ./src/basis_universal/CMakeLists.txt
CMake Error: Unknown argument --clean-first
However, --clean-first appears to be supported.
Just to make it abundantly clear to you... typically there are 2 steps you take in any cmake project... configuration and building.
In the configuration step, CMake looks for the files on your system, the compiler, etc. and prepares everything for building.
The building step of actually turning your code into an executable is a second, separate step.
When you run
cmake --clean-first ./src/basis_universal/CMakeLists.txt
you are just configuring your project. The --clean-first command is not available during configuration.
After configuration, you need to build your project. In that step, you can use the --clean-first option.

Waiting for targets in a CMake build

I think I do have a CMake order/parallelism problem.
In my build process, I need to build a tool which is then later used by some other target. This tool is a separate project with a CMakeLists.txt file like this:
project (package-tool LANGUAGES CXX)
set (SOURCES package_tool.cpp)
...
Later in the build, this top level target is referenced by some other target:
...
add_custom_command (OUTPUT "${DST_FILE}"
COMMAND ${PACKAGE_COMMAND} "${DST_FILE}"
COMMAND package-tool.exe -e "${DST_FILE}"
DEPENDS ${PACKAGE_DEPENDENCIES} package-tool)
...
I use ninja for building and the dependencies (ninja -t depends) are looking correctly. Also, the build commands (ninja -t commands) are making sense. But: From time to time, the build fails. The message does not make sense, it reads:
This version of package-tool.exe is not compatible with the version
of Windows you're running.
Because the build runs in parallel (32 processes) I suspect that the package-tool target is not completed when the generated exe is being used in the second target, which might lead to this confusing error message. Again, most of the time the build succeeds but every 10th or 20th run, it fails with that message.
So now my question is:
Is there a way to wait for a tool/target having been finished building in a parallel build in CMake/Ninja ?
Or how do I handle the task of building build tools in the same build process correctly ?
Thank you in advance !
Actually depend on the executable file and run the executable file, not the target. Don't concern yourself with any .exe suffix. Also better don't assume add_custom_command will be run in CMAKE_RUNTIME_OUTPUT_DIRECTORY - if you depend on specific directory explicitly set it with WORKING_DIRECTORY.
add_custom_command (
OUTPUT "${DST_FILE}"
COMMAND ${PACKAGE_COMMAND} "${DST_FILE}"
COMMAND $<TARGET_FILE:package-tool> -e "${DST_FILE}"
DEPENDS ${PACKAGE_DEPENDENCIES} $<TARGET_FILE:package-tool>
)

Evaluate command only when running tests

I need to check if the mpirun command is present and exit with an error message if not present, but only when the user tries to run the tests. When just building the main library or executable, this command need not exist.
More generally, how to execute a cmake script when a specific target is invoked? I.e., only when I type build some_target, cmake should start searching for certain environment variables, commands, etc.
EDIT
Workaround. In my case, the custom target is dependent on an executable, and for the executable I can use add_custom_command with the PRE_LINK flag. The custom command then displays an error message and calls exit 1 if necessary and only when the custom target is invoked. However, the PRE_LINK option only works on real targets such as executables and libraries, and not for a custom target in general, so I'm still curious how to solve this for the general case.

Is there a way to get errors when a CMake command fails?

I am writing a script and started working with the install command (for copying files) and it is not working. CMake configure/generate does not show any errors (i.e. it does not stop and no warnings/errors show related to this command) and the command does not seem to be working, because I don't see any files being copied.
Since I am new, I am wondering:
How can I tell that install failed (perhaps the source directory was wrong, or the destination directory was wrong)? It appears to be failing silently.
Are there error codes I can check to see what went wrong?
When is install called? When I click configure? Or when the project is built?
I am on Windows.
To the general question, there are a number of ways to get more verbose output from CMake - I just learned a third for gnarly errors:
to debug CMake recipes, I like using the message command and you can even iterate over directories and issue messages*
e.g. message( STATUS "SQLITE3_LIB: ${SQLITE3_LIB} SQLITE3_PATH: ${SQLITE3_PATH}") # prints SQLITE3_LIB and SQLITE3_PATH variables
perform verbose builds to troubleshoot your build itself
run make VERBOSE=1 (with make, ninja -v with ninja, etc.) to help you troubleshoot the process, such as cmake -DYOUR_OPTION="insert values" ~/path/to/files/ && make VERBOSE=1
if you ever find an inscrutable error, I just learned that we can run strace on the failing command - this can be a bit overwhelming, but can help when you have exhausted #1 and #2
I just used strace /usr/bin/cmake -E copy_directory $MY_SOURCE_PATH $MY_DEST_PATH to try to understand why a copy was failing
*I have used DLRdave's answer to a different question to print out the INCLUDE_DIRS:
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "dir='${dir}'")
endforeach()
When you add an install command to your CMakeLists.txt, you get a new target created called "install".
In order to actually install the chosen files/targets, you need to build this install target. It's not automatically built as part of the "ALL" target.
For example, if you're using Visual Studio, the "INSTALL" target should appear in the "CMakePredefinedTargets" folder of the Solution Explorer. Just selecting this target and building it will cause the solution to be built and the selected items installed.
If any part of the build or install process fails, the notifications should then be apparent.