12

CMake's execute_process command seems to only let you, well, execute a process - not an arbitrary line you could feed a command shell. The thing is, I want to use pipes, file descriptor redirection, etc. - and that does not seem to be possible. The alternative would be very painful for me (I think)...

What should I do?

PS - CMake 2.8 and 3.x answer(s) are interesting.

einpoklum
  • 118,144
  • 57
  • 340
  • 684

3 Answers3

27

You can execute any shell script, using your shell's support for taking in a script within a string argument.

Example:

execute_process(
    COMMAND bash "-c" "echo -n hello | sed 's/hello/world/;'" 
    OUTPUT_VARIABLE FOO
)

will result in FOO containing world.

Of course, you would need to escape quotes and backslashes with care. Also remember that running bash would only work on platforms which have bash - i.e. it won't work on Windows.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
10
  1. execute_process command seems to only let you, well, execute a process - not an arbitrary line you could feed a command shell.

Yes, exactly this is written in documentation for that command:

All arguments are passed VERBATIM to the child process. No intermediate shell is used, so shell operators such as > are treated as normal arguments.

  1. I want to use pipes

Different COMMAND within same execute_process invocation are actually piped:

Runs the given sequence of one or more commands with the standard output of each process piped to the standard input of the next.

  1. file descriptor redirection, etc. - and that does not seem to be possible.

For complex things just prepare separate shell script and run it using execute_process. You can pass variables from CMake to this script using its parameters, or with prelimiary configure_file.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • I can't prepare a distinct shell script on a target machine which is not the development machine - or, do you suggest I bundle this shell script as well? An extra file just for that? – einpoklum Feb 29 '16 at 08:03
  • I mean additional shell script in *sources*. If you perform build not on the target machine, you needn't to put this script there. – Tsyvarev Feb 29 '16 at 08:07
  • There is `INPUT_FILE` for file descriptor, you can put `/dev/null` as a file name for example. – Sandburg Feb 08 '22 at 13:24
1

I needed to pipe two commands one after the other and actually learned that each COMMAND of the execute_process is piped already. So at least that much is resolved by simply adding commands one after the other:

execute_process(
    COMMAND echo "Hello"
    COMMAND sed -e 's/H/h/'
    OUTPUT_VARIABLE GREETINGS
    OUTPUT_STRIP_TRAILING_WHITESPACE)

Now the variable GREETINGS is set to hello.

If you indeed need a lot of file redirection (as you stated), you probably want to write an external script and then execute that script from CMakeLists.txt. It's really difficult to get all the escaping right in CMake.

If you can simplify your scripts to one command generating a file, then another handling that file, etc. then you can always use the INPUT_FILE and OUTPUT_FILE options. Or pass a filename to your command for the input.

It's often much cleaner to handle one file at a time. Although I understand that some commands may need multiple sources and destinations.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156