subprocess  0.2.0
Modern subprocess library for c++
subprocess

cross platform subprocess library for c++ similar to design of python subprocess. See subprocess documentation for further documentation.

supports

  • very python like style of subprocess. With very nice syntax for c++20.
  • Connect output of process A to input of process B. However not pretty API for this.

Shakey elements

  • The os error level exceptions is still changing. I'm thinking of having an OSError subclass to abstract the OS differences.

requirements

  • c++17
  • linked with support for threading, filesystem

Integration

Adhoc

  1. copy files in src/cpp to your project.
  2. add the top folder as include.
  3. make sure cpp files are compiled.
  4. add #include <subprocess.hpp> to start using in source files.

<a href="https://bitbucket.org/benman/teaport">Teaport</a>

add this to your dependencies:

"subprocess": "0.1.+"

Todo add to cocoapods and perhaps others.

Examples

#include <subprocess.hpp>
#include <thread>
#include <cstring>
void simple() {
// quick echo it, doesn't capture
subprocess::run({"echo", "hello", "world"});
// simplest capture output.
CompletedProcess process = subprocess::run({"echo", "hello", "world"},
RunBuilder().cout(PipeOption::pipe));
// simplest sending data example
process = subprocess::run({"cat"},
RunBuilder().cin("hello world\n"));
// simplest send & capture
process = subprocess::run({"cat"},
RunBuilder().cin("hello world").cout(PipeOption::pipe));
std::cout << "captured: " << process.cout << '\n';
// capture stderr too.
process = subprocess::run({"echo", "hello", "world"},
RunBuilder().cerr(PipeOption::pipe)
.cout(PipeOption::pipe)
.check(true) // will throw CalledProcessError if returncode != 0.
);
// there is no cerr so it will be empty
std::cout << "cerr was: " << process.cerr << "\n";
#if __cplusplus >= 202002L
// capture output. You can do this syntax if you have C++20
process = subprocess::run({"echo", "hello", "world"}, {
.cout = PipeOption::pipe,
// make true to throw exception
.check = false
});
std::cout << "captured: " << process.cout << '\n';
#endif
}
void popen_examples() {
// simplest example
// capture is enabled by default
Popen popen = subprocess::RunBuilder({"echo", "hello", "world"})
.cout(PipeOption::pipe).popen();
char buf[1024] = {0}; // initializes everything to 0
subprocess::pipe_read(popen.cout, buf, 1024);
std::cout << buf;
// the destructor will call wait on your behalf.
popen.close();
// communicate with data
popen = subprocess::RunBuilder({"cat"}).cin(PipeOption::pipe)
.cout(PipeOption::pipe).popen();
/* if we write more data than the buffer, we would dead lock if the subprocess
is deadlocked trying to write. So we spin a new thread for writing. When
you provide buffers for cin, internally the library spins it's own thread.
*/
std::thread write_thread([&]() {
subprocess::pipe_write(popen.cin, "hello world\n", std::strlen("hello world\n"));
// no more data to send. If we don't close we may run into a deadlock as
// we are looking to read for more.
popen.close_cin();
});
for (auto& c : buf)
c = 0;
subprocess::pipe_read(popen.cout, buf, 1024);
std::cout << buf;
popen.close();
if (write_thread.joinable())
write_thread.join();
}
int main(int argc, char** argv) {
std::cout << "running basic examples\n";
simple();
std::cout << "running popen_examples\n";
popen_examples();
return 0;
}

Design

stdin, stdout, stderr are macros, so it's not possible to use those variable names. Instead c++ variable names is used cin, cout, cerr where the std* would have been respectively.

PopenBuilder was a bad idea. Removed, now only RunBuilder remains which is enough. Have both is too confusing.

current progress

All tests are passing on macos, linux. Most tests pass on cross compiling on linux for windows using mingw. The library is almost feature complete.

must to be implemented

  • documentation
  • bugs, there is lots of them to be discovered.
  • main structure is set in place and help is welcome.

not good

  • due to types c++ is more wordy

Changelog

0.2.0

  • omg setting check=true is fixed. What a typo
subprocess::CompletedProcess::cerr
std::string cerr
Definition: basic_types.hpp:158
subprocess::RunBuilder::cout
RunBuilder & cout(const PipeVar &cout)
Definition: ProcessBuilder.hpp:242
subprocess::run
CompletedProcess run(Popen &popen, bool check=false)
subprocess::RunBuilder
Definition: ProcessBuilder.hpp:228
subprocess::PipeOption
PipeOption
Definition: basic_types.hpp:87
subprocess::pipe_read
ssize_t pipe_read(PipeHandle, void *buffer, size_t size)
subprocess::Popen
Definition: ProcessBuilder.hpp:67
subprocess.hpp
subprocess::CompletedProcess
Definition: basic_types.hpp:148
subprocess::PipeOption::cout
@ cout
Redirects to stdout.
subprocess::RunBuilder::popen
Popen popen()
Definition: ProcessBuilder.hpp:264
subprocess::CompletedProcess::cout
std::string cout
Definition: basic_types.hpp:156
subprocess::pipe_write
ssize_t pipe_write(PipeHandle, const void *buffer, size_t size)