From d73a0041eb8548679cfc42b2ef0543b51f6e3d74 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sat, 16 Apr 2022 19:26:27 +0200 Subject: [PATCH] Find the correct library file from the chainloader Instead of using this hardcdoed path. --- src/chainloader/meson.build | 8 ++- src/chainloader/utils.cpp | 81 ++++++++++++++++++++++++++++ src/chainloader/utils.h | 37 +++++++++++++ src/chainloader/vst2-chainloader.cpp | 19 ++++--- src/chainloader/vst3-chainloader.cpp | 19 ++++--- src/plugin/bridges/common.h | 1 + src/plugin/vst2-plugin.cpp | 4 +- src/plugin/vst3-plugin.cpp | 4 +- 8 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 src/chainloader/utils.cpp create mode 100644 src/chainloader/utils.h diff --git a/src/chainloader/meson.build b/src/chainloader/meson.build index 195e1367..622904f6 100644 --- a/src/chainloader/meson.build +++ b/src/chainloader/meson.build @@ -2,15 +2,19 @@ # main `meson.build` file so everything gets bundled to a single directory. vst2_chainloader_sources = files( - 'vst2-chainloader.cpp', + '../common/logging/common.cpp', '../common/linking.cpp', '../common/notifications.cpp', '../common/process.cpp', + 'utils.cpp', + 'vst2-chainloader.cpp', ) vst3_chainloader_sources = files( - 'vst3-chainloader.cpp', + '../common/logging/common.cpp', '../common/linking.cpp', '../common/notifications.cpp', '../common/process.cpp', + 'utils.cpp', + 'vst3-chainloader.cpp', ) diff --git a/src/chainloader/utils.cpp b/src/chainloader/utils.cpp new file mode 100644 index 00000000..e2cec39b --- /dev/null +++ b/src/chainloader/utils.cpp @@ -0,0 +1,81 @@ +// yabridge: a Wine plugin 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 "utils.h" + +#include + +// Generated inside of the build directory +#include + +#include "../common/linking.h" +#include "../common/logging/common.h" +#include "../common/notifications.h" +#include "../common/process.h" + +namespace fs = ghc::filesystem; + +void* find_plugin_library(const std::string& name) { + // Just using a goto for this would probably be cleaner, but yeah... + const auto impl = [&name]() -> void* { + // If `name` exists right next to the Wine plugin host binary, then + // we'll try loading that. Otherwise we'll fall back to regular + // `dlopen()` for distro packaged versions of yabridge + const std::vector search_path = get_augmented_search_path(); + if (const auto& yabridge_host_path = + search_in_path(search_path, yabridge_individual_host_name)) { + const fs::path candidate = yabridge_host_path->parent_path() / name; + if (fs::exists(candidate)) { + return dlopen(candidate.c_str(), RTLD_LAZY | RTLD_LOCAL); + } + } + + if (const auto& yabridge_host_32_path = search_in_path( + search_path, yabridge_individual_host_name_32bit)) { + const fs::path candidate = + yabridge_host_32_path->parent_path() / name; + if (fs::exists(candidate)) { + return dlopen(candidate.c_str(), RTLD_LAZY | RTLD_LOCAL); + } + } + + return dlopen(name.c_str(), RTLD_LAZY | RTLD_LOCAL); + }; + + void* handle = impl(); + if (!handle) { + const fs::path this_plugin_path = get_this_file_location(); + + Logger logger = Logger::create_exception_logger(); + + logger.log(""); + logger.log("Could not find '" + name + "'."); + logger.log("Make sure you followed the installation instructions from"); + logger.log("yabridge's readme"); + logger.log(""); + logger.log("Source: '" + this_plugin_path.string() + "'"); + logger.log(""); + + // Also show a desktop notification since most people likely won't see + // the above message + send_notification("Could not find '" + name + "'", + "Make sure you followed the installation " + "instructions from yabridge's readme", + this_plugin_path); + } + + return handle; +} diff --git a/src/chainloader/utils.h b/src/chainloader/utils.h new file mode 100644 index 00000000..48be7826 --- /dev/null +++ b/src/chainloader/utils.h @@ -0,0 +1,37 @@ +// yabridge: a Wine plugin 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 + +#include + +/** + * Finds the matching `libyabridge-*.so` for this chainloader. Returns the + * handle if it is found. Otherwise, we'll log an error and show a desktop + * notification, and this function returns a null pointer. The pointer may be + * `dlclose()`'d when it's no longer needed. This search works in the following + * order: + * + * - First we'll try to locate `yabridge-host.exe` using the same method used by + * the yabridge plugin bridges themselves. We'll search in `$PATH`, followed + * by `${XDG_DATA_HOME:-$HOME/.local/share}/yabridge`. If that file exists and + * the target plugin library exists right next to it, then we'll use that. + * - For compatibility with 32-bit only builds of yabridge, we'll repeat this + * process for `yabridge-host-32.exe`. + * - When those don't exist, we'll try to `dlopen()` the file directly. This + * will use the correct path for the system. + */ +void* find_plugin_library(const std::string& name); diff --git a/src/chainloader/vst2-chainloader.cpp b/src/chainloader/vst2-chainloader.cpp index a6da808a..030bebaf 100644 --- a/src/chainloader/vst2-chainloader.cpp +++ b/src/chainloader/vst2-chainloader.cpp @@ -20,8 +20,12 @@ #include +// Generated inside of the build directory +#include + #include "../common/linking.h" #include "../common/utils.h" +#include "utils.h" // These chainloader libraries are tiny, mostly dependencyless libraries that // `dlopen()` the actual `libyabridge-{vst2,vst3}.so` files and forward the @@ -35,8 +39,6 @@ // distro packaging, because updates to Boost might require the package to be // rebuilt, which in turn would also require a resync. -// TODO: Order to check in: See Discord - namespace fs = ghc::filesystem; using audioMasterCallback = void*; @@ -65,11 +67,10 @@ bool initialize_library() { return true; } - // FIXME: Hardcoded path - library_handle = dlopen( - "/home/robbert/Documenten/projecten/yabridge/build/libyabridge-vst2.so", - RTLD_LAZY | RTLD_LOCAL); - assert(library_handle); + library_handle = find_plugin_library(yabridge_vst2_plugin_name); + if (!library_handle) { + return false; + } #define LOAD_FUNCTION(name) \ do { \ @@ -89,7 +90,9 @@ extern "C" YABRIDGE_EXPORT AEffect* VSTPluginMain( audioMasterCallback host_callback) { assert(host_callback); - initialize_library(); + if (!initialize_library()) { + return nullptr; + } const fs::path this_plugin_path = get_this_file_location(); return yabridge_plugin_init(host_callback, this_plugin_path.c_str()); diff --git a/src/chainloader/vst3-chainloader.cpp b/src/chainloader/vst3-chainloader.cpp index 8b476050..3ce91113 100644 --- a/src/chainloader/vst3-chainloader.cpp +++ b/src/chainloader/vst3-chainloader.cpp @@ -20,8 +20,12 @@ #include +// Generated inside of the build directory +#include + #include "../common/linking.h" #include "../common/utils.h" +#include "utils.h" // These chainloader libraries are tiny, mostly dependencyless libraries that // `dlopen()` the actual `libyabridge-{vst2,vst3}.so` files and forward the @@ -35,8 +39,6 @@ // distro packaging, because updates to Boost might require the package to be // rebuilt, which in turn would also require a resync. -// TODO: Order to check in: See Discord - namespace fs = ghc::filesystem; using Vst3PluginBridge = void; @@ -83,11 +85,10 @@ bool initialize_library() { return true; } - // FIXME: Hardcoded path - library_handle = dlopen( - "/home/robbert/Documenten/projecten/yabridge/build/libyabridge-vst3.so", - RTLD_LAZY | RTLD_LOCAL); - assert(library_handle); + library_handle = find_plugin_library(yabridge_vst3_plugin_name); + if (!library_handle) { + return false; + } #define LOAD_FUNCTION(name) \ do { \ @@ -109,7 +110,9 @@ extern "C" YABRIDGE_EXPORT bool ModuleEntry(void*) { // This function can be called multiple times, so we should make sure to // only initialize the bridge on the first call if (active_instances.fetch_add(1, std::memory_order_seq_cst) == 0) { - assert(initialize_library()); + if (!initialize_library()) { + return false; + } // You can't change the deleter function with `.reset()` so we'll need // this abomination instead diff --git a/src/plugin/bridges/common.h b/src/plugin/bridges/common.h index 61cfc5d2..f42f8860 100644 --- a/src/plugin/bridges/common.h +++ b/src/plugin/bridges/common.h @@ -142,6 +142,7 @@ class PluginBridge { << " (32-bit build)" #endif << std::endl; + // TODO: Show this library's path now that we're chainloading init_msg << "host: '" << plugin_host_->path().string() << "'" << std::endl; init_msg << "plugin: '" << info_.windows_plugin_path_.string() diff --git a/src/plugin/vst2-plugin.cpp b/src/plugin/vst2-plugin.cpp index f5056741..52b7800d 100644 --- a/src/plugin/vst2-plugin.cpp +++ b/src/plugin/vst2-plugin.cpp @@ -52,8 +52,8 @@ void log_init_error(const std::exception& error, const fs::path& plugin_path) { logger.log(error.what()); logger.log(""); - // Also show a desktop notification most people likely won't see the above - // message + // Also show a desktop notification since most people likely won't see the + // above message send_notification( "Failed to initialize VST2 plugin", error.what() + diff --git a/src/plugin/vst3-plugin.cpp b/src/plugin/vst3-plugin.cpp index 9a430e71..67f73ec4 100644 --- a/src/plugin/vst3-plugin.cpp +++ b/src/plugin/vst3-plugin.cpp @@ -77,8 +77,8 @@ void log_init_exception(const std::exception& error, logger.log(error.what()); logger.log(""); - // Also show a desktop notification most people likely won't see the above - // message + // Also show a desktop notification since most people likely won't see the + // above message // FIXME: Go through these messages and update them to reflect the // chainloading changes send_notification(