Linux Dynamic Loading of shared libraries
Steve Teale
steve.teale at britseyeview.com
Mon Mar 10 04:59:19 PDT 2014
On Sunday, 9 March 2014 at 12:07:22 UTC, Steve Teale wrote:
> Now suppose that my D shared library contains a class, rather
> that just module ctors/dtors, how do I go about creating an
> instance of that class and using its methods?
>
After wandering down several dead-end paths, and help from other
contributors, I have finally come up with something that looks
like the basis of a plugin pattern for Linux DMD using shared
objects (.so files). This is somewhat long for a forum post. You
can download this readme and the associated files from
britseyeview.com/plugin101.tar.bz2
To get started, you need a base class that provides declarations
for all functions that the plugin will be allowed to use
externally. Why base class, and not interface? Well I guess
because interfaces don't provide any information about data. If
you create a shared library based on an interface, then all the
shared object methods that reference data in the class that
implements the interface fail miserably. I'm sure someone will
explain why - probably some obvious thing I have overlooked.
OK, so my base class is:
module plugin;
class Plugin
{
int n;
this(int _n) { n = _n; }
int foo() { return int.min; }
void bar() {}
}
The class that implements this base in the shared library is:
module exta;
import plugin;
import std.stdio;
import std.math;
class ExtA: Plugin
{
double d;
this(int n) { super(n); d = PI; }
override int foo() { return ++n; }
override void bar() { writefln("Done my thing (%f)", d); }
}
Plugin getInstance(int n)
{
return new ExtA(n);
}
shared static this() {
writeln("exta.so shared static this");
}
shared static ~this() {
writeln("exta.so shared static ~this");
}
The module ctor/dtor are included because that has become
conventional in discussions about dynamic loading. Otherwise, the
so has the class implementation - ExtA, and a shared method to
create an instance of same. It includes references to methods in
Phobos.
The test program is as follows:
module main;
import core.runtime;
import std.stdio;
import plugin;
extern(C) void* dlsym(void*, const char*);
alias Plugin function(int) pfi;
Plugin getPlugin(string name)
{
void* lib = Runtime.loadLibrary(name~".so");
if (lib is null)
{
writeln("failed to load plugin shared object");
return null;
}
void* vp = dlsym(lib,
"_D4exta11getInstanceFiZC6plugin6Plugin\0".ptr);
if (vp is null)
{
writeln("plugin creator function not found");
return null;
}
pfi f = cast(pfi) vp;
Plugin x = f(42);
if (x is null)
{
writeln("creation of plugin failed");
return null;
}
return x;
}
void main()
{
Plugin x = getPlugin("exta");
int n = x.foo();
writefln("n = %d", n);
x.bar();
}
The long symbol name used in the dlsym() call is of course from
the .map file generated when the .so file is created
These can be built using the following primitive makefile, whose
main purpose is to spell out the required compiler flags:
main :
dmd -c plugin.d
dmd -c -shared -fPIC exta.d
dmd exta.o -shared -defaultlib=libphobos2.so -map
dmd -c main.d
dmd main.o plugin.o -L-ldl -defaultlib=libphobos2.so -L-rpath=.
This assumes that the plugins will be in the same directory as
the executable (rpath=.).
Note that there is no call to Runtime.unloadLibrary(). The
assumption her is that once the plugin has been loaded it will be
there for the duration of the program. If you want to unload it
you'll probably have to make sure the plugin object is purged
from memory first, and I have not discovered how to do that yet
;=(
Steve
More information about the Digitalmars-d-learn
mailing list