• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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