subprocess  0.1.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.

Todo add to cocoapods and perhaps others.

Examples

Simple examples

#include <subprocess.hpp>
// 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
CompletedProcess process = subprocess::run({"cat"},
RunBuilder().cin("hello world"));
// simplest send & capture
CompletedProcess process = subprocess::run({"cat"},
PopenBuilder().cin("hello world").cout(PipeOption::pipe));
std::cout << "captured: " << process.cout << '\n';
// capture stderr too.
CompletedProcess process = subprocess::run({"echo", "hello", "world"},
PopenBuilder().cerr(PipeOption::pipe)
.cout(PipeOption::pipe)
.check(true) // will throw CalledProcessError if returncode != 0.
);
std::cout << "cerr was: " << process.cerr;
// capture output. You can do this syntax if you have C++20
CompletedProcess process = subprocess::run({"echo", "hello", "world"}, {
.cout = PipeOption::pipe,
// make true to throw exception
.check = false
});
std::cout << "captured: " << process.cout << '\n';

Popen examples

These examples show using the library while the subprocess is still running.

// simplest example
// capture is enabled by default
Popen popen = subprocess::Popen({"echo", "hello", "world"}, RunBuilder().cout(PipeOption::pipe));
char buf[1024] = {0}; // initializes everything to 0
subprocess::pipe_read(popen.cout, buffer, 1024);
std::cout << buf;
// the destructor will call wait on your behalf.
popen.close();
// communicate with data
Popen popen = subprocess::Popen({"cat"}, RunBuilder().cin(PipeOption::pipe).cout(PipeOption::pipe));
/* 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([&]() {
pipe_write(popen.cin, "hello world\n", 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.cin_close();
});
char buf[1024] = {0}; // initializes everything to 0
subprocess::pipe_read(popen.cout, buffer, 1024);
std::cout << buf;
popen.close();
if (write_thread.joinable())
write_thread.join();

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
subprocess::CompletedProcess::cerr
std::string cerr
Definition: basic_types.hpp:158
subprocess::run
CompletedProcess run(Popen &popen, bool check=false)
subprocess::pipe_read
ssize_t pipe_read(PipeHandle, void *buffer, size_t size)
subprocess::Popen
Definition: ProcessBuilder.hpp:64
subprocess.hpp
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)