cmake add_custom_command - cmake

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.

Related

Cmake get/query/print build settings on the command line?

Let's assume I have a Cmake C project, and I have something like this in the project:
project(my_project C CXX ASM)
set(my_executable_sources
main.c
file_one.c
)
set(my_executable_sources ${my_executable_sources} file_two.c)
add_executable(my_executable
${my_executable_sources}
file_three.c
)
Let's assume I'm in the ./build subfolder, and cmake ../ -G "Unix Makefiles" has passed successfully.
Can I somehow query build information from the command line using cmake?
For instance, I'm interested here in the final list of source files for my_executable; is there a command that would easily retrieve them? Say, like the following pseudocode:
$ cmake --pseudo-query-build --project="my_project" --target="my_executable" --query="source_files"
my_executable source files:
main.c
file_one.c
file_two.c
file_three.c
I don't see any cmake-generator-independent way of achieving this and even if you know the generator in use the project files generated.
You could modify your project to include a custom target that prints the sources though:
add_custom_target(print_my_executable_sources COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:my_executable,SOURCES>" COMMAND_EXPAND_LISTS)
this allows you to use
cmake --build <binary_dir> [--config <configuration>] --target print_my_executable_sources
to print the sources, even if generator expressions are used in the sources.
Note: This does print all files in a single line; to get all the file names on separate lines, you could instead run cmake with the -P option passing the soures via -D and add logic to print one file name per line in the cmake script file.
Alternatively setting the CMAKE_EXPORT_COMPILE_COMMANDS variable to True during configuration could result in the generation of json files that would allow for the extraction of the information, but you'd need a json parser to extract the info. Furthermore this approach only works for the Makefile and Ninja CMake generators. Also I'm not sure you can tell which target a source file belongs to in all cases.
Start by obtaining the target's sources via this line (after add_executable):
get_target_property(MY_TARGET_SOURCES my_executable SOURCES)
And then proceed with a simple line at the end of the file (after add_executable)
message(STATUS ${MY_TARGET_SOURCES})
EDIT: For a full list of available target properties refer to this link.
EDIT2: As I've noticed now that you probably intend to just use it within the CLI, then for my solution you would also have to encapsulate it with a if/endif that checks for a definition e.g. if(SOURCES_DEBUG_INFO) and then run it with -DSOURCES_DEBUG_INFO=TRUE

CMake call add_subdirectory within custom command

I'm working with a code generator that produces C++ and a CMakeLists.txt file, unfortunately I cannot use this in my main CMakeLists.txt file for testing purposes.
For example you have the following CMakeLists.txt file:
project(SomeProject CXX C)
add_custom_command(OUTPUT ${SRCS}
COMMAND ${CODEGEN_CLI_PATH} -i "${INPUT}" -o "${OUT}"
COMMENT "Generating sources"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
add_custom_target(CODEGEN
DEPENDS
${SRCS}
)
# Needs to be executed after the custom command
add_subdirectory(${GENERATED_CMAKE_LISTS_LOCATION})
Is it possible to use functions such as add_subdirectory only after you execute custom commands for a particular target, such as CODEGEN?
I've already tried to execute it by adding an extra line to the existing custom command:
COMMAND ${CMAKE_COMMAND} -D DIR=${GENERATED_CMAKE_LISTS_LOCATION} -P add_subdirectories.cmake
Unfortuantly this doesn't work because it isn't allowed to execute functions like add_subdirectory in script mode.
Neither I can manage to call custom made functions (that are executing add_subdirectory) from add_custom_command that are located in the same file.
Nope, it is not possible. The add_subdirectory command is run during configuration step, while CODEGEN is a target that runs during build.
You seem to be doing something wrong, so the only advice I can give you is to use execute_process command to run commands you need. The execute_process command is executed during configuration stage, so it will be able to generate files you need before add_subdirectory.
But again, please describe your problem, why do you want CMake to do that.
I have a huge fixed unsigned char array that I compiled into a static library. The way I work around it is by:
if(NOT EXISTS ${PATH_TO_FOLDER}/smeagol.a)
add_subdirectory(smeagol)
endif()
I'm still looking for a nicer kung-fu way to do it using cmake. I feel that its out there, and I will update this answer once i find it.

How to define a variable during build with cmake?

I would like to define a CMake variable BUILD_TIME_VAR in CMakeLists.txt:
computed with a python script during build phase
I can then access its content with ${VAR}
In other words, the equivalent during build phase of:
execute_process(COMMAND bash -c "python $SCRIPT $FILE" OUTPUT_VARIABLE GEN_TIME_VAR)
The variable is then used to generate a file which is a dependency to make binaries.
The goal is to make the code more easy to read since otherwise, the computation occur several times.
Rather than calling n times, the python script, to compute BUILD_TIME_VAR, I would like to use the script once, to factor the code in this way:
if(expression_1)
add_custom_command(OUTPUT foo
COMMAND cmd_1(${BUILD_TIME_VAR}))
...
elseif(expression_2)
# elseif section.
add_custom_command(OUTPUT foo
COMMAND cmd_2(${BUILD_TIME_VAR}))
...
else(expression_n)
# else section.
add_custom_command(OUTPUT foo
COMMAND cmd_n(${BUILD_TIME_VAR}))
...
endif(expression)
add_custom_target(${BINARY} ALL
DEPENDS foo)
Thanks you for your help.
If I understand your question correctly, you're effectively trying to create a "build-time variable." That is something that the build tool (actually all the build tools supported by CMake) would have to support. I know of no such functionality in build tools (make, ninja, VS, ...), and hence of no support for such a thing in CMake either.
You could emulate this by writing the results to a file and reading that file in all subsequent build steps using it.
I believe you've misinterpreted the role of CMake. In short, CMake generates build files for the back-end system of your choice (Make, ninja, etc.). This is concisely reviewed here, where the configure/generate step is briefly documented along with how it precedes the actual build step.
It's not clear what you're trying to achieve exactly, but maybe defining custom commands and using their outputs to link them to custom targets for further dependency chaining (see DEPENDS here) might be helpful, e.g.
cmake_minimum_required(VERSION 3.11)
project(foobar)
set(FOO_FILES "foo.txt")
add_custom_command(OUTPUT ${FOO_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${FOO_FILES}
COMMAND echo hello >> ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Creating ${FOO_FILES}"
VERBATIM)
add_custom_target(foo DEPENDS ${FOO_FILES})
set(BAR_FILES "bar_dummy.txt") # this is only use to link the custom command to the corresponding custom target
add_custom_command(OUTPUT ${BAR_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${BAR_FILES}
COMMAND cat ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Displaying ${FOO_FILES}"
VERBATIM)
add_custom_target(bar DEPENDS ${BAR_FILES})
add_dependencies(bar foo)
However, you might need to consider the probability of going against the tool, and thus, it might be clearer to have a required step prior to the configuration of your project.

How to integrate ANTLR with CMake?

I'm trying to make CMake generate source files with ANTLR without any success.
Here command I'm using to generate these files:
$ antlr grammar/MyGrammar.g -fo src/parser
My executable target is defined in PROJECT/src/CMakeLists.txt, instead of PROJECT/CMakeLists.txt.
If you're saying you want to execute this command from within PROJECT/src/CMakeLists.txt, then the following should work:
execute_process(COMMAND antlr grammar/MyGrammar.g -fo src/parser
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..)
Edit
Going by your comment, it looks like you want to invoke this every time you build your executable.
To tie the antlr invocation with your executable, you can use add_custom_command
add_custom_command(TARGET MyExe PRE_BUILD
COMMAND antlr grammar/MyGrammar.g -fo src/parser
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..)
This will only execute the antlr call if the MyExe target is out of date. If MyGrammar.g is changed, but MyExe doesn't need rebuilt, antlr doesn't run.
If you have multiple targets which depend on antlr being run, or you want to be able to invoke the antlr command any time, you could instead use add_custom_target. This adds the antlr command as a new psuedo-target. If you just build this target, all it does is invoke antlr. For each target which depends on it, use add_dependencies:
add_custom_target(Antlr
COMMAND antlr grammar/MyGrammar.g -fo src/parser
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..
SOURCES ../grammar/MyGrammar.g)
add_dependencies(MyExe Antlr)
add_dependencies(MyOtherExe Antlr)
As before, antlr will only be invoked if one of the dependent targets needs rebuilt, or if you explicitly build the new custom target "Antlr". (You don't need the SOURCES argument in the add_custom_target call, but this convenience feature adds MyGrammar.g to the target's files visible in IDEs like MSVC)
A little bit off topic but maybe it will be usefull for you.
Here you'll find CMake build file for the ANTLR C runtimme library.
Generated sources are same as any other sources generated from metadata.
You can use QT's UIC complier macro as an example:
MACRO (QT4_WRAP_UI outfiles )
QT4_EXTRACT_OPTIONS(ui_files ui_options ${ARGN})
FOREACH (it ${ui_files})
GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h)
ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
COMMAND ${QT_UIC_EXECUTABLE}
ARGS ${ui_options} -o ${outfile} ${infile}
MAIN_DEPENDENCY ${infile} VERBATIM)
SET(${outfiles} ${${outfiles}} ${outfile})
ENDFOREACH (it)
ENDMACRO (QT4_WRAP_UI)

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.