Boost logo

Boost :

Subject: Re: [boost] [boost.process] 0.6 Redesign
From: Klemens Morgenstern (klemens.morgenstern_at_[hidden])
Date: 2016-04-20 05:57:38

> It would be great if that interface, arguably nice, could boil down to a
> more template-less and simpler interface.
> Programs that tend to make an heavy use of external process launching
> usually need to setup how the process are launched in different stages. You
> might want to allow an iterative construction (and reuse) of the process
> launch options.
> For example:
> struct process_options
> {
> boost::optional<boost::filesystem::path> working_directory;
> boost::optional<std::map<std::string, std::string>> env;
> struct channel { ... };
> channel stdin;
> channel stdout;
> channel stderr;
> };
> This can be hidden through a nice interface, using some good defaults.

I think the way you can do it is too diverse to cover it with defaults,
and I actually don't know what good defaults would be. We already had
the discussion here about making everything async.

I.e. we would sacrifice a lot of flexibility. Of course you can
implement the example above very easily with the process library:

struct my_process
     //btw: that's in, but not yet documented
     filesystem::path working_dir = this_process::pwd();
     process::environment env = this_process::environment();

     process::pipe in;
     process::pipe out;
     filesystem::path err;
     process::child launch(const std::string & cmd)
        return process::execute(cmd, process::start_dir = working_dir,
                                process::std_in < in,
                                process::std_out > out,
                                process::std_err > err, env);

BUT you can also use a functional style if you want to:

auto in_setting = process::std_in < null;
auto c = execute("thingy", in_setting);

> But when you need to setup dynamically how a process should be launched,
> there is no other choice than aggregating the setup options until the
> launch point. The previous version of boost.process did not allow it[1],
> and forced me to come up with my own thing[2]. Also, do you plan to port
> back the type erasure PR[3] to your new version ?
> Cheers,
> [1]
> [2]
> [3]

No and no. So first of all, I don't really get it: you have a few
settings which will be aggregated like environment settings or args. Now
those can already be joint before the call of execute, i.e.

execute("thingy", args+="para1", args+="para2", env["PATH"]+="/path1",

//can be written as
environment env = this_process::environment();
env["PATH"] += "/path1";
env["PATH"] += "/path2";
vector<string> args = {"para1", "para2"};

execute("thingy", args, env);

The Problem with [2] and [3] is, that I now have the
initializer-sequence as a template parameter of the executor. I did this
so initializers can access the sequence, which was necessary for the
async stuff (i.e. so they can access the io_service). This renders any
virtualization impossible, because the handler-functions now have to be
Also: though not yet implemented, I'd like to have a few compile-time
checks, e.g. that you don't redirect a pipe twice etc. That would be
completely impossible with a initializer sequence built at runtime.

Now: since we have a finite amount of initializers, it would be possible
to implement some polymorphic sequence with boost.variant, but I still
fail to see why that must be determined at runtime. Keep in mind: you
would not determine the value of some initializer but which initializers
you set. Do you have an example where it has to be done at runtime? That
maybe helpful for me to understand the actual problem here. I really
don't like to use runtime-polymorphy when it can be done at compile-time.

Boost list run by bdawes at, gregod at, cpdaniel at, john at