Where Is Boost.Process

Where is Boost.Process?

Julio M. Merino Vidal, who is, I beleive, the original author, wrote in this 2007 post that he did not have time to complete it.

Development was taken over by Boris Schaeling. This is the version that you found at http://www.highscore.de/boost/process/. According to this post, he is still actively developing it.

There is another version, by Ilya Sokolov.

For your other question:

Could you perhaps suggest other cross-platform libraries for managing simple starting of and interation with external processes?

you could look at this wiki page listing alternatives.

Depending on your needs, popen() could also do the job.

Boost process open process in new window (Windows)

ITNOA

As you can see in Boost::process hide console on windows, you can create new mode for creating process.

CreateProcessA function system call, Show yourself to how to create new process with new console, by helping creation flags: CREATE_NEW_CONSOLE (thanks to Using multiple console windows for output)

you can write code like below

struct new_window
: ::boost::process::detail::handler_base
{
// this function will be invoked at child process constructor before spawning process
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.creation_flags = ::boost::detail::winapi::CREATE_NEW_CONSOLE_;
}
};

and for using this, you can just write something like below

::boost::process::child ch("./worker.exe", new_window);

Boost Process 1.71 does not look in environment path anymore

I haven't checked whether the behaviour actually changed, but I know there's a way to explicitly allow Boost to search the path:

Keep in mind that searching the path can easily be a security issue because it can be compromised, or attackers can leverage knowledge of the path setting to intercept executables. This is why you'd expect search_path to be OFF by default (except for the system interface, which is traditionally insecure)

Live On Wandbox

#include <boost/process.hpp>

int main() {
namespace bp = boost::process;

bp::child c(
bp::search_path("date"),
std::vector<std::string> { "+%s" });
c.wait();
}

Is there a way to log the output of a process create via boost::process::spawn?

No that is not possible. It's implied in the documentation:

This function does not allow asynchronous operations, since it cannot
wait for the end of the process. It will fail to compile if a
reference to boost::asio::io_context is passed.

Maybe you can use child::detach instead?

#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <iostream>
namespace bp = boost::process;

int main()
{
boost::asio::io_service ios;

std::future<std::string> data;

bp::child c("/usr/bin/g++", "main.cpp", // set the input
bp::std_in.close(),
bp::std_out > bp::null, // so it can be written without anything
bp::std_err > data, ios);
c.detach();

ios.run(); // this will actually block until the compiler is finished

auto err = data.get();
std::cout << err;
}

Set the working directory when starting a process with boost


#include <boost/process/start_dir.hpp>

namespace bp = boost::process;

int result = bp::system("/usr/bin/g++", "main.cpp", bp::start_dir("/home/user"));

bp::child c(bp::search_path("g++"), "main.cpp", bp::start_dir("/home/user"));
c.wait();

See boost::process::start_dir and the complete Reference.

Args are program name, program args and other process properties from the Reference.

Cannot send and execute correct command through pipes using Boost library in C++

You are printing to cout as if the async operations happen immediately. That's not the case. The async operations only happen when the io service runs.

svc.run();

Is at the very end of your code. So no async_ operation ever completes (or even starts) before that.

Other problems:

  1. Your out async pipe is never used (not even connected). It's unclear to me how you intend to communicate with the child process that way.

  2. In fairness, you only every write to the child process, so maybe you're not at all interested in the output. (But then perhaps recv_buffer can be deleted just as well).

  3. Your buffers include the terminating NUL characters. (asio::buffer("uci\n") sends {'u','c','i','\n','\0'}). That's going to mess up the child processes's parsing.

  4. You do in.close() in response to every single async_write completion. This guarantees that subsequent writes never can happen, as you closed the pipe.

  5. Then when you send quit you fail to include the '\n' as well

  6. You are reading into a char[64] with operator>> which makes no sense at all. Maybe you are using c++20 (so width of 64 might be assumed) but you never set a width. Most likely you would want to read into a string instead.

  7. However, doing so cannot accept commands with whitespace (because std::ios::skipws is set by default). So, likely you wanted std::getline instead...

  8. The fact that you include a boatload of C headers makes me think you're porting some C code (badly). That's also exemplified by the strcmp use and others, e.g. no need to use ::stat

  9. Don't use using namespace std; (Why is "using namespace std;" considered bad practice?)

  10. Don't use global variables (errDetails)

  11. Don't use loops to wait for a time delay

  12. No need to manually print backtraces. Instead, use Boost:

    void abort_application(std::string const& errDetails) {
    std::cerr << errDetails << "\n";
    std::cerr << boost::stacktrace::stacktrace{} << std::endl;
    std::this_thread::sleep_for(3s);
    abort();
    }

Existing Stockfish Client: Playing Games

You're in luck: I have a written full demo using stockfish on this site: Interfacing with executable using boost in c++.

This example shows how to correctly await and parse expected replies from the child process(es).

You will note that I chose coroutines for the async version:

Just for completeness, I thought I'd try an asynchronous implementation. Using the default Asio callback style this could become unwieldy, so I thought to use Boost Coroutine for the stackful coroutines. That makes it so the implementation can be 99% similar to the synchronous version

Just for comparison, here's what your code should look like if you didn't use coroutines:

Fixing Up Your Code

Live On Coliru

#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/stacktrace/stacktrace.hpp>
#include <chrono>
#include <iomanip>
#include <iostream>

namespace bp = boost::process;
using boost::system::error_code;
using namespace std::literals;

static void abort_application(std::string const& errDetails) {
std::cerr << errDetails << "\n";
std::cerr << boost::stacktrace::stacktrace{} << std::endl;
std::this_thread::sleep_for(3s);
abort();
}

inline static bool stockfish_check_exists(std::string& name) {
return boost::filesystem::exists(name);
}

int main() {
boost::asio::io_service svc;
bp::async_pipe in{svc};
std::string proc = "/usr/games/stockfish";

if (!stockfish_check_exists(proc)) {
abort_application("Stockfish not found!");
}

auto on_exit = [](int code, std::error_code ec) {
std::cout << "Exited " << code << "(" << ec.message() << ")\n";
};

bp::child process(proc, bp::std_in < in, svc, bp::on_exit = on_exit);

std::function<void()> command_loop;
std::string command_buffer;
command_loop = [&] {
std::cout << "Enter your command: " << std::flush;
// boost::asio::streambuf recv_buffer;
if (getline(std::cin, command_buffer)) {
std::cout << "Your command is: " << command_buffer << std::endl;
command_buffer += '\n';

async_write( //
in, boost::asio::buffer(command_buffer),
[&](error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << " (" << ec.message() << ")" << std::endl;

if (command_buffer == "quit\n") {
std::cout << "Quiting......." << std::endl;
// in.close();
std::cout << "Engine quit!" << std::endl;
} else {
command_loop(); // loop
}
});
}
};

std::cout << "uci send" << std::endl;
async_write(
in, boost::asio::buffer("uci\n"sv),
[&](error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << "\n" << std::endl;
std::cout << "isready send" << std::endl;
async_write(in, boost::asio::buffer("isready\n"sv),
[&](error_code ec, size_t n) {
std::cout << "Write: " << n << std::endl;
command_loop(); // start command loop
});
});

svc.run(); // only here any of the operations start
}

Prints, e.g.

Sample Image

Or if Stockfish is in fact installed:

Sample Image



Related Topics



Leave a reply



Submit