You can define an on-load function for a linux library using the .init
mechanism. This is the same as specifying the load-time entry point for a binary (e.g. using something other than main as the entry point for a program).
When linking using ld
directly you use the:
-init <function name>
or if you’re using cc/gcc to link, you use:
-Wl,-init,<function name>
This is at it’s most simple level.
Edit
For destructors/finalizers, you use the .fini
mechanism. This operates in the same manner as the init option, and you use:
-fini <function name>
when invoking ld
. Availability is limited to the -init
option on the Mac OSX platform.
You should also be able to use the __attribute__((constructor))
syntax for gcc:
static void con() __attribute__((constructor));
void con() {
printf("I'm a constructor\n");
}
Which is probably a more portable way rather than screwing with the linker options. All constructors should be invoked at load-time, but don’t depend on the order of their initialization, that leads to insanity and unreproducible bugs that cost time and effort to debug.
Edit 2 The use of the __attribute__((constructor))/__attribute__((destructor))
semantic is the most preferable mechanism for the C/C++ programming language.
For the D
programming language you should really use the static module constructor/destructor:
static this() {
printf("static this for mymodule\n");
}
static ~this() {
printf("static ~this for mymodule\n");
}
Or the static class constructor:
class Foo {
static this() {
printf("static this for Foo\n");
}
}
This is strongly hinted at in the writing win32 DLLS and in the language specification relating to static constructors/destructors.
Edit 3 You will need to link in a .o
that exports constructor/destructor routines, that will allow the use of the static initializers. As all it should do is call Runtime.initialize(), this actually invokes all the static constructors/destructors in the D
code.
Stub d code for the initializer (in a file called myshared.d
):
import core.runtime;
extern (C) {
void attach();
void detach();
}
export void attach() {
Runtime.initialize();
}
export void detach() {
Runtime.terminate();
}
Create the .o for this stub:
dmd -m32 -c myshared.d
Check the names of the attach/detach functions:
nm myshared.o
Shows (among other output):
0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv
sample .c code for invoking this (called export.c in this case), we reference the names of the exported routines from the my shared.o
file:
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();
}
Note that the extern void
references need to use the mangled name of the exported function. These must match or the code will not link.
compile the C code using:
gcc -m32 -c export.c
link the .c.o and the .d.o files together using:
cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2
Assuming that the phobos2 library is in your standard linker search path. The smatterings of -m32
options for the compiler and linker are because the version of the D compiler that I built locally only supported 32bit.
This produces a .dylib that can be linked to. It seems to work based on the limited testing I performed. It looks like support for shared objects/dynamic libraries is very limited, so there is a good chance that there will be another hurdle to overcome.