Boost logo

Boost :

Subject: Re: [boost] [boost.process] 0.6 Redesign
From: Raphaël Londeix (raphael.londeix_at_[hidden])
Date: 2016-04-20 11:50:28


Hi,

Of course you can implement the example above very easily with the process
> library:
>

Thanks, that's almost what I need, but it is not practical for stream
initializations:

    enum stream { std_in, std_out, std_err, dev_null };

    struct options
    {
        // stderr redirection
        boost::variant<
            boost::filesystem::path,
            boost::process::pipe,
            stream> err;

        ...
    };

How can I spawn a process, so that it will redirect stderr alternatively to
a path, to a pipe, to stdout, or to /dev/null ? If I'm right, I will need
to write explicitly 4 different calls to process::execute(). And it gets
worse if we want to have the same flexibility for the stdin and stdout ...

All in all, I'm not suggesting that you add support for boost::variant, but
instead suggesting that boost.process could have one low-level generic way
to spawn a process. As mentioned earlier, the Python subprocess library is
great, its subprocess.Popen[1] constructor provides a way to do so.

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);
>

I'm not suggesting that you should remove the nice API, more that it could
be optional.

> you have a few settings which will be aggregated like environment

settings or args.
>

Yes, sorry, I didn't spot that for the env and args. However the argument
remains for the streams initialization.

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).

AFAIK, this was also the case in the 0.5 version

> This renders any virtualization impossible, because the handler-functions
> now have to be
> tempalted.
>

Yes.

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

I believe that those checks are incredibly cheap compared to a fork or a
CreateProcess(), why not also do some runtime checks ?

> 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

I completely agree that compile-time checks are nice, but having a lower
level non fully typesafe API cannot hurt.

An example where it is necessary to do the initialization at runtime could
be a simple launcher that can exercise every combination of options that
boost.process allow, like:

    Usage: boost-process-launcher [OPTIONS] -- COMMAND [ARG]...

That you could use like that

    $ echo test | boost-process-launcher --stdout=STDERR
--stderr=./somefile.txt --E ENVVAR=1 --no-inherit-env -- grep test

Cheers,

[1] https://docs.python.org/3.6/library/subprocess.html#popen-constructor


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk