diff --git a/src/common/linking.cpp b/src/common/linking.cpp new file mode 100644 index 00000000..a70f3163 --- /dev/null +++ b/src/common/linking.cpp @@ -0,0 +1,58 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020-2022 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "linking.h" + +#include + +#include + +std::string get_this_file_location() { + // We'll try to find the library this function was defined in. When called + // from a copy of `libyabridge-*.so` this will return that library. Because + // the chainloader libraries load the plugin libraries from fixed locations, + // the plugin libraries cannot use this function directly when using the + // chainloaders. + + // On success this returns a non-zero value, just to keep you on your toes + Dl_info info; + assert(dladdr(reinterpret_cast(get_this_file_location), &info) != 0); + assert(info.dli_fname); + + std::string this_file(info.dli_fname); + + // HACK: Not sure why, but `boost::dll::this_line_location()` used to return + // a path starting with a double slash on some systems. I've seen this + // happen on both Ubuntu 18.04 and 20.04, but not on Arch based + // distros. Under Linux a path starting with two slashes is treated + // the same as a path starting with only a single slash, but Wine will + // refuse to load any files when the path starts with two slashes. The + // easiest way to work around this if this happens is to just add + // another leading slash and then normalize the path, since three or + // more slashes will be coerced into a single slash. We no longer use + // Boost.Dll, but unless this was an obscure Boost.Filesystem bug it + // sounds more likely that it was caused by some `ld.so` setting. + // Unless we can really figure out what was causing this, it seems + // best to still account for it + if (this_file.starts_with("//")) { + const size_t path_start_pos = this_file.find_first_not_of('/'); + if (path_start_pos != std::string::npos) { + this_file = "/" + this_file.substr(path_start_pos); + } + } + + return this_file; +} diff --git a/src/common/linking.h b/src/common/linking.h new file mode 100644 index 00000000..0eb595a1 --- /dev/null +++ b/src/common/linking.h @@ -0,0 +1,32 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020-2022 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// This header is completely standalone so the chainloading libraries can +// retrieve their file path without pulling in a lot of additional dependencies + +#include + +/** + * Return a path to this `.so` file. This can be used to find out from where + * this copy of `libyabridge-{vst2,vst3}.so` or `libyabridge-chainloader-*.so` + * was loaded so we can search for a matching Windows plugin library. When the + * chainloaders are used, this path should be passed to the chainloaded plugin + * library using the provided exported functions since they can't detect the + * path themselves. + */ +std::string get_this_file_location(); diff --git a/src/plugin/bridges/common.h b/src/plugin/bridges/common.h index b771f0a4..640a5177 100644 --- a/src/plugin/bridges/common.h +++ b/src/plugin/bridges/common.h @@ -29,6 +29,9 @@ #include "../../common/utils.h" #include "../host-process.h" +// FIXME: This should be passed as an argument instead +#include "../../common/linking.h" + /** * If the amount of lockable memory is below this, then we'll warn about it * during startup. Otherwise we may run into issues when mapping shared memory @@ -73,9 +76,8 @@ class PluginBridge { * @throw std::runtime_error Thrown when the Wine plugin host could not be * found, or if it could not locate and load a VST3 module. */ - template F> + template < + invocable_returning F> PluginBridge(PluginType plugin_type, F&& create_socket_instance) // This is still correct for VST3 plugins because we can configure an // entire directory (the module's bundle) at once diff --git a/src/plugin/meson.build b/src/plugin/meson.build index b582ee28..287ae11a 100644 --- a/src/plugin/meson.build +++ b/src/plugin/meson.build @@ -9,6 +9,7 @@ vst2_plugin_sources = files( '../common/logging/common.cpp', '../common/logging/vst2.cpp', '../common/audio-shm.cpp', + '../common/linking.cpp', '../common/plugins.cpp', '../common/process.cpp', '../common/utils.cpp', @@ -80,6 +81,7 @@ vst3_plugin_sources = files( '../common/serialization/vst3/process-data.cpp', '../common/audio-shm.cpp', '../common/configuration.cpp', + '../common/linking.cpp', '../common/plugins.cpp', '../common/process.cpp', '../common/utils.cpp', diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index af4a6ec5..087f3822 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -19,7 +19,6 @@ #include #include -#include #include // Generated inside of the build directory @@ -28,6 +27,9 @@ #include "../common/configuration.h" #include "../common/utils.h" +// FIXME: This should be passed as an argument instead +#include "../common/linking.h" + namespace fs = ghc::filesystem; // These functions are used to populate the fields in `PluginInfo`. See the @@ -271,25 +273,6 @@ std::variant find_wine_prefix( return dosdevices_dir->parent_path(); } -fs::path get_this_file_location() { - // HACK: Not sure why, but `boost::dll::this_line_location()` returns a path - // starting with a double slash on some systems. I've seen this happen - // on both Ubuntu 18.04 and 20.04, but not on Arch based distros. - // Under Linux a path starting with two slashes is treated the same as - // a path starting with only a single slash, but Wine will refuse to - // load any files when the path starts with two slashes. The easiest - // way to work around this if this happens is to just add another - // leading slash and then normalize the path, since three or more - // slashes will be coerced into a single slash. - // FIXME: Replace Boost.Filesystem usage - fs::path this_file = boost::dll::this_line_location().string(); - if (this_file.string().starts_with("//")) { - this_file = ("/" / this_file).lexically_normal(); - } - - return this_file; -} - bool equals_case_insensitive(const std::string& a, const std::string& b) { return std::equal(a.begin(), a.end(), b.begin(), [](const char& a_char, const char& b_char) { diff --git a/src/plugin/utils.h b/src/plugin/utils.h index ea2c9630..34f1f189 100644 --- a/src/plugin/utils.h +++ b/src/plugin/utils.h @@ -235,12 +235,6 @@ ghc::filesystem::path generate_group_endpoint( */ std::vector get_augmented_search_path(); -/** - * Return a path to this `.so` file. This can be used to find out from where - * this link to or copy of `libyabridge-{vst2,vst3}.so` was loaded. - */ -ghc::filesystem::path get_this_file_location(); - /** * Load the configuration that belongs to a copy of or symlink to * `libyabridge-{vst2,vst3}.so`. If no configuration file could be found then