I need to execute a command with add_custom_command a capture its stdout. The shell redirection to file > does not work and add_custom_command does not have any related options. How can I do it?
3 Answers
(Please note that I changed my answer after investigating the issue because of Florian's comment. More about the edit below)
The documentation of the execute_process clearly states that it does not use intermediate shell, so redirection operators do not work there.
But it's not true for the add_custom_command. Redirection should work there as expected. [EDIT] The reason sometimes it does not seem to work is some unfortunate combination of the CMake generator, the VERBATIM specifier and the (missing) space between > and the file name.
It turned out if you make sure there's a space between > and the file name it works with in most cases, even with VERBATIM:
add_custom_command(OUTPUT ${some-file}
COMMAND cmake --version > ${some-file}
VERBATIM # optional
)
A note on an alternative solution: previously I thought add_custom_command, just like execute_process doesn't use an intermediate shell so I suggested calling a CMake script which contains an execute_process command which runs the actual command, redirecting its output with the OUTPUT_FILE option.
If for some reason the solution above still fails for you, try the alternative solution using an ExecuteProcessWrapper.cmake
11 Comments
cmd.exe /c for custom commands on Windows. And the pipe commands are tested in CMake's custom command unit test.add_custom_target() may not work in some cases. From the other side, both add_custom_command() and add_custom_target() accept VERBATIM option, which has no sence until shell is involved. Contrary, execute_process() doesn't accept that option, and has explicit remark about redirection. So, where it the truth?VERBATIM doesn't prevent redirection. See, e.g., that answer: stackoverflow.com/a/31558761/3440745.> because I think the pipe command is handled in a special way. See BUG: Do not escape shell operators when generating command lines and CMAKE add_custom_command: How to use my raw commandsAs a fallback, one solution is to place the script you want to run in a separate .sh file and run that file. That way you do not have to think too hard about how to write such a script within cmake. It also makes it a lot easier to maintain and for other programmers to help with the script. This may be less important for a one liner, but it often starts with a single line and ends up being a 2,000 line script one day...
add_custom_command(
OUTPUT
${some-file}
COMMAND
${CMAKE_SOURCE_DIR}/my-script.sh ${some-file}
WORKING_DIRECTORY
${CMAKE_BINARY_DIR}
)
I also like to use the WORKING_DIRECTORY to be clear on where we start when executing the script.
P.S. the script needs to be executable:
chmod 755 my-script.sh
However, in your specific situation, you could also have considered executing the command and saving the results in a file like so:
execute_process(
COMMAND
cmake --version
OUTPUT_FILE
${some-file}
)
which is probably much cleaner.
The one thing to keep in mind in this case: the order of execution will be different. The execute_process() happens as the statement is parsed. The add_custom_command() is executed when its output is required, usually through an add_custom_target().