Das verzögerte Laden ist KEINE Laufzeitfunktion. MSVC++ hat es ohne Hilfe von Windows implementiert. Und wie dlopen
ist die einzige Möglichkeit unter Linux, GetProcAddress
ist die einzige Laufzeitmethode unter Windows.
Also, was ist dann verzögertes Laden? Es ist ganz einfach:Jeder Aufruf einer DLL muss über einen Zeiger gehen (da Sie nicht wissen, wo sie geladen wird). Dies wurde immer vom Compiler und Linker für Sie erledigt. Aber beim verzögerten Laden setzt MSVC++ diesen Zeiger zunächst auf einen Stub, der LoadLibrary
aufruft und GetProcAddress
für dich.
Clang kann dasselbe ohne Hilfe von ld
tun . Zur Laufzeit ist es nur ein gewöhnlicher dlopen
aufrufen, und Linux kann nicht feststellen, dass Clang es eingefügt hat.
Um die Antwort von MSalter zu ergänzen, kann man den Windows-Ansatz zum verzögerten Laden unter Linux leicht nachahmen, indem man eine kleine statische Stub-Bibliothek erstellt, die versuchen würde, dlopen
auszuführen Benötigte Bibliothek beim ersten Aufruf einer ihrer Funktionen (Ausgeben einer Diagnosemeldung und Beenden, wenn dlopen fehlgeschlagen ist) und Weiterleiten aller Aufrufe an sie.
Solche Stub-Bibliotheken können von Hand geschrieben, durch ein projekt-/bibliotheksspezifisches Skript oder durch das universelle Tool Implib.so generiert werden:
$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...
Diese Funktionalität kann auf portable Weise mit dem Proxy-Entwurfsmuster erreicht werden.
Im Code kann es etwa so aussehen:
#include <memory>
// SharedLibraryProxy.h
struct SharedLibraryProxy
{
virtual ~SharedLibraryProxy() = 0;
// Shared library interface begin.
virtual void foo() = 0;
virtual void bar() = 0;
// Shared library interface end.
static std::unique_ptr<SharedLibraryProxy> create();
};
// SharedLibraryProxy.cc
struct SharedLibraryProxyImp : SharedLibraryProxy
{
void* shared_lib_ = nullptr;
void (*foo_)() = nullptr;
void (*bar_)() = nullptr;
SharedLibraryProxyImp& load() {
// Platform-specific bit to load the shared library at run-time.
if(!shared_lib_) {
// shared_lib_ = dlopen(...);
// foo_ = dlsym(...)
// bar_ = dlsym(...)
}
return *this;
}
void foo() override {
return this->load().foo_();
}
void bar() override {
return this->load().bar_();
}
};
SharedLibraryProxy::~SharedLibraryProxy() {}
std::unique_ptr<SharedLibraryProxy> SharedLibraryProxy::create() {
return std::unique_ptr<SharedLibraryProxy>{new SharedLibraryProxyImp};
}
// main.cc
int main() {
auto shared_lib = SharedLibraryProxy::create();
shared_lib->foo();
shared_lib->bar();
}