diff --git a/sycl/include/sycl/detail/os_util.hpp b/sycl/include/sycl/detail/os_util.hpp index 936d5be56cc4..6dc084573cc5 100644 --- a/sycl/include/sycl/detail/os_util.hpp +++ b/sycl/include/sycl/detail/os_util.hpp @@ -12,6 +12,7 @@ #include // for __SYCL_EXPORT +#include #include // for size_t #include #include // for string @@ -106,27 +107,38 @@ void fileTreeWalk(const std::string Path, std::function Func, bool ignoreErrors = false); -void *dynLookup(const char *WinName, const char *LinName, const char *FunName); - // Look up a function name that was dynamically linked -// This is used by the runtime where it needs to manipulate native handles (e.g. -// retaining OpenCL handles). On Windows, the symbol name is looked up in -// `WinName`. In Linux, it uses `LinName`. +// This is used by the runtime where it needs to manipulate native handles +// (e.g. retaining OpenCL handles). // // The library must already have been loaded (perhaps by UR), otherwise this // function throws a SYCL runtime exception. +void *dynLookup(const char *const *LibNames, size_t LibNameSizes, + const char *FunName); + template -fn *dynLookupFunction(const char *WinName, const char *LinName, +fn *dynLookupFunction(const char *const *LibNames, size_t LibNameSize, const char *FunName) { - return reinterpret_cast(dynLookup(WinName, LinName, FunName)); + return reinterpret_cast(dynLookup(LibNames, LibNameSize, FunName)); } -// On Linux, the name of OpenCL that was used to link against may be either -// `OpenCL.so`, `OpenCL.so.1` or possibly anything else. -// `libur_adapter_opencl.so` is a more stable name, since it is hardcoded into -// the loader. + +// On Linux, first try to load from libur_adapter_opencl.so, then +// libur_adapter_opencl.so.0 if the first is not found. libur_adapter_opencl.so +// and libur_adapter_opencl.so.0 might be different libraries if they are not +// symlinked, which is the case with PyPi compiler distribution package. +// We can't load libur_adapter_opencl.so.0 always as the first choice because +// that would break SYCL unittests, which rely on mocking libur_adapter_opencl. +#ifdef __SYCL_RT_OS_WINDOWS +constexpr std::array OCLLibNames = {"OpenCL"}; +#else +constexpr std::array OCLLibNames = { + "libur_adapter_opencl.so", "libur_adapter_opencl.so.0"}; +#endif + #define __SYCL_OCL_CALL(FN, ...) \ (sycl::_V1::detail::dynLookupFunction( \ - "OpenCL", "libur_adapter_opencl.so", #FN)(__VA_ARGS__)) + sycl::detail::OCLLibNames.data(), sycl::detail::OCLLibNames.size(), \ + #FN)(__VA_ARGS__)) } // namespace detail } // namespace _V1 diff --git a/sycl/source/detail/os_util.cpp b/sycl/source/detail/os_util.cpp index 9069e1ca25ef..ba27c507d79a 100644 --- a/sycl/source/detail/os_util.cpp +++ b/sycl/source/detail/os_util.cpp @@ -291,36 +291,44 @@ size_t getDirectorySize(const std::string &Path, bool ignoreErrors) { return DirSizeVar; } -// Look up a function name that was dynamically linked -// This is used by the runtime where it needs to manipulate native handles (e.g. -// retaining OpenCL handles). On Windows, the symbol name is looked up in -// `WinName`. In Linux, it uses `LinName`. +// Look up a function name from the given list of shared libraries. // -// The library must already have been loaded (perhaps by UR), otherwise this +// These library must already have been loaded (perhaps by UR), otherwise this // function throws a SYCL runtime exception. -void *dynLookup([[maybe_unused]] const char *WinName, - [[maybe_unused]] const char *LinName, const char *FunName) { +void *dynLookup(const char *const *LibNames, size_t LibNameSizes, + const char *FunName) { #ifdef __SYCL_RT_OS_WINDOWS - auto handle = GetModuleHandleA(WinName); - if (!handle) { - throw sycl::exception(make_error_code(errc::runtime), - std::string(WinName) + " library is not loaded"); - } - auto *retVal = GetProcAddress(handle, FunName); + HMODULE handle = nullptr; + auto GetHandleF = [](const char *LibName) { + return GetModuleHandleA(LibName); + }; + auto GetProcF = [&]() { return GetProcAddress(handle, FunName); }; #else - auto handle = dlopen(LinName, RTLD_LAZY | RTLD_NOLOAD); - if (!handle) { - throw sycl::exception(make_error_code(errc::runtime), - std::string(LinName) + " library is not loaded"); - } - auto *retVal = dlsym(handle, FunName); - dlclose(handle); + void *handle = nullptr; + auto GetHandleF = [](const char *LibName) { + return dlopen(LibName, RTLD_LAZY | RTLD_NOLOAD); + }; + auto GetProcF = [&]() { + auto *retVal = dlsym(handle, FunName); + dlclose(handle); + return retVal; + }; #endif - if (!retVal) { + + // Iterate over the list of libraries and try to find one that is loaded. + size_t LibNameIterator = 0; + while (!handle && LibNameIterator < LibNameSizes) + handle = GetHandleF(LibNames[LibNameIterator++]); + if (!handle) + throw sycl::exception(make_error_code(errc::runtime), + "Libraries could not be loaded"); + + // Look up the function in the loaded library. + auto *retVal = GetProcF(); + if (!retVal) throw sycl::exception(make_error_code(errc::runtime), "Symbol " + std::string(FunName) + " could not be found"); - } return reinterpret_cast(retVal); }