Zpoždění načítání NENÍ funkce runtime. MSVC++ to implementovalo bez pomoci Windows. A jako dlopen
je jediný způsob v Linuxu, GetProcAddress
je jedinou runtime metodou ve Windows.
Co je tedy zpoždění načítání? Je to velmi jednoduché:Každé volání knihovny DLL musí projít ukazatelem (protože nevíte, kde se načte). To vždy za vás vyřešil kompilátor a linker. Ale se zpožděním načítání MSVC++ nastaví tento ukazatel zpočátku na stub, který volá LoadLibrary
a GetProcAddress
pro tebe.
Clang může udělat totéž bez pomoci ld
. Za běhu je to jen obyčejný dlopen
a Linux nemůže určit, že jej Clang vložil.
Chcete-li přidat k odpovědi MSalters, lze snadno napodobit přístup Windows k línému načítání v Linuxu vytvořením malé statické knihovny se zakázaným inzerováním, která by se pokusila dlopen
potřebnou knihovnu při prvním volání kterékoli z jejích funkcí (vyslání diagnostické zprávy a ukončení, pokud selže dlopen) a následné přesměrování všech volání na ni.
Takové útržkové knihovny lze psát ručně, generovat skriptem specifickým pro projekt/knihovnu nebo generovat univerzálním nástrojem Implib.so:
$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...
Této funkce lze dosáhnout přenosným způsobem pomocí návrhového vzoru proxy.
V kódu to může vypadat nějak takto:
#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();
}