Index: openmp/libomptarget/include/rtl.h =================================================================== --- openmp/libomptarget/include/rtl.h +++ openmp/libomptarget/include/rtl.h @@ -154,6 +154,8 @@ int64_t RequiresFlags = OMP_REQ_UNDEFINED; + static thread_local llvm::SmallVector<__tgt_bin_desc*> DelayedDescs; + explicit RTLsTy() = default; // Register the clauses of the requires directive. Index: openmp/libomptarget/src/interface.cpp =================================================================== --- openmp/libomptarget/src/interface.cpp +++ openmp/libomptarget/src/interface.cpp @@ -18,6 +18,9 @@ #include "Utilities.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SmallVector.h" + #include #include #include @@ -35,15 +38,28 @@ /// adds a target shared library to the target execution image EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) { TIMESCOPE(); + + // `RTLsTy::loadRTLs` `dlopen`s the runtime plugins, which might load other libraries finally + // calling `__tgt_register_lib` during their initialization. + // When this happens delay the loading of the libraries until the outermost call finishes, + // to ensure that the plugins are initialized before any library is loaded. + RTLsTy::DelayedDescs.push_back(Desc); + if(RTLsTy::DelayedDescs.size() > 1) { + return; + } std::call_once(PM->RTLs.InitFlag, &RTLsTy::loadRTLs, &PM->RTLs); - for (auto &RTL : PM->RTLs.AllRTLs) { - if (RTL.register_lib) { - if ((*RTL.register_lib)(Desc) != OFFLOAD_SUCCESS) { - DP("Could not register library with %s", RTL.RTLName.c_str()); + + for (auto* DelayedDesc: RTLsTy::DelayedDescs) { + for (auto &RTL : PM->RTLs.AllRTLs) { + if (RTL.register_lib) { + if ((*RTL.register_lib)(DelayedDesc) != OFFLOAD_SUCCESS) { + DP("Could not register library with %s", RTL.RTLName.c_str()); + } } } + PM->RTLs.registerLib(DelayedDesc); } - PM->RTLs.registerLib(Desc); + RTLsTy::DelayedDescs.clear(); } //////////////////////////////////////////////////////////////////////////////// @@ -54,6 +70,16 @@ /// unloads a target shared library EXTERN void __tgt_unregister_lib(__tgt_bin_desc *Desc) { TIMESCOPE(); + + // Similarly to `__tgt_register_lib`, libraries might be unregistered during `RTLsTy::loadRTLs`. + // When this happens just cancel their delayed registration. + for (auto It = RTLsTy::DelayedDescs.begin(), E = RTLsTy::DelayedDescs.end(); It != E; ++It) { + if(*It == Desc) { + RTLsTy::DelayedDescs.erase(It); + return; + } + } + PM->RTLs.unregisterLib(Desc); for (auto &RTL : PM->RTLs.UsedRTLs) { if (RTL->unregister_lib) { Index: openmp/libomptarget/src/rtl.cpp =================================================================== --- openmp/libomptarget/src/rtl.cpp +++ openmp/libomptarget/src/rtl.cpp @@ -353,6 +353,8 @@ return __tgt_image_info{(*BinaryOrErr)->getArch().data()}; } +thread_local llvm::SmallVector<__tgt_bin_desc*> RTLsTy::DelayedDescs; + void RTLsTy::registerRequires(int64_t Flags) { // TODO: add more elaborate check. // Minimal check: only set requires flags if previous value Index: openmp/libomptarget/test/offloading/dynamic_module_multiple.c =================================================================== --- /dev/null +++ openmp/libomptarget/test/offloading/dynamic_module_multiple.c @@ -0,0 +1,21 @@ +// RUN: %libomptarget-compile-generic -DFOO -fPIC -shared -o %t-foo.so && \ +// RUN: %libomptarget-compile-generic -DBAR -fPIC -shared -o %t-bar.so && \ +// RUN: %libomptarget-compile-generic %t-foo.so %t-bar.so && \ +// RUN: %libomptarget-run-generic 2>&1 | %fcheck-generic + +#if defined(FOO) +void foo() {} +#elif defined(BAR) +void bar() {} +#else + +#include +int main() { +#pragma omp target + ; + // CHECK: DONE. + printf("%s\n", "DONE."); + return 0; +} + +#endif