My CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(main)
SET(MAIN main)
SET(MAIN_OUT "${CMAKE_CURRENT_BINARY_DIR}/out.txt")
add_executable(${MAIN} main.cpp)
# command is unknown
add_custom_command(OUTPUT ${MAIN_OUT}
POST_BUILD
COMMAND ./${MAIN} > ${MAIN_OUT}
DEPENDS ${MAIN}
)
After compiling, I just want to be able to type
make out.txt
However, cmake seems to be unaware of this target ("no rule"). In the build directory, a call of
grep out.txt -r *
finds no files containing out.txt. How can I make my target callable? I know this has probably asked before, but I have not found it.
If you want to be able to type "make out.txt", you probably want add_custom_target instead of add_custom_command. This creates a target which can be built, and in building executes the specified commands.
Rather than call this target "out.txt" which would misleadingly make it look like a text file instead of a target, I'd recommend something more like "RunMain" or "GetOutputOfMain".
If you can specify a recent version of CMake as the minimum, you can use "generator expressions" within the command part of your add_custom_target call. This isn't documented for add_custom_target, but you can read about generator expressions in the docs for add_custom_command. I'm not sure what the minimum required version of CMake should be set to in order to have generator expressions available.
So, your CMakeLists.txt could be changed to something like:
cmake_minimum_required(VERSION 2.8.10)
project(Test)
add_executable(MyExe main.cpp)
set(MainOut "${CMAKE_CURRENT_BINARY_DIR}/out.txt")
add_custom_target(RunMain $<TARGET_FILE:MyExe> > ${MainOut}
COMMENT "Running MyExe with output redirected to ${MainOut}")
# Ensure MyExe is built before trying to build the custom target
add_dependencies(RunMain MyExe)
Then just do make RunMain to generate out.txt.
If you don't want to specify such a high minimum version, you can use the obsolete LOCATION target property instead:
get_target_property(MyExeLocation MyExe LOCATION)
add_custom_target(
RunMain ${MyExeLocation} > ${MainOut}
COMMENT "Running ${MyExeLocation} with output redirected to ${MainOut}")
Related
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)
Part of my source code is generated by a tool which is also built under our main project with a add_subdirectory. We execute this tool with a execute_process command. Clearly, if the tool is not built before we reach the execute_process statement it will fail.
I use a GLOB (file(GLOB...)) to find the source files generated. I do this because it is not possible to know beforehand how many files are generated, neither their names.
How do I force cmake to wait for the subproject to be compiled before the execute process? I would need something like a DEPENDS property for the execute_process but this option is not available.
# This subproject will source generator the tool
add_subdirectory(generator)
# I need something like: wait_for(generator)
execute_process(COMMAND generator ${CMAKE_SOURCE_DIR}/src)
file(GLOB GeneratedSources ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(mainprject.exe ${ProcessorSourceFiles}
Command execute_process executes its COMMAND immediately, at configuration stage. So it cannot be arranged after the executable is created with add_executable command: that executable will be built only at build stage.
You need to build subproject at configuration stage too. E.g. with
execute_process(COMMAND ${CMAKE_COMMAND}
-S ${CMAKE_SOURCE_DIR}/generator
-B ${CMAKE_BINARY_DIR}/generator
-G ${CMAKE_GENERATOR}
)
execute_process(COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}/generator
)
The first command invokes cmake for configure the 'generator' project, located under ${CMAKE_SOURCE_DIR}/generator directory. With -G option we use for subproject the same CMake generator, as one used for the main project.
The second command builds that project, so it produces generator executable.
After generator executable is created, you may use it for your project:
execute_process(COMMAND ${CMAKE_BINARY_DIR}/generator/<...>/generator ${CMAKE_SOURCE_DIR}/src)
Here you need to pass absolute path to the generator executable as the first parameter to COMMAND: CMake no longer have generator executable target, so it won't substitute its path automatically.
You will need to model this with target dependencies. The tool "generator" should be a cmake target. In that case use add_custom_target instead of execute_process somthing like this:
add_custom_target(generate_sources ALL COMMAND generator ${CMAKE_SOURCE_DIR}/src))
Then add a target dependency to "generator" using add_dependencies:
add_dependencies(generate_sources generator)
This will make sure your target "generate_sources", which runs the tool will only run during build after the target "generator" has been compiled.
The following is false, see the comments for more info:
Use add_dependencies to add a dependency from "mainproject.exe" to "generate_sources". Now this I have never tested, so take with a grain of salt: With CMake more recent than version 3.12, according to the entry on file, you should then be able to change your file command to:
file(GLOB GeneratedSources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/src/*.cpp)
Which I interpret as this will re-glob the files during build if the directory changes.
I want to copy qml files from source directory to build directory. Following script works fine only first time. When I change any of the *.qml files and run make, they are not copied to build folder, they are not updated. What am I doing wrong?
file(GLOB_RECURSE SOURCES *.cpp)
file(GLOB_RECURSE QMLS *.qml)
add_library(MyLib SHARED ${SOURCES} ${QMLS})
foreach(QmlFile ${QMLS})
add_custom_command(TARGET MyLib POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${QmlFile} $<TARGET_FILE_DIR:MyLib>)
endforeach()
While Angew's answer is good, it is possible to eliminate usage of additional target. For doing this, add_library call should use copied .qml files (instead of original ones, like in the script in the question post):
# This part is same as in Angew's answer
set(copiedQmls "")
foreach(QmlFile ${QMLS})
get_filename_component(nam ${QmlFile} NAME)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${nam}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QmlFile} ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${QmlFile}
COMMENT "Copying ${QmlFile}"
VERBATIM
)
list(APPEND copiedQmls ${CMAKE_CURRENT_BINARY_DIR}/${nam})
endforeach()
# But instead of creating new target, we reuse library one.
add_library(MyLib SHARED ${SOURCES} ${copiedQmls})
When library target is built, it triggers non-sources files in add_library call to be updated (if there is corresponded add_custom_command call), but updating non-source files doesn't force library file to be rebuilt. This is why your original code doesn't work as expected.
Note, because .qml files are not recognized by CMake as sources, you doesn't need to set GENERATED property for them, as stated here.
Your are using the TARGET signature of add_custom_command, which means the commands are executed as part of building the TARGET. In your case, POST_BUILD, which means the commands will be run after the build of MyLib finishes. If MyLib is up to date and does not need to be re-built, the commands will not run.
You might want to use the output-generating signature (OUTPUT) instead. Something like this:
set(copiedQmls "")
foreach(QmlFile ${QMLS})
get_filename_component(nam ${QmlFile} NAME)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${nam}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QmlFile} ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${QmlFile}
COMMENT "Copying ${QmlFile}"
VERBATIM
)
list(APPEND copiedQmls ${CMAKE_CURRENT_BINARY_DIR}/${nam})
endforeach()
add_custom_target(
CopyQMLs ALL
DEPENDS ${copiedQmls}
)
Note that unfortunately, the OUTPUT argument of add_custom_command does not support generator expressions, so $<TARGET_FILE_DIR> cannot be used there. I used ${CMAKE_CURRENT_BINARY_DIR} in the example above, you might need to customise this to suit your needs. ${CMAKE_CFG_INTDIR} can be used to specify the per-configuration directory for multiconfiguration generators.
Note the presence of the additional custom target in my code above. That's necessary, because CMake will only execute an output-producing custom command if something depends on that output. The custom command does that, by listing the outputs in its DEPENDS section.
Perhaps this is impossible and I'm misreading the cmake 3.2 documentation, but I though creating a custom command would create a custom "target" in the Makefile so that I could build the target by invoking the name of the output file. The CMake docs says:
In makefile terms this creates a new target in the following form:
OUTPUT: MAIN_DEPENDENCY DEPENDS
COMMAND
so I thought I could then run make OUTPUT. Perhaps the documentation is confusing CMake targets with Makefile targets?
For example,
add_custom_command(OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
I would like to do
make foo_out
and it will make foo_out. However, if I do this, I get
make: **** No rule to make target `foo_out`. Stop.
and sure enough, the word "foo_out" doesn't exist anywhere in any file in the cmake binary output directory. If I change it to this
add_custom_target(bar DEPENDS foo_out)
add_custom_command(OUTPUT foo_out COMMAND post_process foo_in > foo_out)
Then I can do
make bar
and I can do
make foo_in
but I still can't do
make foo_out
The problem with make bar is that it is unintuitive, as the actual file output is foo_out not bar.
How do I do this?
In my case, I need to run a special processing step to the standard executable target which inserts optional resources into the ELF file. I would like the ability to have both executables as Makefile targets, so I can build the naked ELF executable as well as the resource-injected ELF executable.
If I was writing a custom Makefile, this is trivial to do!
foo_in: foo.c
$(CC) $< -o $#
foo_out: foo_in
post_process $< > $#
And I can do make foo_in and make foo_out.
add_custom_command does not create a new target. You have to define targets explicitly by add_executable, add_library or add_custom_target in order to make them visible to make.
If you have to fix things up for deployment, you could
1. use the install command (somewhere in your CMakeLists.txt) like this:
install(SCRIPT <dir>/post_install.cmake)
to store commands which are executed only when you run make install in a separate .cmake file. Or if the install target is already reserved for other things or you have more complex stuff going on:
2. manually define a deploy target. Once you got that, you can create a custom post-build command which is only executed when you explicitly run make on your deploy target. This allows you to execute commands through a separate target.
In your CMakeLists.txt this could look like:
cmake_minimum_required(VERSION 3.0)
add_executable("App" <sources>)
# option 1: do deployment stuff only when installing
install(SCRIPT <dir>/post_install.cmake)
# option 2: define a deploy target and add post-build commands
add_custom_target("deploy")
add_custom_command(TARGET "deploy" POST_BUILD <some command>)
Both approaches allow you to separate dev builds from expensive ready-to-deploy builds (if I understand correctly, that's the goal here). I would recommend option 1 since it's just cleaner.
Hope this helps!
Documentation Unclear
CMake's documentation is unclear here. The Makefiles generators of CMake do create the source file make rules in sub Makefiles which are not visible in the main Makefile. In the main Makefile you will find only the PHONY rules for your CMake targets. The only exception I know of is the Ninja
Makefiles generator which puts all build rules into single file.
Translating Post-Processing Steps into CMake
From my experience - if post_process is a script - you should probably think about rewriting your post-processing steps with/inside the CMake scripts, because CMake should know about all the file dependencies and variables used for post-processing (it then will e.g. handle all the necessary re-build or clean-up steps for you).
Here is a simplified/modified version of what I do:
function(my_add_elf _target)
set(_source_list ${ARGN})
add_executable(${_target}_in ${_source_list})
set_target_properties(
${_target}_in
PROPERTIES
POSITION_INDEPENDENT_CODE 0
SUFFIX .elf
)
add_custom_command(
OUTPUT ${_target}_step1.elf
COMMAND some_conversion_cmd $<TARGET_FILE:${_target}_in> > ${_target}_step1.elf
DEPENDS ${_target}_in
)
add_custom_target(
${_target}_step1
DEPENDS
${_target}_step1.elf
)
add_custom_command(
OUTPUT ${_target}_out.elf
COMMAND final_post_process_cmd ${_target}_step1.elf > ${_target}_out.elf
DEPENDS ${_target}_step1
)
add_custom_target(
${_target}_out
DEPENDS
${_target}_out.elf
)
# alias / PHONY target
add_custom_target(${_target} DEPENDS ${_target}_out)
endfunction(my_add_elf)
and then call
my_add_elf(foo foo.c)
It's only an example, but I hope it gives the idea: you could call make foo for the final ELF output, make foo_in or make foo_step1 for one of the other steps. And I think all steps are transparent for the user and CMake.
Can't give your Target the same name as one of the Outputs
When you're trying to give a custom target the same name as one of its outputs e.g. like this:
add_executable(foo_in foo.c)
add_custom_command(
OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
add_custom_target(foo_out DEPENDS foo_out)
You end-up with invalid make files. I've raised an issue about this in the hope that there could be a possible solution by extending CMake itself and got the following reply:
CMake is not intended to produce specific content in a Makefile.
Top-level target names created by add_custom_target are always logical
(i.e. phony) names. It is simply not allowed to have a file of the
same name.
Posible Workarounds
So there are some workarounds, but they all have one or the other disadvantage.
1. Shortest Version:
macro(my_add_elf_we _target)
add_executable(${_target}_in ${ARGN})
add_custom_target(
${_target}_out
COMMAND post_process $<TARGET_FILE:${_target}_in> > ${_target}_out
DEPENDS ${_target}_in
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target}_out)
endmacro(my_add_elf_we)
You can't declare OUTPUTs in the add_custom_target() itself, but in this case you don't want to (because you don't want to have any naming confusions). But if you don't declare any outputs:
The target will always considered out-of-date
You need to add the "invisible" outputs the clean build rule
2. Force Output Name Version
Here is a version of the above macro that forces target and output names to given values:
macro(my_add_elf_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_custom_target(
${_target_out}
COMMAND post_process ${_target_in} > ${_target_out}
DEPENDS ${_target_in}
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target_out})
endmacro(my_add_elf_in_out)
You call it with:
my_add_elf_in_out(foo_in.elf foo_out.elf foo.c)
3. Object Libary Version
The following version uses object libraries, but the system will not reuse the foo_in target linkage:
macro(my_add_elf_obj_in_out _target_in _target_out)
add_library(${_target_in}_obj OBJECT ${ARGN})
add_executable(${_target_in} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
EXCLUDE_FROM_ALL 1
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
endmacro(my_add_elf_obj_in_out)
4. Last and Final Version
And one final version that definitely works only for with Makefile generators and that got me posting the issue at CMake's bug tracker:
macro(my_add_elf_ext_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} NotExisting.c)
set_source_files_properties(
NotExisting.c
PROPERTIES
GENERATED 1
HEADER_FILE_ONLY 1
)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
RULE_LAUNCH_LINK "# "
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
add_dependencies(${_target_out} ${_target_in})
endmacro(my_add_elf_ext_in_out)
Some references
CMake add_custom_command/_target in different directories for cross-compilation
CMake: how do i depend on output from a custom target?
cmake add_custom_command
How do I use CMake to build LaTeX documents?
Turning around the dependencies, and using the second signature of add_custom_command, this should work:
add_custom_target(foo_out DEPENDS foo_in)
add_custom_command(TARGET foo_out POST_BUILD COMMAND post_process foo_in > foo_out)
Note: Adding BYPRODUCTS foo_out will cause (for example) ninja to say
multiple rules generate foo_out. builds involving this target will not be correct; continuing anyway
I'm struggling with add_custom_command. Let me explain the problem in detail.
I've these set of cxx files and hxx files. I run a perl script on each of them to generate a certain kind of translation file. The command looks like
perl trans.pl source.cxx -o source_cxx_tro
and similarly for header.hxx files as well.
So I'll end up with some multiple commands (each for a file)
Then I run another perl scripn on the output generated from these commands (source_cxx_tro, header_hxx_tro)
perl combine.pl source_cxx_tro header_hxx_tro -o dir.trx
dir.trx is the output file.
I've something like this.
Loop_Over_All_Files()
Add_Custom_Command (OUTPUT ${trofile} COMMAND perl trans.pl ${file} -o ${file_tro})
List (APPEND trofiles ${file_tro})
End_Loop()
Add_Custom_Command (TARGET LibraryTarget POST_BUILD COMMAND perl combine.pl ${trofiles} -o LibraryTarget.trx)
What I expect is when building the post build target, the trofiles will be built first. but it is not the case. The ${trofiles} are not getting built and hence the post build command ends in a failure.
Is there any way I can tell the POST_BUILD command depend on the previous custom command ?
Any suggestions ?
Thanks in advance,
Surya
Use add_custom_command's to create a file transformation chain
*.(cxx|hxx) -> *_(cxx|hxx)_tro
*_(cxx|hxx)_tro -> Foo.trx
and make the last transformation an first class entity in cmake by using add_custom_target. By default this target won't be build, unless you mark it with ALL or let another target that is built depend on it.
set(SOURCES foo.cxx foo.hxx)
add_library(Foo ${SOURCES})
set(trofiles)
foreach(_file ${SOURCES})
string(REPLACE "." "_" file_tro ${_file})
set(file_tro "${file_tro}_tro")
add_custom_command(
OUTPUT ${file_tro}
COMMAND perl ${CMAKE_CURRENT_SOURCE_DIR}/trans.pl ${CMAKE_CURRENT_SOURCE_DIR}/${_file} -o ${file_tro}
DEPENDS ${_file}
)
list(APPEND trofiles ${file_tro})
endforeach()
add_custom_command(
OUTPUT Foo.trx
COMMAND perl ${CMAKE_CURRENT_SOURCE_DIR}/combine.pl ${trofiles} -o Foo.trx
DEPENDS ${trofiles}
)
add_custom_target(do_trofiles DEPENDS Foo.trx)
add_dependencies(Foo do_trofiles)
You want to create a custom target that consumes the output of the custom commands. Then use ADD_DEPENDENCIES to make sure the commands are run in the right order.
This might be sort of close to what you want:
https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-do-i-use-cmake-to-build-latex-documents
Basically one add_custom_command for each file generated, collect a list of those files (trofiles), then use add_custom_target with a DEPENDS on the list trofiles. Then use add_dependencies to make the LibraryTarget depend on the custom target. Then the custom target should be built before the library target is built.