È possibile definire una funzione di caricamento per una libreria Linux utilizzando il meccanismo .init
. Questo equivale a specificare il punto di ingresso del tempo di caricamento per un binario (ad esempio utilizzando qualcosa di diverso da main come punto di ingresso per un programma).
Quando si collega usando ld
direttamente si utilizza il:
-init <function name>
o se si sta utilizzando cc/gcc di collegare, si utilizza:
-Wl,-init,<function name>
Questo è al suo livello più semplice.
Modifica Per distruttori/finalizzatori, si utilizza il meccanismo .fini
. Questo funziona nello stesso modo come l'opzione di init, e si utilizza:
-fini <function name>
quando si richiama ld
. La disponibilità è limitata all'opzione -init
sulla piattaforma Mac OSX.
Si dovrebbe anche essere in grado di utilizzare la sintassi __attribute__((constructor))
per gcc:
static void con() __attribute__((constructor));
void con() {
printf("I'm a constructor\n");
}
che è probabilmente un modo più portatile piuttosto che avvitare con le opzioni di linker. Tutti i costruttori devono essere richiamati al momento del caricamento, ma non è il dipendente dall'ordine della loro inizializzazione, che porta alla follia e bug non riproducibili che costano tempo e fatica per il debug.
Modifica 2 L'uso della semantica __attribute__((constructor))/__attribute__((destructor))
è il meccanismo più preferibile per il linguaggio di programmazione C/C++.
Per la lingua D
di programmazione si dovrebbe davvero utilizzare la statica del modulo costruttore/distruttore:
static this() {
printf("static this for mymodule\n");
}
static ~this() {
printf("static ~this for mymodule\n");
}
o la classe costruttore statico:
class Foo {
static this() {
printf("static this for Foo\n");
}
}
Questo è fortemente accennato nel writing win32 DLLS e in la specifica della lingua relating to static constructors/destructors.
Modifica 3 È necessario collegare in un .o
che esporta le routine di costruzione/distruttore, che consentiranno l'utilizzo degli inizializzatori statici. Come tutto ciò che dovrebbe fare è chiamare Runtime.initialize(), questo in realtà richiama tutti i costruttori/distruttori statici nel codice D
.
Stub codice d per l'inizializzazione (in un file chiamato myshared.d
):
import core.runtime;
extern (C) {
void attach();
void detach();
}
export void attach() {
Runtime.initialize();
}
export void detach() {
Runtime.terminate();
}
Creare il .o per questo stub:
dmd -m32 -c myshared.d
controllare i nomi delle funzioni di aggancio/sgancio:
nm myshared.o
Spettacoli (tra gli altri in uscita):
0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv
esempio di codice .c di richiamo di questa (chiamato export.c in questo caso), ci riferimento ai nomi delle routine esportate dal file my shared.o
:
extern void D8myshared6attachFZv(void);
extern void D8myshared6detachFZv(void);
void __attach(void) __attribute__((constructor));
void __detach(void) __attribute__((destructor));
void __attach(void)
{
D8myshared6attachFZv();
}
void __detach(void)
{
D8myshared6detachFZv();
}
Si noti che i riferimenti devono extern void
usa il nome storpiato della funzione esportata. Questi devono corrispondere o il codice non si collegherà.
compila il codice C utilizzando:
gcc -m32 -c export.c
link .c.o ei file .d.o insieme utilizzando:
cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2
Supponendo che la libreria phobos2 è nel percorso di ricerca linker standard. Le infarinature delle opzioni -m32
per il compilatore e il linker sono perché la versione del compilatore D che ho creato localmente supportava solo 32 bit.
Questo produce un .dylib che può essere collegato a. Sembra funzionare sulla base dei test limitati che ho eseguito. Sembra che il supporto per gli oggetti condivisi/le librerie dinamiche sia molto limitato, quindi ci sono buone probabilità che ci sia un altro ostacolo da superare.
https://stackoverflow.com/q/2053029/4361073 – parasrish