CMake custom command called twice - cmake

Why version.cmake are called twice in the setup detailed bellow? How do I correct this to call it just one time?
Details: The objective is to call version.cmake in every build once, regardless of any dependency (this trick was adapted from here). This module verify the current git version and if it differs from a previous version.cpp file, it write a new file. The version.cpp are a dependency of the main program test.cpp and are linked together. This way, if the version stay the same, nothing need to be compiled or linked, if differs, it get recompiled and relinked with the main cpp. A reconfiguration isn't needed.
Note: To make this more easy to explain/reproduce, and be more focused in the related problem, the version.cmake bellow was greatly simplified, not depending of git. It just write a new version.cpp every time it is called.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(test)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.cpp
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/version.cmake
DEPENDS dummy_always_rebuild
)
add_custom_command(
OUTPUT dummy_always_rebuild
COMMAND true > /dev/null
)
add_library(libversion OBJECT
${CMAKE_CURRENT_BINARY_DIR}/version.cpp
)
add_executable(test test.cpp)
target_link_libraries(test PRIVATE libversion)
version.cmake:
message("version.cmake called")
# (not showed here) get sw version, **IF** it differs from existing 'version.cpp', write a new file:
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" "const char* version=\"xx.yy.zz\";")
test.cpp:
#include <iostream>
extern const char* version;
int main(int argc, char **argv) {
std::cout << "version=" << version << std::endl;
return 0;
}
Console output for the make command (after a cmake run). Observe that version.cmake are called twice:
[ 20%] Generating dummy_always_rebuild
[ 40%] Generating version.cpp
version.cmake called
Scanning dependencies of target libversion
[ 40%] Generating dummy_always_rebuild
[ 40%] Generating version.cpp
version.cmake called
[ 60%] Building CXX object CMakeFiles/libversion.dir/version.cpp.o
[ 60%] Built target libversion
[ 80%] Linking CXX executable test
[100%] Built target test
Setup info: Linux OS, cmake version 3.12.0, GNU Make version 4.2.1.

Related

How to setup 2 CMake targets for a single executable with different post build actions?

I am working on an embedded project managed with CMake and I would like to do different actions on the same executable.
Consider I have the following project:
/cmake/foo.cmake
/CMakeLists.txt
/main.cpp
Irrelevant main.cpp for this question:
#include <iostream>
int main() {
std::cout << "hello world" << std::endl;
return 0;
}
The foo.cmake file contains a function:
function(print_executable_size TARGET_NAME)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND size ${TARGET_NAME}.exe
)
endfunction()
The main CMakeLists.txt has the following content:
cmake_minimum_required(VERSION 3.15)
project(proj)
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(foo)
add_executable(pgm-dev main.cpp)
add_executable(pgm-prod ALIAS pgm-dev)
# this line works but this is not needed when compiling the "dev" program.
print_executable_size(pgm-dev)
# Uncomment this line leads to TARGET 'pgm-prod' was not created in this directory.
# print_executable_size(pgm-prod)
My ideal build process would be to have:
a cmake target "pgm-dev" that just build the executable,
a cmake target "pgm-prod" that re-build the "pgm-dev" executable if necessary AND do some POST_BUILD actions.
Why having two targets "pgm-dev" and "pgm-prod"?
Consider the "pgm-prod" does some extra build actions like cipher the produced binary so, no need to do it in everyday development.
Why use a cmake file with a function instead of add_custom_command() right after executable?
I have multiple executables concerned in my whole project and I would like to avoid code duplications.
Why not creating another executable, with a different name?
"pgm-dev" and "pgm-prod" are exactly compiled the same way, only post build actions differ.
I thought using add_executable(.. ALIAS ..) would be great for this but it seems I'm not understanding some key points here. What would be the best CMake approach to do what I want?
Don't create an alias. Instead create a custom target that executes the commands and add a dependency to the executable target
add_executable(pgm-dev main.cpp)
add_custom_target(pgm-prod COMMAND size $<TARGET_FILE:pgm-dev>)
add_dependency(pgm-prod pgm-dev)
This way cmake makes sure that pgm-dev is built before the command is executed.
If you need to more than one of those commands to all be executed, you could introduce intermediate targets that execute the command that depend on the original target and create a target for executing all those commands that depends on all of those:
function(pgm_add_custom_postbuild_command ORIGINAL_TARGET NEW_TARGET SUFFIX)
if(NOT TARGET ${ORIGINAL_TARGET})
add_custom_target(${ORIGINAL_TARGET})
endif()
add_custom_target(pgm_internal_${ORIGINAL_TARGET}_${SUFFIX} ${ARGN})
# hide away target in a dedicated folder, if folders are activated in the IDE
set_target_properties(pgm_internal_${ORIGINAL_TARGET}_${SUFFIX} PROPERTIES FOLDER PgmInternal)
add_dependencies(pgm_internal_${ORIGINAL_TARGET}_${SUFFIX} ${ORIGINAL_TARGET})
add_dependencies(${NEW_TARGET} pgm_internal_${ORIGINAL_TARGET}_${SUFFIX})
endfunction()
function(pgm_print_size ORIGINAL_TARGET NEW_TARGET)
pgm_add_custom_postbuild_command(${ORIGINAL_TARGET} ${NEW_TARGET} size
COMMAND size $<TARGET_FILE:${ORIGINAL_TARGET}>)
endfunction()
function(pgm_print_md5sum ORIGINAL_TARGET NEW_TARGET)
pgm_add_custom_postbuild_command(${ORIGINAL_TARGET} ${NEW_TARGET} md5sum
COMMAND ${CMAKE_COMMAND} -E md5sum $<TARGET_FILE:${ORIGINAL_TARGET}>)
endfunction()
pgm_print_size(pgm-dev pgm-prod)
pgm_print_md5sum(pgm-dev pgm-prod)

cmake rule that depends on the output of a command

How do I generate source files during the pre-build step if and only if they need to be regenerated?
One of my project's dependencies is a library (libfoo) which expensive to relink (several minutes) and even more expensive to rebuild (less than an hour). Generating the source files for this dependency is inexpensive (several seconds), but using out-of-date sources would render the resultant application suite useless. I have a command check_foo.sh that will exit with a non-zero status when the sources must be regenerated, but I haven't been able to determine how to convince CMake to run check_foo.sh during every build and only rebuild libfoo when check_foo.sh returns nonzero.
In trying to create a simple proof, the closest I have gotten is as follows, although only ever runs generate_foo_if.sh once. The ultimate goal is that generate_foo_if.sh gets run unconditionally, but libfoo is only rebuilt when generate_foo_if.sh modifies foo.cpp.
CMakeLists.txt
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(my_project
VERSION 1.0.0.0
LANGUAGES CXX)
add_custom_command(OUTPUT foo.cpp
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/generate_foo_if.sh" "${CMAKE_CURRENT_BINARY_DIR}/foo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/check_foo.sh"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Generating foo.cpp..."
)
add_library(foo STATIC foo.cpp)
add_executable(main main.cpp)
target_link_libraries(main foo)
main.cpp
#include "foo.hpp"
int main(int,char**){
return foo::exit_status;
}
foo.hpp
#pragma once
namespace foo {
extern const int exit_status;
}
check_foo.sh
#!/usr/bin/env bash
exit $(((${RANDOM} % 2 )))
generate_foo_if.sh
#!/usr/bin/bash
CHECK=${2:-./check_foo.sh}
if [ ${CHECK} -eq 0 ]; then
exit 0
fi
msg=$(cat <<__EOF
#include "foo.hpp"
namespace foo {
const int exit_status = 1;
}
__EOF
)
echo "${msg}" >${1:-foo.cpp}
Turns out, I wasn't very far off the mark.
The critical difference seems to be in creating a custom target rather than a custom command, using BYPRODUCTS rather than OUTPUT, and explicitly adding the dependency. Updated CMakeLists.txt is below, and results in the desired behavior (i.e. libfoo is only regenerated if it should be).
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(my_project
VERSION 1.0.0.0
LANGUAGES CXX)
add_custom_target(generate_foo
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/generate_foo_if.sh" "${CMAKE_CURRENT_BINARY_DIR}/foo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/check_foo.sh"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
BYPRODUCTS foo.cpp
)
add_library(foo STATIC foo.cpp)
add_dependencies(foo generate_foo)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
add_executable(main main.cpp)
target_link_libraries(main foo)
While I can't really say I know why it works, this does what I want.

Cppcheck support in CMake

I am not asking about the various available third-party modules that support Cppcheck in one way or the other.
With CMake 3.10, CMake seems to have gained some official Cppcheck support. See CMAKE_<LANG>_CPPCHECK.
Unfortunately the documentation how to use this variable is a bit sparse. Is there a good example of how Cppcheck is supposed to be used with CMake 3.10 (or later)?
An simple example would be - if you have cppcheck in your PATH and you are not specifying additional parameters - the following by setting global CMAKE_<LANG>_CPPCHECK variable:
cmake_minimum_required(VERSION 3.10)
project(CppCheckTest)
file(
WRITE "main.cpp"
[=[
int main()
{
char a[10];
a[10] = 0;
return 0;
}
]=]
)
set(CMAKE_CXX_CPPCHECK "cppcheck")
add_executable(${PROJECT_NAME} "main.cpp")
The files to scan are added automatically to the cppcheck command line. So the above example gives the following output (gcc and cppcheck on Linux system):
# make
Scanning dependencies of target CppCheckTest
[ 50%] Building CXX object CMakeFiles/CppCheckTest.dir/main.cpp.o
Checking .../CppCheckTest/main.cpp...
Warning: cppcheck reported diagnostics:
[/mnt/c/temp/StackOverflow/CppCheckTest/main.cpp:4]: (error) Array 'a[10]' accessed at index 10, which is out of bounds.
[100%] Linking CXX executable CppCheckTest
[100%] Built target CppCheckTest
You could give cppcheck a try in an existing project by simply setting the CMAKE_CXX_CPPCHECK variable via the cmake command line:
# cmake -DCMAKE_CXX_CPPCHECK:FILEPATH=cppcheck ..
A more "daily life" example would probably for you to include something like the following code snippet in your CMakeList.txt:
find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck)
if (CMAKE_CXX_CPPCHECK)
list(
APPEND CMAKE_CXX_CPPCHECK
"--enable=warning"
"--inconclusive"
"--force"
"--inline-suppr"
"--suppressions-list=${CMAKE_SOURCE_DIR}/CppCheckSuppressions.txt"
)
endif()
References
CMake Commit: Add properties to run cppcheck along with the compiler
<LANG>_CPPCHECK target property
This property is supported only when <LANG> is C or CXX.
Specify a ;-list containing a command line for the cppcheck static analysis tool. The Makefile Generators and the Ninja generator will run cppcheck along with the compiler and report any problems.
This property is initialized by the value of the CMAKE_<LANG>_CPPCHECK variable if it is set when a target is created.

How to copy the binary output of one target into the binary folder of another target?

I'm building a dynamic library that is meant to be loaded dynamically like a plugin. When present, the library is loaded. When not present, it can't.
Naturally, I made a test app...and it doesn't work.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
PROJECT(MYLIB)
enable_testing()
INCLUDE(CPack)
SET(SRCS
src/source1.cpp
src/source2.cpp
)
ADD_LIBRARY(mylib SHARED ${SRCS})
ADD_SUBDIRECTORY(test)
test/CMakeLists.txt
ADD_EXECUTABLE(test_loader main.c)
TARGET_LINK_LIBRARIES(test_loader dl)
ADD_TEST(NAME test_loader COMMAND test_loader)
test/main.c
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
void* handle;
handle = dlopen("./mylib.so", RTLD_LAZY);
if (handle == 0)
{
fprintf(stderr, "%s\n", dlerror());
}
return 1;
}
and then to build
mkdir build
cd build
cmake ..
make
The result is that there is a mylib.so file in /build. There is a test_loader executable in /build/test.
And this doesn't work out.
What I need is for there to be a copy of mylib.so under /build/test/ so that I can dynamically load it with the test app.
While the answers given helped me greatly (and anyone reading this should review those answers as well as the comments), I found an even better solution:
add_custom_command(TARGET test_loader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:mylib>" $<TARGET_FILE_DIR:test_loader>)
This solution results in two copies of the library. One copy is next to the test_loader, so that the unit tests can work. The other is in the default output location. Since it's still in the default output location, other projects that depend on mylib know where to find them, by default.
There are cmake variables that let you control where libraries, shared libraries, and executables are placed. See cmake documentation Variables that Control the Build. I do not think it is a good idea to mix executables and libraries. (Of course this is my opinion--you can use whatever layout you want.) I use the following:
# Directory for output files
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
CACHE PATH "Output directory for static libraries.")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
CACHE PATH "Output directory for shared libraries.")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
CACHE PATH "Output directory for executables and DLL's.")
If you used this, then you would need to adjust your dlopen statement to handle = dlopen("../lib/libmylib.so", RTLD_LAZY); Note that I adjusted the name of mylib because I believe cmake will, by default on Linux, use a lib prefix when naming libraries.

Retrieve sources using shell command or globbing, update build accordingly

How can I get a CMake generated build system to retrieve source files using an arbitrary shell command and update the build properly?
The motivation for doing this is to migrate from another build system to CMake. The intermediate goal is to have a single list of source files shared between the build systems. The list of source files might actually live inside of the other build system but in general suppose some shell command can retrieve the list of source files. This problem is very similar to the problem of using globbing to get source file names but in this case manually listing all the source files in a CMakeLists.txt file is not a reasonable alternative.
Even if there's no way to get CMake itself to do this, an answer that provides any automated solution would be fine (e.g. a script that wraps the generated build system).
Very simple concrete example of the problem
We have an app that consists of two source files, main.cpp and foo.cpp. For some reason it is desirable to acquire the names of sources files with some shell command instead of listing them in a CMakeLists.txt file. For this example, the files are listed one per line in files.txt and we cat this file. In general, the shell command is some script that retrieves a list of source files in mysterious ways.
main.cpp (ver 1)
#include "foo.h"
int main() {
foo();
}
foo.h
#ifndef FOO_H
#define FOO_H
void foo();
#endif
foo.cpp
#include "foo.h"
#include <iostream>
void foo() {
std::cout << "foo()" << std::endl;
}
files.txt (ver 1)
main.cpp
foo.cpp
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.1)
project(SourcesFromCommand)
# run some external command that retrieves our source files
execute_process(COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/files.txt OUTPUT_VARIABLE files)
# turn newline separated relative filenames into cmake list of absolute filenames
string(REPLACE "\n" ";${CMAKE_CURRENT_SOURCE_DIR}/" file_list ${files})
# print filenames to make sure the list came out right
foreach(file ${file_list})
message(${file})
endforeach()
add_executable(main ${file_list})
CMake generates a working build system for a project that consists of the above files. Later, our app is successful and popular so we decide to add new functionality for ver. 2.0. main.cpp now calls bar() which lives in bar.h and bar.cpp. We update files.txt accordingly.
main.cpp (ver 2)
#include "foo.h"
#include "bar.h"
int main() {
foo();
bar();
}
bar.h
#ifndef BAR_H
#define BAR_H
void bar();
#endif
bar.cpp
#include "bar.h"
#include <iostream>
void bar() {
std::cout << "bar()" << std::endl;
}
files.txt (ver 2)
main.cpp
foo.cpp
bar.cpp
The build system previously generated by CMake no longer works -- trying to use it results in linker errors because it doesn't know about bar.cpp. This can be solved manually by touching the CMakeLists.txt file or rerunning the cmake command but the point of a build system is to free us from such arduous and easily forgotten manual labor. How can this be automated?
You can solve this problem with a makefile that touchs the relevant CMakeLists.txt files.
I'll continue from the OP's example and also add a directory, glob_us/ from which we want to glob all filenames matching *.cpp. It contains baz.cpp which is similar to the OP's bar.cpp.
Relevant files:
Makefile
CMakeLists.txt
files.txt
main.cpp
main.h
foo.cpp
foo.h
bar.cpp
bar.h
glob_us/baz.h
glob_us/baz.cpp
The bottom of CMakeLists.txt becomes:
file(GLOB globbed_files glob_us/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/glob_us)
add_executable(main ${file_list} ${globbed_files})
Makefile contains the following:
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
GLOBBED := $(wildcard $(MAKEFILE_DIR)/glob_us/*cpp)
# phony target that depends on whatever files we need to touch
cmake: $(MAKEFILE_DIR)/CMakeLists.txt
$(MAKEFILE_DIR)/CMakeLists.txt: $(MAKEFILE_DIR)/files.txt $(GLOBBED)
#touch $(MAKEFILE_DIR)/CMakeLists.txt
.PHONY: cmake
Generate a build system:
mkdir build
cd build
cmake -G $MY_FAVORITE_GENERATOR ..
Then build:
make -f ../Makefile && $MY_FAVORITE_BUILD_SYSTEM_COMMAND
Files can be added to and globbed from glob_us or as in the OP's example, to files.txt, without manual intervention.