c++boostsfinaeboost-process

custom initializer hook not applied in boost.process


My sample code is the following. This uses boost.process v2

#include <boost/filesystem.hpp>
#include <boost/process/v2.hpp>
#include <boost/asio.hpp>

namespace sys = boost::system;
namespace v2 = boost::process::v2;
namespace fs = boost::filesystem;
namespace asio = boost::asio;

using launcher_type = v2::posix::default_launcher;
using pathname_type = fs::path;
using args_type = char* const*;

const fs::path null_cmd = v2::environment::find_executable("true");
std::initializer_list<std::string> args{};

size_t last_local_event = 0;  

struct hooks {
  sys::error_code on_setup(launcher_type &, const pathname_type &, const args_type &) {
    last_local_event = 1;
    return sys::error_code{};
  }
};


auto main() -> int {
    asio::io_context context;
    sys::error_code ec{};
    launcher_type launch{};
    hooks init{};

    v2::process p = launch(
      context, ec,
      null_cmd,
      args,
      std::move(init)
    );

    context.run();
    p.wait(ec);
    assert(last_local_event == 1);
    
}

The custom on_setup callback in my hooks instance is not being applied under the boost process launcher instance, a v2::posix::default_launcher.

It looks like the function signature for my on_setup call should match that for an on_setup callback under a boost process Linux launcher of this launcher type.

After taking a look at the boost.process source code, I believe that my on_setup call should be substituted and called during launcher on_setup, as it was provided via the initializer init when the process launcher object was called.

I believe that the function signature for my on_setup function matches that expected for on_setup with a custom initializer in boost process on Linux. The function signatures appear to match, and yet my custom initializer is not being used for the process. The assert call fails in my example code. The value of last_local_event was not changed by my custom on_setup function.

Is there something I'm missing here, such as in how to apply the template substitutions for a custom boost.process on_setup hook?

Could there be any advice on how to diagnose why my hooks::on_setup is not being called from the provided init?

I've tested this under compilation with clang20 using C++20 and with GCC 13.2.0 using C++2b(GNU)

Under local build, maybe I've been missing some compiler notices due to including boost with -isystem. The compiler might provide some info about why the substitution is not working out there?

Update

The substitution may have been failing on the args_type as defined

using args_type = char* const*;

as used within the method

sys::error_code on_setup(launcher_type &, const pathname_type &, const args_type &)

When using similar code (adapted after a unit test in boost process) but when specializing on_setup as so, then the launcher-initializer's on_setup method is reached as expected:

struct hooks {
  // [sic]

  template <typename L>
  sys::error_code on_setup(L&, const pathname_type&, const char*const*&) {
    event_flag = true;
    return sys::error_code{};
  }
};

This also works, though it may be a little less portable, when defining the on_setup hook without a template for the launcher arg:

struct hooks {
  // [sic]

  sys::error_code on_setup(launcher_type&, const pathname_type&, const char*const*&) {
    event_flag = true;
    return sys::error_code{};
  }
};

The args type for boost process v2 on posix-like platforms is char* const*. This differs to windows platforms, which would use std::wstring as the args type.

Why does the template substitution fail when using my args_type specialization there? This was tested with both GCC and clang. It seems const args_type& in the method declaration is handled as a different type than const char*const*&?

I understand that I can probably work around this by using a macro defined on each platform, or folding the initial const into the args_type definition, to keep it platform-generic in some way, e.g

using const_args_type = const char* const*;

Can anyone help to elucidate why the template substitution fails when on_setup is defined with const args_type& there? Could it be anything specific to C-like array types?


Solution

  • args_type is not a pointer-to-pointer to CONST char.

    using args_type = char* const*;
    

    Should be

    using args_type = char const* const*;
    

    That fixes it

    Live On Coliru

    #include <boost/asio.hpp>
    #include <boost/filesystem.hpp>
    #include <boost/process/v2.hpp>
    
    namespace sys  = boost::system;
    namespace bp   = boost::process::v2;
    namespace fs   = boost::filesystem;
    namespace asio = boost::asio;
    
    using launcher_type = bp::posix::default_launcher;
    using pathname_type = fs::path;
    
    fs::path const                     null_cmd = bp::environment::find_executable("true");
    std::initializer_list<std::string> args{};
    
    size_t last_local_event = 0;
    
    struct hooks {
        using args_type = char const* const*;
    
        sys::error_code on_setup(launcher_type&, pathname_type const&, args_type const&) const {
            last_local_event = 1;
            return {};
        }
    };
    
    int main() {
        asio::io_context context;
        sys::error_code  ec{};
        launcher_type    launch{};
        hooks            init{};
    
        bp::process p = launch(context, ec, null_cmd, args, std::move(init));
    
        context.run();
        p.wait(ec);
        assert(last_local_event == 1);
    }