From fde90d7bc3cfa29e405f133d9e3bc65f4d4454cc Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sat, 16 Apr 2022 14:21:24 +0200 Subject: [PATCH] Pass plugin path around instead of redetecting This is now set only once at the top level. This is needed for the chainloading to work because we'll need to set the path when we create the bridge. --- src/common/linking.cpp | 4 +++- src/common/linking.h | 4 ++-- src/plugin/bridges/common.h | 25 ++++++++++++++----------- src/plugin/bridges/vst2.cpp | 4 +++- src/plugin/bridges/vst2.h | 8 +++++++- src/plugin/bridges/vst3.cpp | 3 ++- src/plugin/bridges/vst3.h | 8 +++++++- src/plugin/utils.cpp | 23 +++++++++++++---------- src/plugin/utils.h | 14 ++++++++++---- src/plugin/vst2-plugin.cpp | 10 ++++++++-- src/plugin/vst3-plugin.cpp | 11 +++++++++-- 11 files changed, 78 insertions(+), 36 deletions(-) diff --git a/src/common/linking.cpp b/src/common/linking.cpp index 16c2744e..c9de990b 100644 --- a/src/common/linking.cpp +++ b/src/common/linking.cpp @@ -20,7 +20,9 @@ #include -std::string get_this_file_location() { +namespace fs = ghc::filesystem; + +fs::path 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, diff --git a/src/common/linking.h b/src/common/linking.h index 20f50e20..4eb59e90 100644 --- a/src/common/linking.h +++ b/src/common/linking.h @@ -19,7 +19,7 @@ // This header is completely standalone so the chainloading libraries can // retrieve their file path without pulling in a lot of additional dependencies -#include +#include /** * Return a path to this `.so` file. This can be used to find out from where @@ -29,4 +29,4 @@ * library using the provided exported functions since they can't detect the * path themselves. */ -std::string get_this_file_location(); +ghc::filesystem::path get_this_file_location(); diff --git a/src/plugin/bridges/common.h b/src/plugin/bridges/common.h index 5238d1d9..5f2610a4 100644 --- a/src/plugin/bridges/common.h +++ b/src/plugin/bridges/common.h @@ -66,23 +66,26 @@ class PluginBridge { * `connect_sockets_guarded()` themselves after their initialization list. * * @param plugin_type The type of the plugin we're handling. - * @param plugin_path The path to the plugin. For VST2 plugins this is the - * path to the `.dll` file, and for VST3 plugins this is the path to the - * module (either a `.vst3` DLL file or a bundle). + * @param plugin_path The path to the **native** plugin library `.so` file. + * This is used to determine the path to the Windows plugin library we + * should load. * @param create_socket_instance A function to create a socket instance. * Using a lambda here feels wrong, but I can't think of a better * solution right now. * * @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. + * found, or if it could not locate and load a corresponding Windows + * plugin library. */ template < invocable_returning F> - PluginBridge(PluginType plugin_type, F&& create_socket_instance) + PluginBridge(PluginType plugin_type, + const ghc::filesystem::path& plugin_path, + F&& create_socket_instance) // This is still correct for VST3 plugins because we can configure an // entire directory (the module's bundle) at once - : config_(load_config_for(get_this_file_location())), - info_(plugin_type, config_.vst3_prefer_32bit), + : config_(load_config_for(plugin_path)), + info_(plugin_type, plugin_path, config_.vst3_prefer_32bit), io_context_(), sockets_(create_socket_instance(io_context_, info_)), generic_logger_(Logger::create_from_environment( @@ -179,7 +182,7 @@ class PluginBridge { "recommended to set up proper realtime privileges " "for your user. Check the readme for " "instructions on how to do that.", - false); + std::nullopt); } else { init_msg << "'yes'" << std::endl; } @@ -222,7 +225,7 @@ class PluginBridge { "realtime privileges for your user, and some plugins " "may cause your DAW to crash until you fix this. Check " "the readme for instructions on how to do that.", - false); + std::nullopt); } } else { init_msg @@ -390,7 +393,7 @@ class PluginBridge { "went wrong. You may need to rerun your DAW from a " "terminal and restart the plugin scanning process to " "see the error.", - true); + info_.native_library_path_); std::terminate(); } @@ -426,7 +429,7 @@ class PluginBridge { "Version mismatch", "If you just updated yabridge, then you may need " "to rerun 'yabridgectl sync' first to update your plugins.", - true); + info_.native_library_path_); } } diff --git a/src/plugin/bridges/vst2.cpp b/src/plugin/bridges/vst2.cpp index a2c4392f..76ab7338 100644 --- a/src/plugin/bridges/vst2.cpp +++ b/src/plugin/bridges/vst2.cpp @@ -35,9 +35,11 @@ Vst2PluginBridge& get_bridge_instance(const AEffect& plugin) noexcept { return *static_cast(plugin.ptr3); } -Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback) +Vst2PluginBridge::Vst2PluginBridge(const ghc::filesystem::path& plugin_path, + audioMasterCallback host_callback) : PluginBridge( PluginType::vst2, + plugin_path, [](asio::io_context& io_context, const PluginInfo& info) { return Vst2Sockets( io_context, diff --git a/src/plugin/bridges/vst2.h b/src/plugin/bridges/vst2.h index 0e0f2bc3..5f897a31 100644 --- a/src/plugin/bridges/vst2.h +++ b/src/plugin/bridges/vst2.h @@ -40,13 +40,19 @@ class Vst2PluginBridge : PluginBridge> { * Initializes the Wine plugin bridge. This sets up the sockets for event * handling. * + * @param plugin_path The path to the **native** plugin library `.so` file. + * This is used to determine the path to the Windows plugin library we + * should load. For directly loaded bridges this should be + * `get_this_file_location()`. Chainloaded plugins should use the path of + * the chainloader copy instead. * @param host_callback The callback function passed to the VST plugin by * the host. * * @throw std::runtime_error Thrown when the VST host could not be found, or * if it could not locate and load a VST .dll file. */ - Vst2PluginBridge(audioMasterCallback host_callback); + Vst2PluginBridge(const ghc::filesystem::path& plugin_path, + audioMasterCallback host_callback); /** * Terminate the Wine plugin host process and drop all work when the module diff --git a/src/plugin/bridges/vst3.cpp b/src/plugin/bridges/vst3.cpp index 1e35d32f..00c9a2d5 100644 --- a/src/plugin/bridges/vst3.cpp +++ b/src/plugin/bridges/vst3.cpp @@ -24,9 +24,10 @@ using namespace std::literals::string_literals; -Vst3PluginBridge::Vst3PluginBridge() +Vst3PluginBridge::Vst3PluginBridge(const ghc::filesystem::path& plugin_path) : PluginBridge( PluginType::vst3, + plugin_path, [](asio::io_context& io_context, const PluginInfo& info) { return Vst3Sockets( io_context, diff --git a/src/plugin/bridges/vst3.h b/src/plugin/bridges/vst3.h index f6099b2c..34efa5f7 100644 --- a/src/plugin/bridges/vst3.h +++ b/src/plugin/bridges/vst3.h @@ -52,10 +52,16 @@ class Vst3PluginBridge : PluginBridge> { * Initializes the VST3 module by starting and setting up communicating with * the Wine plugin host. * + * @param plugin_path The path to the **native** plugin library `.so` file. + * This is used to determine the path to the Windows plugin library we + * should load. For directly loaded bridges this should be + * `get_this_file_location()`. Chainloaded plugins should use the path of + * the chainloader copy instead. + * * @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. */ - explicit Vst3PluginBridge(); + explicit Vst3PluginBridge(const ghc::filesystem::path& plugin_path); /** * Terminate the Wine plugin host process and drop all work when the module diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index 88ab1854..887058f1 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -43,9 +43,11 @@ fs::path normalize_plugin_path(const fs::path& windows_library_path, std::variant find_wine_prefix( fs::path windows_plugin_path); -PluginInfo::PluginInfo(PluginType plugin_type, bool prefer_32bit_vst3) +PluginInfo::PluginInfo(PluginType plugin_type, + const ghc::filesystem::path& plugin_path, + bool prefer_32bit_vst3) : plugin_type_(plugin_type), - native_library_path_(get_this_file_location()), + native_library_path_(plugin_path), // As explained in the docstring, this is the actual Windows library. For // VST3 plugins that come in a module we should be loading that module // instead of the `.vst3` file within in, which is where @@ -423,23 +425,24 @@ Configuration load_config_for(const fs::path& yabridge_path) { bool send_notification(const std::string& title, const std::string body, - bool append_origin) { + std::optional origin) { // I think there's a zero chance that we're going to call this function with // anything that even somewhat resembles HTML, but we should still do a // basic XML escape anyways. std::ostringstream formatted_body; formatted_body << xml_escape(body); - // If possible, append the path to this library file to the message. - if (append_origin) { + // If the path to the current library file is provided, then we'll append + // the path to that library file to the message. In earlier versions we + // would detect the library path right here, but that will not work with + // chainloaded plugins as they will load the actual plugin libraries from + // fixed locations. + if (origin) { try { - const fs::path this_library = get_this_file_location(); formatted_body << "\n" << "Source: " - << xml_escape(this_library.filename().string()) + << url_encode_path(origin->parent_path().string()) + << "\">" << xml_escape(origin->filename().string()) << ""; } catch (const std::system_error&) { // I don't think this can fail in the way we're using it, but the diff --git a/src/plugin/utils.h b/src/plugin/utils.h index c6840a98..ae05ee52 100644 --- a/src/plugin/utils.h +++ b/src/plugin/utils.h @@ -58,6 +58,9 @@ struct PluginInfo { * * @param plugin_type The type of the plugin we're going to load. The * detection works slightly differently depending on the plugin type. + * @param plugin_path The path to the **native** plugin library `.so` file. + * This is used to determine the path to the Windows plugin library we + * should load. * @param prefer_32bit_vst3 If there's both a 64-bit and a 32-bit Windows * VST3 module in the same bundle, then setting this to true will cause * the 32-bit version to be used instead of the 64-bit version. @@ -66,7 +69,9 @@ struct PluginInfo { * plugin. The error message contains a human readable description of what * went wrong. */ - PluginInfo(PluginType plugin_type, bool prefer_32bit_vst3 = false); + PluginInfo(PluginType plugin_type, + const ghc::filesystem::path& plugin_path, + bool prefer_32bit_vst3 = false); /** * Create the environment for the plugin host based on `wine_prefix_`. If @@ -267,15 +272,16 @@ Configuration load_config_for(const ghc::filesystem::path& yabridge_path); * @param body The message to display. This can contain line feeds, and it any * HTML tags and XML escape sequences will be automatically escaped. The * message can also be empty. - * @param Whether to append 'Source: ' to the body, where `` is - * a hyperlink to the directory this library is placed in. + * @param origin If this is set to the current plugin's path, then the + * notification will append a 'Source: ' hyperlink to the body so the + * user can more easily navigate to the plugin's path. * * @return Whether the notification was sent. This will be false if * `notify-send` is not available. */ bool send_notification(const std::string& title, const std::string body, - bool append_origin); + std::optional origin); /** * Starting from the starting file or directory, go up in the directory diff --git a/src/plugin/vst2-plugin.cpp b/src/plugin/vst2-plugin.cpp index 674bcbe0..dfb89ea8 100644 --- a/src/plugin/vst2-plugin.cpp +++ b/src/plugin/vst2-plugin.cpp @@ -24,6 +24,8 @@ using namespace std::literals::string_literals; +namespace fs = ghc::filesystem; + // The main entry point for VST2 plugins should be called `VSTPluginMain``. The // other one exist for legacy reasons since some old hosts might still use them // (EnergyXT being the only known host on Linux that uses the `main` entry @@ -40,11 +42,15 @@ using namespace std::literals::string_literals; */ extern "C" YABRIDGE_EXPORT AEffect* VSTPluginMain( audioMasterCallback host_callback) { + // FIXME: Update this for the chainloading + const fs::path plugin_path = get_this_file_location(); + try { // This is the only place where we have to use manual memory management. // The bridge's destructor is called when the `effClose` opcode is // received. - Vst2PluginBridge* bridge = new Vst2PluginBridge(host_callback); + Vst2PluginBridge* bridge = + new Vst2PluginBridge(plugin_path, host_callback); return &bridge->plugin_; } catch (const std::exception& error) { @@ -62,7 +68,7 @@ extern "C" YABRIDGE_EXPORT AEffect* VSTPluginMain( error.what() + "\nIf you just updated yabridge, then you may need to rerun " "'yabridgectl sync' first to update your plugins."s, - true); + plugin_path); return nullptr; } diff --git a/src/plugin/vst3-plugin.cpp b/src/plugin/vst3-plugin.cpp index bff4eb83..e8b2a733 100644 --- a/src/plugin/vst3-plugin.cpp +++ b/src/plugin/vst3-plugin.cpp @@ -29,6 +29,10 @@ using namespace std::literals::string_literals; // NOLINTNEXTLINE(bugprone-suspicious-include) #include +using namespace std::literals::string_literals; + +namespace fs = ghc::filesystem; + // Because VST3 plugins consist of completely independent components that have // to be initialized and connected by the host, hosting a VST3 plugin through // yabridge works very differently from hosting VST2 plugin. Even with @@ -48,8 +52,11 @@ std::unique_ptr bridge; bool InitModule() { assert(!bridge); + // FIXME: Update this for the chainloading + const fs::path plugin_path = get_this_file_location(); + try { - bridge = std::make_unique(); + bridge = std::make_unique(plugin_path); return true; } catch (const std::exception& error) { @@ -67,7 +74,7 @@ bool InitModule() { error.what() + "\nIf you just updated yabridge, then you may need to rerun " "'yabridgectl sync' first to update your plugins."s, - true); + plugin_path); return false; }