When Felix makes a top level unit from a file, it synthesises a module name
from the file name. For example if you're compiling "mname.flx" the module
name will be mname.

In the C++ code generated, everything is put inside

namespace flxusr { namespace mname {
...
}}

This ensures all such units can be linked together without
conflict provided the file basenames are distinct
(maybe there's even a switch to override this I don't know).

Now the problem is that Felix uses dynamic linkage by default,
and there are three extern "C" wrapper entry points:

"create_thread_frame"
-------------------------------

used to construct the thread frame
object which contains all the global data. This function
just does "new mname::thread_frame_t()"

"flx_start"
------------

This runs the procedure "mname::_init_" passing it
argv, argc, stdin, stdout, stderr. The three FILE* are
passed so that Felix code can do standard I/O
without calling any fucked up static objects: that is,
to work around the bad design of ISO C and make
these files parameters. This also allows redirection.
Pointers to the corresponding C++ iostreams are
not passed.  Actual Felix code can and does still
use the non-parametric static objects (should
be fixed eventually since re-entrancy is compromised).

"flx_main"
--------------

You've probably never heard of Felix's replacement
for C's main() function. The program driver runs
create_thread_frame to make a frame object,
then passes it to flx_start, whose job is to initialise it.
Most Felix "programs" are just side effects of initialisation.

Then, flx_main is called if it exists.
This is your actual main program. Whilst "initialisation
side effects" are nice for tutorial code, such code can
be written in many files and the order in which it runs
is indeterminate. To properly setup your environment,
you use flx_main and real control flow constructs.
As you should always do in C and C++! NEVER use
singletons, static initialisers, auto-registration or
other crap to do real work: static initialisers are there to
initialise strings.

Ok, so here's the problem: if you make two such compilation
units as plugins you can plug both of them in, no problem!
This is because symbols in run time dynamically loaded shared
objects do not have to be globally unique: each has its own
symbol table which can (and must) be chosen by the handle
of the loaded library:

SYNOPSIS
     #include <dlfcn.h>

     void*
     dlsym(void* handle, const char* symbol);

The problem is that you cannot statically think such units.

In particular here's a use case: the Felix webserver.
This uses plugins. The webserver itself can be statically
linked to the run time -- but it will still use dynamically
linked plugins. This can be nice but it makes 
SHIPPING a binary difficult -- its called DLLHELL :)

Ideally, we'd modify the plugin loader so it first searches
a registry of preloaded plugins before looking in the file system.
Python does this. These preloaded modules are statically
linked into the program and somehow registered.

But to do this, the first two magic names above have to be replaced
by globally unique ones. We don't have to worry about flx_main
because no one is using it, and if they did .. well you're only allowed
one top level main procedure anyhow.

So: it is easy to modify the plugin manager code to use the new naming
scheme. The problem is that the flx_run code needs fixed entry points:


#ifdef FLX_STATIC_LINK
extern "C" void *create_thread_frame;
extern "C" void *flx_start;
extern "C" void *flx_main;
#endif


#ifdef FLX_STATIC_LINK
    flx_dynlink_t library(
      (thread_frame_creator_t)&create_thread_frame,
      (start_t)&flx_start,
      (main_t)&flx_main);
#else
    flx_dynlink_t library;
    library.link(filename);
#endif


SO: the only solution I can think of goes like this:

(a) generate distinct names 

(b) take all the startup code and factor it out into a library
function: pass the entry points to it (as function pointers).
The library function has a fixed name.

(c) When "flx" runs, actually generate C++ mainline
text if statically linking, which calculates the pointers
using the module name (i.e. it emits C++ text with
the startup names hard coded in, and does nothing
but pass them to the library). That is, generate a thunk.

For dynamic linkage we don't need the thunk because we're
using dlopen/dlsym anyhow.

One advantage of this is that you can make a static archive
which contains many programs and just "pick" one to run
by generating a thunk (the thunk itself has C main() function).

This still leaves open how to register statically linked plugins
so the code that currently links to these plugins can search
the registry first, before trying dlopen (the actual code has
to be transparent, i.e. the webserver should run the same
whether one or more plugins happens to be statically
linked or not)

--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to