From e6e628a43af663d317859cdeb1fda69195245b1e Mon Sep 17 00:00:00 2001 From: "Attila M. Magyar" Date: Sun, 9 Jul 2023 23:10:43 +0200 Subject: [PATCH 1/2] Try loading alternative SO files on 32 bit Linux When a 32 bit host application is running with a 64 bit Linux kernel, then getCurrentMachineName will return "x86_64", but dlopen will fail with "wrong ELF class: ELFCLASS64". When this happens, our best bet might be to try loading the plugin from "i686-linux" and "i386-linux". See: https://github.com/steinbergmedia/vst3sdk/issues/115 --- source/vst/hosting/module_linux.cpp | 82 ++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/source/vst/hosting/module_linux.cpp b/source/vst/hosting/module_linux.cpp index 404054c..ed20d0a 100644 --- a/source/vst/hosting/module_linux.cpp +++ b/source/vst/hosting/module_linux.cpp @@ -143,7 +143,7 @@ class LinuxModule : public Module } } - static Optional getSOPath (const std::string& inPath) + static Optional getSOPath (const std::string& inPath, const std::string& machine) { Path modulePath {inPath}; if (!filesystem::is_directory (modulePath)) @@ -155,12 +155,7 @@ class LinuxModule : public Module if (!filesystem::is_directory (modulePath)) return {}; - // use the Machine Hardware Name (from uname cmd-line) as prefix for "-linux" - auto machine = getCurrentMachineName (); - if (!machine) - return {}; - - modulePath /= *machine + "-linux"; + modulePath /= machine + "-linux"; if (!filesystem::is_directory (modulePath)) return {}; @@ -171,10 +166,59 @@ class LinuxModule : public Module bool load (const std::string& inPath, std::string& errorDescription) override { - auto modulePath = getSOPath (inPath); + // use the Machine Hardware Name (from uname cmd-line) as prefix for "-linux" + auto machine = getCurrentMachineName (); + if (!machine) + { + errorDescription = "uname failed."; + return false; + } + + errorDescription = ""; + +#if SMTG_PLATFORM_64 + return tryLoad (inPath, errorDescription, *machine); +#else + if (tryLoad (inPath, errorDescription, *machine)) + { + return true; + } + + // 64 bit kernel may be runnig a 32 bit application, try possible options + + if (*machine != "i686") + { + errorDescription += '\n'; + if (tryLoad (inPath, errorDescription, "i686")) + { + errorDescription = ""; + return true; + } + } + + if (*machine != "i386") + { + errorDescription += '\n'; + if (tryLoad (inPath, errorDescription, "i386")) + { + errorDescription = ""; + return true; + } + } + + return false; +#endif + } + + void* mModule {nullptr}; + +private: + bool tryLoad (const std::string& inPath, std::string& errorDescription, const std::string& machine) + { + auto modulePath = getSOPath (inPath, machine); if (!modulePath) { - errorDescription = inPath + " is not a module directory."; + errorDescription += inPath + " is not a module directory (" + machine + ")."; return false; } @@ -182,7 +226,7 @@ class LinuxModule : public Module RTLD_LAZY); if (!mModule) { - errorDescription = "dlopen failed.\n"; + errorDescription += "dlopen failed (" + machine + ").\n"; errorDescription += dlerror (); return false; } @@ -190,42 +234,40 @@ class LinuxModule : public Module auto moduleEntry = getFunctionPointer ("ModuleEntry"); if (!moduleEntry) { - errorDescription = - "The shared library does not export the required 'ModuleEntry' function"; + errorDescription += + "The shared library does not export the required 'ModuleEntry' function (" + machine + ")."; return false; } // ModuleExit is mandatory auto moduleExit = getFunctionPointer ("ModuleExit"); if (!moduleExit) { - errorDescription = - "The shared library does not export the required 'ModuleExit' function"; + errorDescription += + "The shared library does not export the required 'ModuleExit' function (" + machine + ")."; return false; } auto factoryProc = getFunctionPointer ("GetPluginFactory"); if (!factoryProc) { - errorDescription = - "The shared library does not export the required 'GetPluginFactory' function"; + errorDescription += + "The shared library does not export the required 'GetPluginFactory' function (" + machine + ")."; return false; } if (!moduleEntry (mModule)) { - errorDescription = "Calling 'ModuleEntry' failed"; + errorDescription += "Calling 'ModuleEntry' failed (" + machine + ")."; return false; } auto f = Steinberg::FUnknownPtr (owned (factoryProc ())); if (!f) { - errorDescription = "Calling 'GetPluginFactory' returned nullptr"; + errorDescription += "Calling 'GetPluginFactory' returned nullptr (" + machine + ")."; return false; } factory = PluginFactory (f); return true; } - - void* mModule {nullptr}; }; //------------------------------------------------------------------------ From e21c2ecd37c7220fa5589b399ca33951dbc031ea Mon Sep 17 00:00:00 2001 From: "Attila M. Magyar" Date: Mon, 10 Jul 2023 10:55:26 +0200 Subject: [PATCH 2/2] More detailed explanation for the 32 bit fallback in source/vst/hosting/module_linux.cpp --- source/vst/hosting/module_linux.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/vst/hosting/module_linux.cpp b/source/vst/hosting/module_linux.cpp index ed20d0a..c90b8dd 100644 --- a/source/vst/hosting/module_linux.cpp +++ b/source/vst/hosting/module_linux.cpp @@ -184,7 +184,10 @@ class LinuxModule : public Module return true; } - // 64 bit kernel may be runnig a 32 bit application, try possible options + // 64 bit kernel may be runnig a 32 bit application, or uname reported i386 when + // we should be looking for i686 or vica-versa, so let's try possible options. + // Note: this logic assumes that the host will never run on a CPU which actually + // doesn't support i686 instructions. if (*machine != "i686") {