La carga diferida NO es una función de tiempo de ejecución. MSVC++ lo implementó sin la ayuda de Windows. Y como dlopen
es la única forma en Linux, GetProcAddress
es el único método de tiempo de ejecución en Windows.
Entonces, ¿qué es la carga retrasada entonces? Es muy simple:cualquier llamada a una DLL tiene que pasar por un puntero (ya que no sabes dónde se cargará). Esto siempre ha sido manejado por el compilador y el enlazador por usted. Pero con la carga retrasada, MSVC ++ establece este puntero inicialmente en un código auxiliar que llama a LoadLibrary
y GetProcAddress
para ti.
Clang puede hacer lo mismo sin la ayuda de ld
. En tiempo de ejecución, es solo un dlopen
ordinario llamada, y Linux no puede determinar que Clang la insertó.
Para agregar a la respuesta de MSalters, uno puede imitar fácilmente el enfoque de Windows para la carga diferida en Linux mediante la creación de una pequeña biblioteca de código auxiliar estático que intentaría dlopen
biblioteca necesaria en la primera llamada a cualquiera de sus funciones (emitir un mensaje de diagnóstico y finalizar si falla dlopen) y luego reenviar todas las llamadas.
Estas bibliotecas de código auxiliar pueden escribirse a mano, generarse mediante un script específico de proyecto/biblioteca o generarse mediante la herramienta universal Implib.so:
$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...
Esta funcionalidad se puede lograr de forma portátil utilizando el patrón de diseño Proxy.
En el código puede ser algo como esto:
#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();
}