Building an Executable
Instead of just running ob_client as script, we can build an executable.
The command works on all platforms:
flx --static -c -od . ob_client.flx
This will put an executable ob_client in the current directory on
Linux or OSX, or ob_client.exe on Windows.
You can run the executable:
and it will work as before, loading the plugin dynamically. Hopefully.
But the executable is not self-contained so cannot be easily shipped,
the plugin binary has to be shipped too, and put on the dynamic linker
Static Prelinking Plugins
There is a solution! When Felix tries to load a plugin by its text name,
it first looks in a special data structure called the prelink respository
to see if it is pre-loaded.
If not, it tries an actual OS level library load. If we want to avoid
this, we can statically link the plugin with the program, and then
load the appropriate information into the pre-link repository.
To do this, we have to first create an object file for the plugin,
instead of a DLL.
flx --static -c -od . --nolink ob_implementation.flx
This puts the object file into the current directory.
It will be called ob_implementation_static.o on MacOSX or Linux,
or ob_implementation_static.obj on Windows.
Now we have to compile our program as an object file too:
flx --static -c -od . --nolink ob_client.flx
Now we need a special file called a static loader thunk:
static-link-symbol ob_client_create_thread_frame in plugin ob_client;
static-link-symbol ob_client_flx_start in plugin ob_client;
val linstance = Dynlink::prepare_lib("ob_client");
This is actually our mainline now! We need to open the class Dynlink
to find the functions used for storing stuff in the registry.
Next, we specify the name of our plugin.
We also need to specify the names of two symbols used to run our
program. ob_client_create_thread_frame allocates a
global storage object. ob_client_flx_start runs the initialisation
procedure for that object: this is actually what you previously,
and incorrectly, thought of as your program.
What?? Yes, that’s right. Felix doesn’t do programs, only libraries.
What you thought was your program is actually the side-effects of the
initialisation procedure for a library.
Finally, we create an instance of the library ob_client with
Dylink’s function prepare_lib. This creates the thread frame
object and initialises it (yep, that’s your “program” running).
Since that’s all we want to do we just ignore the library handle
and we’re finished.
When the ob_client code runs, it tries to load the plugin
ob_implementation. But it finds it in the registry, along
with the stanard symbols a plugin has. The static-link-plugin
statement generates code that updates the repository.
Here’s how you link the program:
flx --static -c -od . \
Notice that unfortunately you have to give the platform dependent name of the
object files. Notice also Felix adds the suffix _static to object files compiled
for static linkage. Object files compiled for dynamic linkage get the suffix
_dynamic instead. On some platforms these are the same, but not Linux.
Dynamic link objects are compiled with -fPIC for position independent code.
Static link files are not. For the x86_64 processor, leaving out -fPIC
generates much faster function calls.
The final program can be run like: