25

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 3

11

(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

Sign up to request clarification or add additional context in comments.

11 Comments

I think CMake's implementation of custom command may be platform dependent. Can you add an example where custom command is not using an intermediate shell? I've successfully used stdout/stderr redirection with Ninja and Visual Studio generators. Those generators do prefix cmd.exe /c for custom commands on Windows. And the pipe commands are tested in CMake's custom command unit test.
I found that thread on CMake developers' forum: cmake.3232098.n2.nabble.com/…. They write, that redirection in 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?
Hmm, For me VERBATIM doesn't prevent redirection. See, e.g., that answer: stackoverflow.com/a/31558761/3440745.
@Tsyvarev it seems that this redirection issue is very variable across platforms and generators. For me: mingw or window-cmd prompt + msvc generator the VERBATIM does break redirection.
The question is really where those quotes come from. Please try to add a space after > 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 commands
|
3
find_program(BASH bash HINTS /bin)
...
add_custom_command(
  OUTPUT
    ${some-file}
  COMMAND
    ${CMAKE_COMMAND} -E env ${BASH} -c "cmake --version > ${some-file} 2>&1"
  VERBATIM
)

Comments

0

As 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().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.