CMake: require building of files in addition to building targets - cmake

In this simple CMakefile, the first script list.sh outputs a list of 2 generated files file1.proto;file2.proto, instructing CMake that they can be built from source source.xml (using the second script gen.sh).
cmake_minimum_required(VERSION 3.13)
set(source "source.xml")
execute_process(
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/list.sh ${source}
OUTPUT_VARIABLE protos
)
message("${protos}: ${source}")
add_custom_command(
OUTPUT ${protos}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.sh ${source}
DEPENDS ${source}
)
add_custom_target(my_target DEPENDS ${protos})
Everything works well if I run:
$ cmake ..
file1.proto;file2.proto: source.xml
-- Configuring done
-- Generating done
-- Build files have been written to: /build
$ make my_target
[100%] Generating file1.proto, file2.proto
[100%] Built target my_target
What should I add to be able to also run the code generation with:
$ make file1.proto
[EDIT] autocomplete suggests only the following for command make:
$ make (TAB TAB)
all cmake_force edit_cache/ preinstall
clean default_target help preinstall/
clean/ depend my_target rebuild_cache
cmake_check_build_system edit_cache my_target/ rebuild_cache/

Solution from #KamilCuk :
Adding the following makes it possible to build each proto file individually
(it works, but then cmake complains about circular dependencies!)
foreach(p ${protos})
add_custom_target(${p} DEPENDS {CMAKE_CURRENT_BINARY_DIR}/${p})
endforeach()

Related

How can I include a dependency file generated by a custom command in cmake for GNU make?

I have integrated a tool that generates some code from a text file in CMake based build environment.
This tool is also able to generate the dependency file in the GNU make format (pretty much like gcc -MD does it for c files).
I would like to include this dependency file in makefiles generated by CMake in order to correctly rebuild when necessary. Unfortunately, I could not find the correct way to do this.
I tried:
Generated Dependency Files in CMake , but there was no answer
https://cmake.org/cmake/help/latest/command/add_custom_command.html?highlight=add_custom_command has the DEPFILE option but it only works for Ninja
Has anyone had a similar issue?
try to define your file as dependency of your add_custom_target:
cmake_minimum_required(VERSION 3.0)
project(Custom_Command_TEST)
add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/your_gen_file.txt"
COMMAND /bin/date > "${CMAKE_BINARY_DIR}/your_gen_file.txt"
COMMAND /bin/echo "RUNNING COMMAND")
add_custom_target(GenerateFile
/bin/echo "RUNNING TARGET"
DEPENDS "${CMAKE_BINARY_DIR}/your_gen_file.txt")
add_executable(${PROJECT_NAME} main.cpp)
add_dependencies(${PROJECT_NAME} GenerateFile)
will only rebuild the target GenerateFile. You could put your .txt generation step as COMMAND in add_custom_command.
output of first make:
[ 33%] Generating your_gen_file.txt
RUNNING COMMAND
RUNNING TARGET
[ 33%] Built target GenerateFile
[ 66%] Building CXX object CMakeFiles/Custom_Command_TEST.dir/main.cpp.o
[100%] Linking CXX executable Custom_Command_TEST
[100%] Built target Custom_Command_TEST
output second make:
RUNNING TARGET
[ 33%] Built target GenerateFile
[100%] Built target Custom_Command_TEST
In case you want to rebuild everything again, you'll want to make clean.
You could also check this older post

Using google tests with CMake/Ctest with the new command gtest_discover_tests

I am trying to use googletest with CMake/Ctest. I have several sources files for my tests (each one containing many TEST/TEST_F/... commands) which are located in several directories. I want that the tests related to a given source are executed in the same directory as their source file. Also, I prefer that the build process of a test source file is a test by itself. So I made something like:
file(GLOB_RECURSE test_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"tests/*.cpp")
foreach(test_src ${test_srcs})
get_filename_component(test_dir ${test_src} DIRECTORY)
get_filename_component(test_exe ${test_src} )NAME_WE)
add_executable(${test_exe} EXCLUDE_FROM_ALL tests/gtest_main.cpp ${test_src})
set_target_properties(${test_exe}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${test_dir}
)
target_link_libraries(${test_exe} gtest)
add_test(NAME build_${test_exe} COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${test_exe})
set_tests_properties(build_${test_exe} PROPERTIES FIXTURES_SETUP ${test_exe})
gtest_discover_tests(${test_exe}
TEST_LIST list
WORKING_DIRECTORY ${test_dir}
PROPERTIES DEPENDS build_${test_exe}
PROPERTIES FIXTURES_REQUIRED ${test_exe}
)
endforeach()
But it seems that the dependencies I am trying to declare between the tests are not taken into account: the build of the tests does not necessarily occurs before the execution of the underlying tests...
If I use the old gtest_add_tests as in the following instead of gtest_discover_tests, it works:
gtest_add_tests(
TARGET ${test_exe}
SOURCES ${test_src}
WORKING_DIRECTORY ${test_dir}
TEST_LIST tlist
)
set_tests_properties(${tlist} PROPERTIES FIXTURES_REQUIRED ${test_exe})
Am I missing something with gtest_discover_tests?
After having started the bounty, I re-started the research on my own. I found out, the simplest method out there is to have googletest installed system-wide.
So, first install the package. On Ubuntu 18.04, that was supt apt install googletest.
For some reason, I had to build the library (perhaps not necessary somehow though?):
cd /usr/src/googletest
mkdir bin && cd bin
cmake ..
make && make install
After that I have been able to compile and run a test case. My CMakeLists.txt testing section looks like this:
enable_testing()
find_package(GTest REQUIRED)
include(GoogleTest)
add_executable(tests tests/foo_test.cpp tests/bar_test.cpp)
target_link_libraries(tests GTest::GTest GTest::Main)
gtest_discover_tests(tests)
A minimal test case file looks like this in my project:
// tests/foo_test.cpp
#include "gtest/gtest.h"
TEST(Foo, Sum)
{
EXPECT_EQ(2, 1 + 1);
}
Compiling is as easy as:
mkdir bin && cd bin
cmake ..
./tests

How to instruct CMake to use the build architecture compiler

When using CMake for cross compiling, one generally specifies a toolchain file via the CMAKE_TOOLCHAIN_FILE option. In GNU terminology, one can specify the host architecture toolset using this file. However, one can generally not expect to be able to execute anything built with this toolchain. So often enough, some build tools need to be compiled for the build architecture.
Consider the following setup. I have two source files genfoo.c and bar.c. During build, genfoo.c needs to be compiled and run. Its output needs to be written to foo.h. Then I can compile bar.c, which #include "foo.h". Since CMake defaults to using the host architecture toolchain, the instructions for bar.c are easy. But how do I tell it to use the build architecture toolchain for compiling genfoo.c? Simply saying add_executable(genfoo genfoo.c) will result in using the wrong compiler.
CMake can only handle one compiler at a time. So - if you don't go the long way to set up the other compiler as a new language - you will end up with two configuration cycles.
I see the following approaches to automate this process:
Taking the example "CMake Cross Compiling - Using executables in the build created during the build?" from the CMake pages as a starting point I'll get:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# When crosscompiling import the executable targets
if (CMAKE_CROSSCOMPILING)
set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build")
file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE)
include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake)
# Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Only build the generator if not crosscompiling
if (NOT CMAKE_CROSSCOMPILING)
add_executable(genfoo genfoo.cpp)
export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake")
endif()
Then using a script like:
build.sh
#!/bin/bash
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
cmake --build crossBuild
I'll get the desired results by calling ./build.sh.
Splitting the CMakeLists.txt and maybe even replace the export()/include() with something where I know the output path of my build tools e.g. by using CMAKE_RUNTIME_OUTPUT_DIRECTORY would simplify things:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(BuildTools)
add_executable(genfoo genfoo.cpp)
build.sh
#!/bin/bash
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild
fi
cmake --build hostBuild
cmake --build crossBuild
References
Making a CMake library accessible by other CMake packages automatically
CMake build multiple targets in different build directories
How do I make CMake output into a 'bin' dir?
It is possible to do that completely within CMake.
The trick is to run a separate CMake configuring stage within its own space, silently dismissing every crosscompiling setting and using the host's default toolchain, then import the generated outputs into it's parent, crosscompiling build.
First part:
set(host_tools_list wxrc generate_foo)
if(CMAKE_CROSSCOMPILING)
# Pawn off the creation of the host utilities into its own dedicated space
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
execute_process(
COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
add_custom_target(host_tools
COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)
foreach(tgt IN ITEMS ${host_tools_list})
add_dependencies(host${tgt} host_tools)
endforeach()
else()
# Add an empty target, host tools are built inplace
add_custom_target(host_tools
DEPENDS ${host_tools_list}
)
endif()
... then you add the usual add_executable and whatever ...
At the end:
if(NOT CMAKE_CROSSCOMPILING)
foreach(tgt IN ITEMS ${host_tools_list})
add_executable(host${tgt} ALIAS ${tgt})
endforeach()
export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()
When it crosscompiles, it pawns off the creation of the host-run tools into its own dedicated space, and imports the targets as "hostwxrc" and "hostgenerate_foo", with a dependency on generating the host_tools themselves .
When it doesn't crosscompile, it builds wxrc and generate_foo as-is, and aliases them to hostwxrc and hostgenerate_foo.
After this, when you use $<TARGET_FILE:wxrc>, you refer to the wxrc built for the target platform, and $<TARGET_FILE:hostwxrc> refers to the wxrc built for the host platform, regardless whether they are the same or not.

cmake add_custom_command not working

I am trying to run gperf from a cmake file.
I created a very minimal CMakeLists.txt below.
When I run it by
$ cmake .
$ make
It does not create the example.hpp file
What could be problem with the below CMakeLists.txt?
cmake_minimum_required( VERSION 2.6 )
function(gperf_generate_new source target)
add_custom_target(${target} echo "Creating ${target}")
add_custom_command(
SOURCE ${source}
TARGET ${target}
COMMAND gperf -L c++ ${source} > ${target}
OUTPUTS ${target}
DEPENDS ${source}
)
endfunction()
gperf_generate_new(command_options.new.gperf example.hpp)
Files, produced by source-files generators(like gpref) are rarely needed as standalone. Instead, these source files are usually used for creating executables or libraries inside a project.
So, standard pattern of using source-file generators in the CMake looks like:
# Call add_custom_command() with appropriate arguments for generate output file
# Note, that *gperf* will work in the build tree,
# so for file in the source tree full path should be used.
function(gperf_generate_new input output)
add_custom_command(
OUTPUT ${output}
COMMAND gperf -L c++ ${input} > ${output}
DEPENDS ${input}
COMMENT "Generate ${output}" # Just for nice message during build
)
endfunction()
# Generate *example.hpp* file ...
gperf_generate_new(${CMAKE_CURRENT_SOURCE_DIR}/command_options.new.gperf example.hpp)
# ... for use it in executable
add_executable(my_program ${CMAKE_CURRENT_BINARY_DIR}/example.hpp <other sources>)
If you want only to test whether example.hpp is generating, instead of add_executable() use
add_custom_target(my_target
ALL # Force target to be built with default build target.
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/example.hpp
)
Note, that linkage between add_custom_command and add_custom_target is expressed using same filename in their OUTPUT and DEPENDS options correspondingly. With such link order of these commands is insignificant (but both commands should be called from the same CMakeLists.txt script).

Using cmake with a custom file generator

I'd like to use CMake to generate obfuscated lua files for delivery. For the life of me I cannot get add_custom_command + add_custom_target to build these files for me. There's something I'm missing.
ADD_CUSTOM_TARGET(LUABIND_COMPILED_FILES ALL)
FOREACH(F ${LUA_SCRIPT_FILES})
ADD_CUSTOM_COMMAND(
OUTPUT ${LUA_COMPILED_SCRIPTS}/${F}
COMMAND ${LUAC} -o ${LUA_COMPILED_SCRIPTS}/${F}
COMMENT "Compiling ${F} to binary"
ADD_DEPENDENCIES(LUABIND_COMPILED_FILES ${LUA_COMPILED_SCRIPTS}/${F})
ENDFOREACH()
For some reason when I run cmake + make the output tells me there's nothing to be done for target LUABIND_COMPILED_FILES. Am I missing something here? Thanks in advance.
The ADD_DEPENDENCIES command can only be used to add dependencies between top-level targets. The ADD_CUSTOM_COMMAND command however generates output files, but does not add new targets.
To make a custom target depend on generated files, use the DEPENDS options of the add_custom_target command:
set (LUA_COMPILED_FILES "")
foreach(F ${LUA_SCRIPT_FILES})
add_custom_command(
OUTPUT "${LUA_COMPILED_SCRIPTS}/${F}"
COMMAND ${LUAC} -o "${LUA_COMPILED_SCRIPTS}/${F}"
COMMENT "Compiling ${F} to binary")
list (APPEND LUA_COMPILED_FILES "${LUA_COMPILED_SCRIPTS}/${F}")
endforeach()
add_custom_target(LUABIND ALL DEPENDS ${LUA_COMPILED_FILES})