1[def bp::system [funcref boost::process::system bp::system]] 2[def bp::async_system [funcref boost::process::async_system bp::async_system]] 3[def bp::spawn [funcref boost::process::spawn bp::spawn]] 4[def bp::child [classref boost::process::child bp::child]] 5[def bp::cmd [classref boost::process::cmd bp::cmd]] 6[def bp::group [classref boost::process::group bp::group]] 7[def bp::ipstream [classref boost::process::ipstream bp::ipstream]] 8[def bp::opstream [classref boost::process::opstream bp::opstream]] 9[def bp::pstream [classref boost::process::pstream bp::pstream]] 10[def bp::pipe [classref boost::process::pipe bp::pipe]] 11[def bp::async_pipe [classref boost::process::async_pipe bp::async_pipe]] 12[def bp::search_path [funcref boost::process::search_path bp::search_path]] 13[def boost_org [@www.boost.org "www.boost.org"]] 14[def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]] 15[def child_running [memberref boost::process::child::running running]] 16[def child_wait [memberref boost::process::child::wait wait]] 17[def child_wait_for [memberref boost::process::child::wait_for wait_for]] 18[def child_exit_code [memberref boost::process::child::exit_code exit_code]] 19[def group_wait_for [memberref boost::process::group::wait_for wait_for]] 20[def bp::on_exit [globalref boost::process::on_exit bp::on_exit]] 21[def bp::null [globalref boost::process::null bp::null]] 22[def child_terminate [memberref boost::process::child::terminate terminate]] 23[def group_terminate [memberref boost::process::group::terminate terminate]] 24[def group_wait [memberref boost::process::group::wait wait]] 25[def bp::std_in [globalref boost::process::std_in bp::std_in]] 26[def bp::std_out [globalref boost::process::std_out bp::std_out]] 27[def bp::std_err [globalref boost::process::std_err bp::std_err]] 28[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]] 29[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]] 30[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]] 31[def bp::environment [classref boost::process::basic_environment bp::environment]] 32[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]] 33[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]] 34[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]] 35[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]] 36 37[def __wait_for__ [memberref boost::process::child::wait_for wait_for]] 38[def __wait_until__ [memberref boost::process::child::wait_until wait_until]] 39[def __detach__ [memberref boost::process::child::detach detach]] 40 41[def __reference__ [link process.reference reference]] 42[def __concepts__ [link boost_process.concepts concepts]] 43 44[def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]] 45[def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]] 46[def bp::env [globalref boost::process::env bp::env]] 47 48[section:tutorial Tutorial] 49 50In this section we will go step by step through the different features of 51boost.process. For a full description see the __reference__ and the __concepts__ sections. 52 53[section Starting a process] 54 55We want to start a process, so let's start with a simple process. We will 56invoke the gcc compiler to compile a simple program. 57 58With the standard library this looks like this. 59 60``` 61int result = std::system("g++ main.cpp"); 62``` 63 64Which we can write exactly like this in boost.process. 65 66``` 67namespace bp = boost::process; //we will assume this for all further examples 68int result = bp::system("g++ main.cpp"); 69``` 70 71If a single string is given (or the explicit form bp::cmd), it will be interpreted as a command line. 72That will cause the execution function to search the `PATH` variable to find the executable. 73The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path), 74and the rest as arguments passed to said function. 75 76[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here].] 77 78So as a first step, we'll use the `exe-args` style. 79 80``` 81int result = bp::system("/usr/bin/g++", "main.cpp"); 82``` 83 84With that syntax we still have "g++" hard-coded, so let's assume we get the string 85from an external source as `boost::filesystem::path`, we can do this too. 86 87``` 88boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else. 89int result = bp::system(p, "main.cpp"); 90``` 91 92Now we might want to find the `g++` executable in the `PATH`-variable, as the `cmd` syntax would do. 93`Boost.process` provides a function to this end: bp::search_path. 94 95``` 96boost::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else. 97int result = bp::system(p, "main.cpp"); 98``` 99 100[note [funcref boost::process::search_path search_path] will search for any executable with that name. 101This also includes to add a file suffix on windows, such as `.exe` or `.bat`.] 102 103[endsect] 104 105[section:launch_mode Launch functions] 106 107Given that our example used the [funcref boost::process::system system] function, 108our program will wait until the child process is completed. This may be unwanted, 109especially since compiling can take a while. 110 111In order to avoid that, boost.process provides several ways to launch a process. 112Besides the already mentioned [funcref boost::process::system system] function and its 113asynchronous version [funcref boost::process::async_system async_system], 114we can also use the [funcref boost::process::spawn spawn] function or the 115[classref boost::process::child child] class. 116 117The [funcref boost::process::spawn spawn] function launches a process and 118immediately detaches it, so no handle will be returned and the process will be ignored. 119This is not what we need for compiling, but maybe we want to entertain the user, 120while compiling: 121 122``` 123bp::spawn(bp::search_path("chrome"), boost_org); 124``` 125 126Now for the more sensible approach for compiling: a non-blocking execution. 127To implement that, we directly call the constructor of [classref boost::process::child child]. 128 129``` 130bp::child c(bp::search_path("g++"), "main.cpp"); 131 132while (c.child_running()) 133 do_some_stuff(); 134 135c.child_wait(); //wait for the process to exit 136int result = c.child_exit_code(); 137``` 138 139So we launch the process, by calling the child constructor. Then we check and do other 140things while the process is running and afterwards get the exit code. The call 141to child_wait is necessary, to obtain it and tell the operating system, that no 142one is waiting for the process anymore. 143 144[note You can also wait for a time span or until a time point with __wait_for__ and __wait_until__.] 145 146[warning If you don't call wait on a child object, it will be terminated on destruction. 147This can be avoided by calling __detach__ beforehand] 148 149[endsect] 150[section:error_handling Error] 151 152Until now, we have assumed that everything works out, but it is not impossible, 153that "g++" is not present. That will cause the launch of the process to fail. 154The default behaviour of all functions is to throw a 155[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure. 156As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] 157will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code. 158 159``` 160std::error_code ec; 161bp::system("g++ main.cpp", ec); 162``` 163[endsect] 164[section:io Synchronous I/O] 165 166In the examples given above, we have only started a program, but did not consider the output. 167The default depends on the system, but usually this will just write it to the same output as the launching process. 168If this shall be guaranteed, the streams can be explicitly forwarded like this. 169 170``` 171 bp::system("g++ main.cpp", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin); 172``` 173 174Now for the first example, we might want to just ignore the output, which can be done by redirecting it to the null-device. 175This can be achieved this way: 176 177``` 178bp::system("g++ main.cpp", bp::std_out > bp::null); 179``` 180 181Alternatively we can also easily redirect the output to a file: 182 183``` 184bp::system("g++ main.cpp", bp::std_out > "gcc_out.log"); 185``` 186 187Now, let's take a more visual example for reading data. 188[@http://pubs.opengroup.org/onlinepubs/009696699/utilities/nm.html nm] is a tool on posix, 189which reads the outline, i.e. a list of all entry points, of a binary. 190Every entry point will be put into a single line, and we will use a pipe to read it. 191At the end an empty line is appended, which we use as the indication to stop reading. 192Boost.process provides the pipestream ([classref boost::process::ipstream ipstream], 193[classref boost::process::opstream opstream], [classref boost::process::pstream pstream]) to 194wrap around the [classref boost::process::pipe pipe] and provide an implementation of the 195[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream], 196[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and 197[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface. 198 199``` 200std::vector<std::string> read_outline(std::string & file) 201{ 202 bp::ipstream is; //reading pipe-stream 203 bp::child c(bp::search_path("nm"), file, bp::std_out > is); 204 205 std::vector<std::string> data; 206 std::string line; 207 208 while (c.child_running() && std::getline(is, line) && !line.empty()) 209 data.push_back(line); 210 211 c.child_wait(); 212 213 return data; 214} 215``` 216 217What this does is redirect the `stdout` of the process into a pipe and we read this 218synchronously. 219 220[note You can do the same thing with [globalref boost::process::std_err std_err].] 221 222Now we get the name from `nm` and we might want to demangle it, so we use input and output. 223`nm` has a demangle option, but for the sake of the example, we'll use 224[@https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html c++filt] for this. 225 226``` 227bp::opstream in; 228bp::ipstream out; 229 230bp::child c("c++filt", std_out > out, std_in < in); 231 232in << "_ZN5boost7process8tutorialE" << endl; 233std::string value; 234out >> value; 235 236c.child_terminate(); 237``` 238 239Now you might want to forward output from one process to another processes input. 240 241``` 242std::vector<std::string> read_demangled_outline(const std::string & file) 243{ 244 bp::pipe p; 245 bp::ipstream is; 246 247 std::vector<std::string> outline; 248 249 //we just use the same pipe, so the output of nm is directly passed as input to c++filt 250 bp::child nm(bp::search_path("nm"), file, bp::std_out > p); 251 bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is); 252 253 std::string line; 254 while (filt.running() && std::getline(is, line)) //when nm finished the pipe closes and c++filt exits 255 outline.push_back(line); 256 257 nm.child_wait(); 258 filt.wait(); 259} 260 261``` 262 263This forwards the data from `nm` to `c++filt` without your process needing to do anything. 264 265[endsect] 266[section:async_io Asynchronous I/O] 267 268Boost.process allows the usage of boost.asio to implement asynchronous I/O. 269If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend), 270you can use [classref boost::process::async_pipe async_pipe] which is implemented 271as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above. 272 273Now we get back to our compiling example. For `nm` we might analyze the output line by line, 274but the compiler output will just be put into one large buffer. 275 276With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like. 277 278``` 279io_service ios; 280std::vector<char> buf(4096); 281 282bp::async_pipe ap(ios); 283 284bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > ap); 285 286asio_async_read(ap, asio_buffer(buf), 287 [](const boost::system::error_code &ec, std::size_t size){}); 288 289ios.run(); 290int result = c.exit_code(); 291``` 292 293To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly, 294provided we also pass a reference to an io_service. 295 296``` 297io_service ios; 298std::vector<char> buf(4096); 299 300bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios); 301 302ios.run(); 303int result = c.exit_code(); 304``` 305 306[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of 307[memberref boost::process::child::wait wait] is needed.] 308 309To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations 310(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system. 311 312Now we will revisit our first example and read the compiler output asynchronously: 313 314``` 315boost::asio::io_service ios; 316 317std::future<std::string> data; 318 319child c("g++", "main.cpp", //set the input 320 bp::std_in.close(), 321 bp::std_out > bp::null, //so it can be written without anything 322 bp::std_err > data, 323 ios); 324 325 326ios.run(); //this will actually block until the compiler is finished 327 328auto err = data.get(); 329``` 330 331[endsect] 332[section:group Groups] 333 334When launching several processes, they can be grouped together. 335This will also apply for a child process, that launches other processes, 336if they do not modify the group membership. E.g. if you call `make` which 337launches other processes and call terminate on it, 338it will not terminate all the child processes of the child unless you use a group. 339 340The two main reasons to use groups are: 341 342# Being able to terminate child processes of the child process 343# Grouping several processes into one, just so they can be terminated at once 344 345If we have a program like `make`, which does launch its own child processes, 346a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc` 347and use the following code, the `gcc` process will still run afterwards: 348 349``` 350bp::child c("make"); 351if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds 352 c.child_terminate(); //then terminate 353``` 354 355So in order to also terminate `gcc` we can use a group. 356 357``` 358bp::group g; 359bp::child c("make", g); 360if (!g.group_wait_for(std::chrono::seconds(10)) 361 g.group_terminate(); 362 363c.child_wait(); //to avoid a zombie process & get the exit code 364``` 365 366Now given the example, we still call child_wait to avoid a zombie process. 367An easier solution for that might be to use [funcref boost::process::spawn spawn]. 368 369 370To put two processes into one group, the following code suffices. Spawn already 371launches a detached process (i.e. without a child-handle), but they can be grouped, 372to that in the case of a problem, RAII is still a given. 373 374``` 375void f() 376{ 377 bp::group g; 378 bp::spawn("foo", g); 379 bp::spawn("bar", g); 380 381 do_something(); 382 383 g.group_wait(); 384}; 385``` 386 387In the example, it will wait for both processes at the end of the function unless 388an exception occurs. I.e. if an exception is thrown, the group will be terminated. 389 390 391Please see the [headerref boost/process/group.hpp reference] for more information. 392 393[endsect] 394[section:env Environment] 395 396This library provides access to the environment of the current process and allows 397setting it for the child process. 398 399``` 400//get a handle to the current environment 401auto env = boost::this_process::environment(); 402//add a variable to the current environment 403env["VALUE_1"] = "foo"; 404 405//copy it into an environment separate to the one of this process 406bp::environment env_ = env; 407//append two values to a variable in the new env 408env_["VALUE_2"] += {"bar1", "bar2"}; 409 410//launch a process with `env_` 411bp::system("stuff", env_); 412``` 413 414A more convenient way to modify the environment for the child is the 415[globalref boost::process::env env] property, which can be used in the example as following: 416 417``` 418bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"}); 419 420``` 421 422Please see the [headerref boost/process/environment.hpp reference] for more information. 423 424[endsect] 425[endsect] 426