Replace Boost.Process for the Wine plugin host

Now we use our own library for this, so we can drop the Boost.Filesystem
dependency after a couple more changes.
This commit is contained in:
Robbert van der Helm
2022-04-14 18:45:47 +02:00
parent f79b0fd146
commit 037d6ad5aa
6 changed files with 148 additions and 413 deletions
-216
View File
@@ -27,224 +27,8 @@
#include <asio/read_until.hpp>
#include <asio/streambuf.hpp>
// FIXME: Remove when we get rid of the patched_async_pipe
#include <asio/io_context.hpp>
#include <asio/posix/stream_descriptor.hpp>
#include <asio/post.hpp>
// FIXME: Get rid of Boost.Process and all of the wrangling below
#include <boost/process/async_pipe.hpp>
#include <boost/process/detail/posix/pipe_out.hpp>
#include <boost/process/posix.hpp>
#include "../utils.h"
/**
* Boost 1.72 was released with a known breaking bug caused by a missing
* typedef: https://github.com/boostorg/process/issues/116.
*
* Luckily this is easy to fix since it's not really possible to downgrade Boost
* as it would break other applications.
*
* Check if this is still needed for other distros after Arch starts packaging
* Boost 1.73.
*
* FIXME: This has been adopted to work with standalone Asio, we should replace
* this when we replace Boost.Process
*/
class patched_async_pipe {
::asio::posix::stream_descriptor _source;
::asio::posix::stream_descriptor _sink;
public:
typedef int native_handle_type;
typedef ::asio::posix::stream_descriptor handle_type;
typedef typename handle_type::executor_type executor_type;
executor_type get_executor() { return _source.get_executor(); }
inline patched_async_pipe(asio::io_context& ios)
: patched_async_pipe(ios, ios) {}
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
inline patched_async_pipe(asio::io_context& ios_source,
asio::io_context& ios_sink)
: _source(ios_source), _sink(ios_sink) {
int fds[2];
if (pipe(fds) == -1)
boost::process::detail::throw_last_error("pipe(2) failed");
_source.assign(fds[0]);
_sink.assign(fds[1]);
};
inline patched_async_pipe(const patched_async_pipe& lhs);
patched_async_pipe(patched_async_pipe&& lhs)
: _source(std::move(lhs._source)), _sink(std::move(lhs._sink)) {
lhs._source =
::asio::posix::stream_descriptor{lhs._source.get_executor()};
lhs._sink = ::asio::posix::stream_descriptor{lhs._sink.get_executor()};
}
template <class CharT, class Traits = std::char_traits<CharT>>
explicit patched_async_pipe(
::asio::io_context& ios_source,
::asio::io_context& ios_sink,
const boost::process::detail::posix::basic_pipe<CharT, Traits>& p)
: _source(ios_source, p.native_source()),
_sink(ios_sink, p.native_sink()) {}
template <class CharT, class Traits = std::char_traits<CharT>>
explicit patched_async_pipe(
asio::io_context& ios,
const boost::process::detail::posix::basic_pipe<CharT, Traits>& p)
: patched_async_pipe(ios, ios, p) {}
template <class CharT, class Traits = std::char_traits<CharT>>
inline patched_async_pipe& operator=(
const boost::process::detail::posix::basic_pipe<CharT, Traits>& p);
inline patched_async_pipe& operator=(const patched_async_pipe& rhs);
inline patched_async_pipe& operator=(patched_async_pipe&& lhs);
~patched_async_pipe() {
std::error_code ec;
close(ec);
}
template <class CharT, class Traits = std::char_traits<CharT>>
inline explicit
operator boost::process::detail::posix::basic_pipe<CharT, Traits>() const;
void cancel() {
if (_sink.is_open())
_sink.cancel();
if (_source.is_open())
_source.cancel();
}
void close() {
if (_sink.is_open())
_sink.close();
if (_source.is_open())
_source.close();
}
void close(std::error_code& ec) {
if (_sink.is_open())
_sink.close(ec);
if (_source.is_open())
_source.close(ec);
}
bool is_open() const { return _sink.is_open() || _source.is_open(); }
void async_close() {
if (_sink.is_open())
asio::post(_sink.get_executor(), [this] { _sink.close(); });
if (_source.is_open())
asio::post(_source.get_executor(), [this] { _source.close(); });
}
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers) {
return _source.read_some(buffers);
}
template <typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence& buffers) {
return _sink.write_some(buffers);
}
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
std::error_code& ec) noexcept {
return _source.read_some(buffers, ec);
}
template <typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence& buffers,
std::error_code& ec) noexcept {
return _sink.write_some(buffers, ec);
}
native_handle_type native_source() const {
return const_cast<asio::posix::stream_descriptor&>(_source)
.native_handle();
}
native_handle_type native_sink() const {
return const_cast<asio::posix::stream_descriptor&>(_sink)
.native_handle();
}
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler, void(std::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler) {
return _source.async_read_some(buffers,
std::forward<ReadHandler>(handler));
}
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler, void(std::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler) {
return _sink.async_write_some(buffers,
std::forward<WriteHandler>(handler));
}
const handle_type& sink() const& { return _sink; }
const handle_type& source() const& { return _source; }
handle_type&& sink() && { return std::move(_sink); }
handle_type&& source() && { return std::move(_source); }
handle_type source(::asio::io_context& ios) && {
::asio::posix::stream_descriptor stolen(ios, _source.release());
return stolen;
}
handle_type sink(::asio::io_context& ios) && {
::asio::posix::stream_descriptor stolen(ios, _sink.release());
return stolen;
}
handle_type source(::asio::io_context& ios) const& {
auto source_in = const_cast<::asio::posix::stream_descriptor&>(_source)
.native_handle();
return ::asio::posix::stream_descriptor(ios, ::dup(source_in));
}
handle_type sink(::asio::io_context& ios) const& {
auto sink_in = const_cast<::asio::posix::stream_descriptor&>(_sink)
.native_handle();
return ::asio::posix::stream_descriptor(ios, ::dup(sink_in));
}
};
// Even more of a mess, we can't use the nice `bp::std_out = ...`/`bp::std_err =
// ...` syntax anymore.
template <int p1, int p2>
struct patched_async_pipe_out
: public boost::process::detail::posix::pipe_out<p1, p2> {
patched_async_pipe& pipe;
template <typename AsyncPipe>
patched_async_pipe_out(AsyncPipe& p)
: boost::process::detail::posix::pipe_out<p1, p2>(p.native_sink(),
p.native_source()),
pipe(p) {}
template <typename Pipe, typename Executor>
static void close(Pipe& pipe, Executor&) {
std::error_code ec;
std::move(pipe).sink().close(ec);
}
template <typename Executor>
void on_error(Executor& exec, const std::error_code&) {
close(pipe, exec);
}
template <typename Executor>
void on_success(Executor& exec) {
close(pipe, exec);
}
};
/**
* Super basic logging facility meant for debugging malfunctioning VST
* plugins. This is also used to redirect the output of the Wine process
+91 -45
View File
@@ -17,24 +17,72 @@
#include "host-process.h"
#include <asio/read_until.hpp>
#include <boost/process/env.hpp>
#include <boost/process/start_dir.hpp>
#include "../common/utils.h"
namespace bp = boost::process;
namespace fs = ghc::filesystem;
HostProcess::HostProcess(asio::io_context& io_context,
Logger& logger,
const Configuration& config,
Sockets& sockets)
: stdout_pipe_(io_context),
stderr_pipe_(io_context),
config_(config),
sockets_(sockets),
logger_(logger) {
// See the comment above the `on_exec_setup` in `launch_host()`
HostProcess::HostProcess(asio::io_context& io_context, Sockets& sockets)
: sockets_(sockets), stdout_pipe_(io_context), stderr_pipe_(io_context) {}
HostProcess::~HostProcess() noexcept {}
Process::Handle HostProcess::launch_host(
const ghc::filesystem::path& host_path,
std::initializer_list<std::string> args,
Logger& logger,
const Configuration& config,
const PluginInfo& plugin_info) {
#ifdef WITH_WINEDBG
// This is set up for KDE Plasma. Other desktop environments and window
// managers require some slight modifications to spawn a detached terminal
// emulator. Alternatively, you can spawn `winedbg` with the `--no-start`
// option to launch a gdb server and then connect to it from another
// terminal.
Process child("kstart5");
child.arg("konsole").arg("--").arg("-e").arg("winedbg").arg("--gdb");
#ifdef WINEDBG_LEGACY_ARGUMENT_QUOTING
// Note the double quoting here. Old versions of winedbg didn't
// respect `argv` and instead expected a pre-quoted Win32 command
// line as its arguments.
child.arg("\"" + host_path.string() + ".so\""),
#else
child.arg(host_path.string() + ".so");
#endif // WINEDBG_LEGACY_ARGUMENT_QUOTING
#else
Process child(host_path);
#endif // WITH_WINEDBG
// What's up with this indentation
for (const auto& arg : args) {
child.arg(arg);
}
child.environment(plugin_info.create_host_env());
Process::Handle child_handle = std::visit(
overload{
[](Process::Handle handle) -> Process::Handle { return handle; },
[&host_path](const Process::CommandNotFound&) -> Process::Handle {
throw std::runtime_error("Could not launch '" +
host_path.string() +
"', command not found");
},
[](const std::error_code& err) -> Process::Handle {
throw std::runtime_error("Error spawning Wine process: " +
err.message());
},
},
// HACK: If the `disable_pipes` option is enabled, then we'll redirect
// the plugin's output to a file instead of using pipes to blend
// it in with the rest of yabridge's output. This is for some
// reason necessary for ujam's plugins and all other plugins made
// with Gorilla Engine to function. Otherwise they'll print a
// nondescriptive `JS_EXEC_FAILED` error message.
config.disable_pipes
? child.spawn_child_redirected(*config.disable_pipes)
: child.spawn_child_piped(stdout_pipe_, stderr_pipe_));
// See the above comment
if (config.disable_pipes) {
logger.log("");
logger.log("WARNING: All Wine output will be written to");
@@ -49,9 +97,9 @@ HostProcess::HostProcess(asio::io_context& io_context,
logger.async_log_pipe_lines(stderr_pipe_, stderr_buffer_,
"[Wine STDERR] ");
}
}
HostProcess::~HostProcess() noexcept {}
return child_handle;
}
IndividualHost::IndividualHost(asio::io_context& io_context,
Logger& logger,
@@ -59,28 +107,32 @@ IndividualHost::IndividualHost(asio::io_context& io_context,
Sockets& sockets,
const PluginInfo& plugin_info,
const HostRequest& host_request)
: HostProcess(io_context, logger, config, sockets),
: HostProcess(io_context, sockets),
plugin_info_(plugin_info),
host_path_(find_vst_host(plugin_info.native_library_path_,
plugin_info.plugin_arch_,
false)),
host_(
launch_host(host_path_,
plugin_type_to_string(host_request.plugin_type),
handle_(launch_host(
host_path_,
{
plugin_type_to_string(host_request.plugin_type),
#if defined(WITH_WINEDBG) && defined(WINEDBG_LEGACY_ARGUMENT_QUOTING)
// Old versions of winedbg flattened all command line
// arguments to a single space separated Win32 command
// line, so we had to do our own quoting
"\"" + plugin_info.windows_plugin_path + "\"",
// Old versions of winedbg flattened all command line
// arguments to a single space separated Win32 command line,
// so we had to do our own quoting
"\"" + plugin_info.windows_plugin_path + "\"",
#else
host_request.plugin_path,
host_request.plugin_path,
#endif
host_request.endpoint_base_dir,
// We pass this process' process ID as an argument so we
// can run a watchdog on the Wine plugin host process that
// shuts down the sockets after this process shuts down
std::to_string(getpid()),
bp::env = plugin_info.create_host_env())) {
host_request.endpoint_base_dir,
// We pass this process' process ID as an argument so we can
// run a watchdog on the Wine plugin host process that shuts
// down the sockets after this process shuts down
std::to_string(getpid())
},
logger,
config,
plugin_info)) {
#ifdef WITH_WINEDBG
if (plugin_info.windows_plugin_path_.string().find('"') !=
std::string::npos) {
@@ -96,9 +148,7 @@ fs::path IndividualHost::path() {
}
bool IndividualHost::running() {
// NOTE: `boost::process::child::running()` still considers zombies as
// running, so it's useless for our purposes.
return pid_running(host_.id());
return handle_.running();
}
void IndividualHost::terminate() {
@@ -109,10 +159,8 @@ void IndividualHost::terminate() {
// prevents us from joining our `std::jthread`s on the plugin side.
sockets_.close();
host_.terminate();
// NOTE: This leaves a zombie, because Boost.Process will actually not call
// `wait()` after we have terminated the process.
host_.wait();
// This will also reap the terminated process
handle_.terminate();
}
GroupHost::GroupHost(asio::io_context& io_context,
@@ -121,7 +169,7 @@ GroupHost::GroupHost(asio::io_context& io_context,
Sockets& sockets,
const PluginInfo& plugin_info,
const HostRequest& host_request)
: HostProcess(io_context, logger, config, sockets),
: HostProcess(io_context, sockets),
plugin_info_(plugin_info),
host_path_(find_vst_host(plugin_info.native_library_path_,
plugin_info.plugin_arch_,
@@ -156,15 +204,13 @@ GroupHost::GroupHost(asio::io_context& io_context,
// new group host process. This process is detached immediately
// because it should run independently of this yabridge instance as
// it will likely outlive it.
bp::child group_host =
// FIXME: Boost.Filesystem conversion
launch_host(host_path_, group_socket_path.string(),
bp::env = plugin_info.create_host_env());
Process::Handle group_host =
launch_host(host_path_, {group_socket_path.string()}, logger,
config, plugin_info);
group_host.detach();
const pid_t group_host_pid = group_host.id();
group_host_connect_handler_ =
std::jthread([this, connect, group_host_pid]() {
std::jthread([this, connect, group_host = std::move(group_host)]() {
set_realtime_priority(true);
pthread_setname_np(pthread_self(), "group-connect");
@@ -172,7 +218,7 @@ GroupHost::GroupHost(asio::io_context& io_context,
// We'll first try to connect to the group host we just spawned
// TODO: Replace this polling with inotify
while (pid_running(group_host_pid)) {
while (group_host.running()) {
std::this_thread::sleep_for(20ms);
try {
+34 -98
View File
@@ -19,10 +19,8 @@
#include <thread>
#include <asio/local/stream_protocol.hpp>
#include <asio/posix/stream_descriptor.hpp>
#include <asio/streambuf.hpp>
#include <boost/process/child.hpp>
#include <boost/process/extend.hpp>
#include <boost/process/io.hpp>
#include <ghc/filesystem.hpp>
#include "../common/communication/common.h"
@@ -59,108 +57,42 @@ class HostProcess {
*/
virtual void terminate() = 0;
/**
* Simple helper function around `boost::process::child` that launches the
* host application (`*.exe`) with some basic setup. This includes setting
* up the asynchronous pipes for STDIO redirection, closing file descriptors
* to prevent leaks, and wrapping everything in winedbg if we're compiling
* with `-Dwith-winedbg=true`. Keep in mind that winedbg does not handle
* arguments containing spaces, so most Windows paths will be split up into
* multiple arugments.
*/
template <typename... Args>
boost::process::child launch_host(ghc::filesystem::path host_path,
Args&&... args) {
return boost::process::child(
#ifdef WITH_WINEDBG
// This is set up for KDE Plasma. Other desktop environments and
// window managers require some slight modifications to spawn a
// detached terminal emulator. Alternatively, you can spawn
// `/usr/bin/winedbg` with the `--no-start` option to launch a gdb
// server and then connect to it from another terminal.
"/usr/bin/kstart5", "konsole", "--", "-e", "winedbg", "--gdb",
#ifdef WINEDBG_LEGACY_ARGUMENT_QUOTING
// Note the double quoting here. Old versions of winedbg didn't
// respect `argv` and instead expected a pre-quoted Win32 command
// line as its arguments.
"\"" + host_path.string() + ".so\"",
#else
host_path.string() + ".so",
#endif // WINEDBG_LEGACY_ARGUMENT_QUOTING
#else
// FIXME: Replace Boost.Filesystem
host_path.string(),
#endif // WITH_WINEDBG
// FIXME: This won't work with our patched async_pipe version
// boost::process::std_out = stdout_pipe_,
// boost::process::std_err = stderr_pipe_,
patched_async_pipe_out<1, -1>(stdout_pipe_),
patched_async_pipe_out<2, -1>(stderr_pipe_),
// NOTE: If the Wine process outlives the host, then it may cause
// issues if our process is still keeping the host's file
// descriptors alive that. This can prevent Ardour from
// restarting after an unexpected shutdown. Because of this we
// won't use `vfork()`, but instead we'll just manually close
// all non-STDIO file descriptors.
// HACK: If the `disable_pipes` option is enabled, then we'll
// redirect the plugin's output to a file instead of using
// pipes to blend it in with the rest of yabridge's output.
// This is for some reason necessary for ujam's plugins and
// all other plugins made with Gorilla Engine to function.
// Otherwise they'll print a nondescriptive `JS_EXEC_FAILED`
// error message.
boost::process::extend::on_exec_setup =
[this](auto& /*executor*/) {
const int max_fds = static_cast<int>(sysconf(_SC_OPEN_MAX));
for (int fd = STDERR_FILENO + 1; fd < max_fds; fd++) {
close(fd);
}
// See above
if (config_.disable_pipes) {
const int redirect_fd =
open(config_.disable_pipes->c_str(),
O_CREAT | O_APPEND | O_WRONLY, 0640);
assert(redirect_fd != -1);
dup2(redirect_fd, STDOUT_FILENO);
dup2(redirect_fd, STDERR_FILENO);
close(redirect_fd);
}
},
std::forward<Args>(args)...);
}
protected:
/**
* Initialize the host process by setting up the STDIO redirection.
* The actual process initialization and everything involved in that process
* is done in `launch_host()` since a new process may not be required
* when using plugin groups.
*
* @param io_context The IO context that the STDIO redurection will be
* handled on.
* @param logger The `Logger` instance the redirected STDIO streams will be
* written to.
* @param io_context The IO context that the STDIO redirection pipes will be
* bound to. The logging for these pipes is set up in `launch_host()`.
* @param sockets The socket endpoints that will be used for communication
* with the plugin. When the plugin shuts down, we'll close all of the
* sockets used by the plugin.
*/
HostProcess(asio::io_context& io_context,
Logger& logger,
const Configuration& config,
Sockets& sockets);
HostProcess(asio::io_context& io_context, Sockets& sockets);
/**
* The STDOUT stream of the Wine process we can forward to the logger.
* Helper function that launches the Wine host application (`*.exe`) with
* all of the correct environment setup. This includes setting the correct
* environment variables for the Wine prefix the plugin is in, setting up
* pipes or files for STDIO redirection, closing file descriptors to prevent
* leaks, and wrapping all of that in a terminal process running winedbg if
* we're compiling with `-Dwith-winedbg=true`. Keep in mind that winedbg
* does not handle arguments containing spaces, so most Windows paths will
* be split up into multiple arguments.
*
* @param logger The `Logger` instance the redirected STDIO streams will be
* written to.
* @param config The plugin's configuration, used to determine whether to
* use pipes or to redirect the output to a file instead.
* @param plugin_info Information about the plugin, used to determine the
* plugin's Wine prefix.
*/
patched_async_pipe stdout_pipe_;
/**
* The STDERR stream of the Wine process we can forward to the logger.
*/
patched_async_pipe stderr_pipe_;
/**
* The current plugin instance's configuration.
*/
const Configuration& config_;
Process::Handle launch_host(const ghc::filesystem::path& host_path,
std::initializer_list<std::string> args,
Logger& logger,
const Configuration& config,
const PluginInfo& plugin_info);
/**
* The associated sockets for the plugin we're hosting. This is used to
@@ -170,9 +102,13 @@ class HostProcess {
private:
/**
* The logger the Wine output will be written to.
* The STDOUT stream of the Wine process we can forward to the logger.
*/
Logger& logger_;
asio::posix::stream_descriptor stdout_pipe_;
/**
* The STDERR stream of the Wine process we can forward to the logger.
*/
asio::posix::stream_descriptor stderr_pipe_;
asio::streambuf stdout_buffer_;
asio::streambuf stderr_buffer_;
@@ -218,7 +154,7 @@ class IndividualHost : public HostProcess {
private:
const PluginInfo& plugin_info_;
ghc::filesystem::path host_path_;
boost::process::child host_;
Process::Handle handle_;
};
/**
+20 -46
View File
@@ -20,23 +20,14 @@
#include <unistd.h>
#include <boost/dll/runtime_symbol_info.hpp>
#include <boost/process/io.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/search_path.hpp>
#include <boost/process/system.hpp>
#include <sstream>
// XXX: With Boost 1.75 at least, this header cannot be included in alphabetical
// order because it's missing some includes
#include <boost/process/env.hpp>
// Generated inside of the build directory
#include <config.h>
#include "../common/configuration.h"
#include "../common/utils.h"
namespace bp = boost::process;
namespace fs = ghc::filesystem;
// These functions are used to populate the fields in `PluginInfo`. See the
@@ -65,25 +56,7 @@ PluginInfo::PluginInfo(PluginType plugin_type, bool prefer_32bit_vst3)
normalize_plugin_path(windows_library_path_, plugin_type)),
wine_prefix_(find_wine_prefix(windows_plugin_path_)) {}
bp::environment PluginInfo::create_host_env() const {
bp::environment env = boost::this_process::environment();
// Only set the prefix when could auto detect it and it's not being
// overridden (this entire `std::visit` instead of `std::has_alternative` is
// just for clarity's sake)
std::visit(overload{
[](const OverridenWinePrefix&) {},
[&](const ghc::filesystem::path& prefix) {
env["WINEPREFIX"] = prefix.string();
},
[](const DefaultWinePrefix&) {},
},
wine_prefix_);
return env;
}
ProcessEnvironment PluginInfo::create_host_env_2() const {
ProcessEnvironment PluginInfo::create_host_env() const {
ProcessEnvironment env(environ);
// Only set the prefix when could auto detect it and it's not being
@@ -130,7 +103,7 @@ std::string PluginInfo::wine_version() const {
Process process(wine_path);
process.arg("--version");
process.environment(create_host_env_2());
process.environment(create_host_env());
const auto result = process.spawn_get_stdout_line();
return std::visit(
@@ -345,7 +318,6 @@ std::string create_logger_prefix(const fs::path& endpoint_base_dir) {
fs::path find_vst_host(const ghc::filesystem::path& this_plugin_path,
LibArchitecture plugin_arch,
bool use_plugin_groups) {
// FIXME: Anything using `this_plugin_path` and similar needs to be changed
auto host_name = use_plugin_groups ? yabridge_group_host_name
: yabridge_individual_host_name;
if (plugin_arch == LibArchitecture::dll_32) {
@@ -361,17 +333,13 @@ fs::path find_vst_host(const ghc::filesystem::path& this_plugin_path,
return host_path;
}
// Boost will return an empty path if the file could not be found in the
// search path
const boost::filesystem::path vst_host_path =
bp::search_path(host_name, get_augmented_search_path());
if (vst_host_path == "") {
if (const std::optional<fs::path> vst_host_path =
search_in_path(get_augmented_search_path(), host_name)) {
return *vst_host_path;
} else {
throw std::runtime_error("Could not locate '" + std::string(host_name) +
"'");
}
// FIXME: Replace Boost.Filesystem usage requiring this conversion
return vst_host_path.string();
}
ghc::filesystem::path generate_group_endpoint(
@@ -396,8 +364,7 @@ ghc::filesystem::path generate_group_endpoint(
return get_temporary_directory() / socket_name.str();
}
// FIXME: Replace Boost.Filesystem
std::vector<boost::filesystem::path> get_augmented_search_path() {
std::vector<fs::path> get_augmented_search_path() {
// HACK: `std::locale("")` would return the current locale, but this
// overload is implementation specific, and libstdc++ returns an error
// when this happens and one of the locale variables (or `LANG`) is
@@ -411,6 +378,11 @@ std::vector<boost::filesystem::path> get_augmented_search_path() {
// https://svn.boost.org/trac10/changeset/72855
//
// https://github.com/boostorg/process/pull/179
// FIXME: As mentioned above, we did this in the past to work around a
// Boost.Process bug. Since we no longer use Boost.Process, we can
// technically get rid of this, but we could also leave it in place
// since this may still cause other crashes for the user if we don't
// do it.
try {
std::locale("");
} catch (const std::runtime_error&) {
@@ -431,17 +403,19 @@ std::vector<boost::filesystem::path> get_augmented_search_path() {
setenv("LC_ALL", "C", true); // NOLINT(concurrency-mt-unsafe)
}
std::vector<boost::filesystem::path> search_path =
boost::this_process::path();
// NOLINTNEXTLINE(concurrency-mt-unsafe)
const char* path_env = getenv("PATH");
assert(path_env);
std::vector<fs::path> search_path = split_path(path_env);
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (const char* xdg_data_home = getenv("XDG_DATA_HOME")) {
search_path.push_back(boost::filesystem::path(xdg_data_home) /
"yabridge");
search_path.push_back(fs::path(xdg_data_home) / "yabridge");
// NOLINTNEXTLINE(concurrency-mt-unsafe)
} else if (const char* home_directory = getenv("HOME")) {
search_path.push_back(boost::filesystem::path(home_directory) /
".local" / "share" / "yabridge");
search_path.push_back(fs::path(home_directory) / ".local" / "share" /
"yabridge");
}
return search_path;
+2 -8
View File
@@ -18,8 +18,6 @@
#include <variant>
#include <boost/process/environment.hpp>
#include "../common/configuration.h"
#include "../common/plugins.h"
#include "../common/process.h"
@@ -76,9 +74,7 @@ struct PluginInfo {
* we'll set `WINEPREFIX` to the detected Wine prefix, or it will be left
* unset if we could not detect a prefix.
*/
boost::process::environment create_host_env() const;
// FIXME: Replace create_host_env with this one
ProcessEnvironment create_host_env_2() const;
ProcessEnvironment create_host_env() const;
/**
* Return the path to the actual Wine prefix in use, taking into account
@@ -236,10 +232,8 @@ ghc::filesystem::path generate_group_endpoint(
* environment variable can be a big hurdle if you've never done anything like
* that before. And since this is the recommended installation location, it
* makes sense to also search there by default.
*
* FIXME: Replace Boost.Filesystem
*/
std::vector<boost::filesystem::path> get_augmented_search_path();
std::vector<ghc::filesystem::path> get_augmented_search_path();
/**
* Return a path to this `.so` file. This can be used to find out from where
+1
View File
@@ -22,6 +22,7 @@
#include "../asio-fix.h"
#include <asio/local/stream_protocol.hpp>
#include <asio/posix/stream_descriptor.hpp>
#include "../common/logging/common.h"
#include "../utils.h"