Adding a custom command with the file name as a target - cmake

I'd like to do something like add_custom_command, with the output file
name as a target in the generated makefile. Is there an elegant way of
doing this?
All the examples I've seen (such as the CMake FAQ re: latex) use add_custom_command to tell how to generate the desired output file, and then add_custom_target to create a target. For example.:
add_executable (hello hello.c)
add_custom_command(OUTPUT hello.bin
COMMAND objcopy --output-format=binary hello hello.bin
DEPENDS hello
COMMENT "objcopying hello to hello.bin")
add_custom_target(bin ALL DEPENDS hello.bin)
However, the target name in the generated makefile is then bin rather
than hello.bin. Is there a way to make hello.bin itself a target
in the generated makefile?
Some solutions I've tried that don't work:
Changing to: add_custom_target(hello.bin ALL DEPENDS hello.bin) results in a circular dependency in the makefile.

You could do it by generating your hello.bin as a side effect of a target. Instead of generating hello.bin from objcopy, you generate hello.tmp. Then as a side effect you also copy hello.tmp to hello.bin. Finally, you create the phony target hello.bin that depends on your hello.tmp. In code:
add_executable (hello hello.c)
add_custom_command(OUTPUT hello.tmp
COMMAND objcopy --output-format=binary hello hello.tmp
COMMAND ${CMAKE_COMMAND} -E copy hello.tmp hello.bin
DEPENDS hello
COMMENT "objcopying hello to hello.bin")
add_custom_target(hello.bin ALL DEPENDS hello.tmp)
The problem with that is that hello.bin is not cleaned when you run clean. To get that working, add:
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES hello.bin)

Related

Why doesn't CMake detect dependency on my generated file?

I'm trying to generate a header with a custom command. The header should be updated on each rebuild, so that the source file which includes it would also be rebuilt. (Actual command is a script, but here is a simplified version.)
Here's my project:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(test_SOURCES test.c)
include_directories("${CMAKE_BINARY_DIR}")
set(VERSION_H_PATH "${CMAKE_BINARY_DIR}/version.h")
message("VERSION_H_PATH: ${VERSION_H_PATH}")
add_custom_command(OUTPUT "${VERSION_H_PATH}" COMMAND "touch" "${VERSION_H_PATH}")
#add_custom_target(GENERATE COMMAND "touch" "${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog GENERATE)
test.c
#include <version.h>
int main()
{
return 0;
}
Now the problem is that the CMakeList.txt, as presented above, doesn't result in version.h being created at all. Only after I switch from add_custom_target to add_custom_command does it do. But then, if I change the file somehow, next make doesn't rebuild the project.
Looks like CMake doesn't recognize that test.c depends on version.h, although it does explicitly #include it. What am I doing wrong here?
Change:
add_custom_command(OUTPUT "${VERSION_H_PATH}" COMMAND "touch" "${VERSION_H_PATH}")
#add_custom_target(GENERATE COMMAND "touch" "${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog GENERATE)
Into:
add_custom_command(OUTPUT "${VERSION_H_PATH}" COMMAND ${CMAKE_COMMAND} -E touch "${VERSION_H_PATH}") #More reliable touch, use cmake itself to touch the file
add_custom_target(generate_version_h DEPENDS "${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog generate_version_h)
See:
CMake command line tool mode.
add_custom_target:
DEPENDS:
Reference files and outputs of custom commands created with add_custom_command() command calls in the same directory (CMakeLists.txt file). They will be brought up to date when the target is built.
add_dependencies:
Make a top-level depend on other top-level targets to ensure that they build before does. A top-level target is one created by one of the add_executable(), add_library(), or add_custom_target() commands (but not targets generated by CMake like install).
By the way, I do not know your specific case, but you might consider using configure_file to generate your header.
The problem seems to be that the name test used for the executable target is a name reserved by CMake. See policy CMP0037. Using a different name for the executable seems to work as expected with the custom target:
add_custom_target(GENERATE COMMAND "touch" "${VERSION_H_PATH}")
add_executable(testexe ${test_SOURCES})
add_dependencies(testexe GENERATE)
Every custom command needs a driver (something that will depend on its output). In your case, the best driver would be the test executable, which means you should add the generated file into your executable's sources:
add_executable(test ${test_SOURCES} ${VERSION_H_PATH})
OK, actually the question was badly formulated from the beginning. I shouldn't have simplified the generating command as much as I did. But the problems I had seem to have been solved by removing content of build directory and re-running cmake. For some reason some changes to CMakeLists.txt are not easy for cmake to understand. So here's the CMakeLists.txt which does work, and with not too much simplified generator command:
cmake_minimum_required(VERSION 2.8)
set(test_SOURCES test.c)
include_directories("${CMAKE_BINARY_DIR}")
set(VERSION_H_PATH "${CMAKE_BINARY_DIR}/version.h")
message("VERSION_H_PATH: ${VERSION_H_PATH}")
add_custom_target(GENERATE COMMAND "bash" "-c" "[ -e ${VERSION_H_PATH} ] \\|\\| touch ${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog GENERATE)
This appears to work even when using the reserved test target instead of myprog.

Retrieve all link flags in CMake

In CMake, is it possible to programmatically retrieve the complete list of linker flags that will be used for a given target? The only way I can see to do this is to inspect the link.txt file in the target's CMakeFiles directory. Not ideal.
The use case that I'm interested in is to collect the data to include in something like a pkg-config file. I'm writing a library, and it includes a couple executable utilities that use the library. Building the executables (especially when the library is build statically) requires a non-trivial link line to link to my library and its dependencies. So I'd like to write out the link line necessary for building these executables to a data file included with the package such that other clients can know how to link.
As #Tsyvarev has commented there is no build-in command or property "to programmatically retrieve the complete list of linker flags" in CMake.
But inspired by your hint "so I'd like to write out the link line necessary for building these executables to a data file" I think I found a feasible solution (at least for makefile generators).
And if I understand your request correctly, we are not talking about simple verbose outputs like you get with e.g. CMAKE_VERBOSE_MAKEFILE, which would still need you to copy things manually.
So taking the following into account:
You need to run the generator first to get the real link line
CMake allows you to invent any linker language by name
You can define the link line with CMAKE_>LANG<_LINK_EXECUTABLE using variables and expansion rules
I came up with adding an LinkLine executable using my ECHO "linker" with the single purpose to create a link line file of my choosing:
set(CMAKE_ECHO_STANDARD_LIBRARIES ${CMAKE_CXX_STANDARD_LIBRARIES})
set(CMAKE_ECHO_FLAGS ${CMAKE_CXX_FLAGS})
set(CMAKE_ECHO_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS})
set(CMAKE_ECHO_IMPLICIT_LINK_DIRECTORIES ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
set(
CMAKE_ECHO_LINK_EXECUTABLE
"<CMAKE_COMMAND> -E echo \"<FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>\" > <TARGET>"
)
add_executable(LinkLine "")
target_link_libraries(LinkLine MyLibraryTarget)
set_target_properties(
LinkLine
PROPERTIES
LINKER_LANGUAGE ECHO
SUFFIX ".txt"
)
The nice thing about this approach is, that the output of my LinkLine target can be used as any other "officially generated" executable output (e.g. in install() commands or post-build steps with generator expressions):
add_custom_command(
TARGET LinkLine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LinkLine> PackageCfg/$<TARGET_FILE_NAME:LinkLine>
)
References
Recursive list of LINK_LIBRARIES in CMake
add_custom_command is not generating a target

Can not generate a CMake command

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}")

How to configure CMake target or command to preprocess C file?

I originally asked this question on CMake mailing list: How to configure target or command to preprocess C file?
I'm porting build configuration based on GNU Autotools to CMake and I have to deal with C preprocessing to generate a file.
The input for preprocessor is SQL file with C preprocessor directives used, like #include "another.sql", etc.
Currently, Makefile uses the following rule to generate plain SQL file as output:
myfile.sql: myfile.sql.in.c
cpp -I../common $< | grep -v '^#' > $#
So, the myfile.sql is meant to be one of products of the build process, similar to share libraries or executables.
What CMake tools should I use to achieve the same effect?
It's unclear to me if I should use add_custom_command, add_custom_target or combine both.
Obviously, I'm looking for a portable solution that would work at least with GNU GCC and Visual Studio toolsets. I presume I will have to define platform-specific custom commands, one for cpp preprocessor, one for cl.exe /P.
Or, does CMake provide any kind of abstraction for C preprocessor?
I scanned the archives, but I only found preprocessing of fortran files or solutions based on make capabilities: make myfile.i
So, it's not quite what I'm looking for.
UPDATE: Added answer based on solution received from Petr Kmoch on CMake mailing list.
I'm answering the question to myself by copying essential parts of solution received from Petr Kmoch as response to my post in the mailing list.
First, create a custom command using add_custom_command (version with the OUTPUT signature) to actually do the preprocessing.
For example:
add_custom_command(
OUTPUT myfile.sql
COMMAND "${CMAKE_C_COMPILER}" -E myfile.sql.in -I ../common
MAIN_DEPENDENCY myfile.sql.in
COMMENT "Preprocessing myfile.sql.in"
VERBATIM)
Second, configure the command trigger:
If the command output file (myfile.sql) is used in another target, added as a source
file added to add_library or add_executable, it is enough to specify it in these commands. CMake will find it as a dependency and run the custom command as required.
If the command output file is a final output not used as dependency in
any other targets, then add a custom target to drive the command using add_custom_target
For example:
add_custom_target(
ProcessSQL ALL
DEPENDS myfile.sql
COMMENT "Preprocessing SQL files"
VERBATIM)
Credits: Petr Kmoch
To take advantage of CMake' make myfile.i feature, you can do this:
add_library(sql_cpp_target EXCLUDE_FROM_ALL myfile.sql.in.c)
Now running make myfile.sql.in.c.i will produce preprocessed source for you, using defined CMAKE_C_FLAGS. It might be possible to change output name and dir for preprocessed file.
At any rate, you'd need to wrap these make invocations into add_custom_target(ALL ...) to make CMake run them during build.
Use CMAKE_MAKE_PROGRAM variable in targets definitions.
If you want to abstract from build tool, you can call cmake itself to build a target for you. Use ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target targetname when defining custom target.
Alternatively, you can just add_custom_command() which runs specified compiler to preprocess files and put them at the appropriate place. But this seems to be less flexible, IMO.

cmake add_custom_command

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.