Just some thoughts on executables.
Gotta do something whilst the build tools are building .. :)

Felix supports a growing array of kinds of executables.

You can make your ordinary statically linked program,
or, you can make a shared library which is invoked with
flx_run or flx_arun: these two executables contain the startup
code that would otherwise be linked into a program if you used
static linkage.

When Felix makes a shared library for your program, it is also
an ordinary shared library. You can link to it from C or C++
either with load time or run time linkage. 

Felix can ALSO make the same library into a plain object file
either with or without "position independent code" or PIC.
The without case is of course used by Felix to do static linkage
and the with case to make a shared library.

I will note Felix shared libraries can ALSO by CPython 3.xx modules.
If you make a Python module, it can still, quite independently,
be run as a program or used as an ordinary C library: all the 
compiler does is make a Python module table if you specify any
function as "python".

Now, Felix has separate compilation using plugins. Before I go on you
should note that since Felix can generate shared libraries, it can also
just make ordinary old C/C++ libraries. In fact Felix can now also make
static link archives. I said that before, but I just want to emphasis that
plugins are not magic. They're just ordinary dynamic libraries following
a special protocol.

Plugins are usually implemented with the object feature of Felix,
although this isn't necessary, its the easiest way. A plugin has the
standard entry points all Felix programs have, which allow the plugins
global "thread frame" object to be created. A thread frame is an instance,
it is a memory object containing a pointer to the universal garbage collector,
program arguments, and all the libraries global variables.

The plugin loading process will therefore create a separate instance
for each load, ensuring the library is reentrant with respect to separate
loads.

Plugins has a fixed setup function which accepts a string and returns an 
integer 0 indicating success. You should view the plugin like a C++ class,
the fixed Felix instance creation is the constructor "mem-initialisers"
and the setup function plays the role of the constructor body. By parsing
the string, variables in the thread frame can be modified to configure the
plugin. I originally implemented this to support the webserver C++ and Felix
linking to include files, so the search path could be passed. However today
using objects there are better ways as we shall see.

Every plugin has a single main function. The type of this function is not
fixed, it depends on the plugin. So when you use the library functions to
load a plugin you have to specify the type of this function. There is no 
checking.
If you get the type wrong all hell breaks loose.

Felix encourages the same method as C to get the type correct: a shared header
file or interface which is used in both the building of the plugin and the 
invoking
of it. Down the track some checking may be introduced. C++ unfortunately doesn't
support run time linkage (there's no way to generate the required mangled 
names).

I am using plugins in the webserver and the Felix build tools, and indeed,
the "flx" program itself uses plugins to support the use of different toolchains
(C/C++ compilers).

Now, I ran into an issue with the webserver: I don't want the user to have to
set a LD_LIBRARY_PATH for the plugins or library, I want a fully statically
linked executable available. But I also want separate compilation because the
webserver takes ages to compile otherwise. As do the build tools ... ;(
This is because C/C++ are really badly designed languages and the existing
C++ compilers floating around are horribly inefficient. Yes, that includes gcc
and clang. They're woefully horrible, even given how bad C/C++ are.
Compare this with the build time of "flxg", the Felix compiler, written in 
Ocaml.

Now, to solve the problem of making programs *designed* for run time
loading of plugins work without doing any dynamic linkage, we add
a level of indirection. Felix contains a dictionary which maps library and
symbol names to addresses. When it goes to load a plugin it first checks
the dictionary. If the plugin is in the dictionary, subsequent requests
for the symbols in the plugin using a dlsym() like function are satisfied
from the dictionary, and no dynamic loading of the library is done.

So the problem is reduced to populating this dictionary.
This is done by some trickiness: we make an object file instead of
a shared library, and we write some code which populates the dictionary
using the required symbol names, and then link that program statically
against the plugin object file. The program is also linked against
your original program, and your original program is then called,
the same way flx_run would call it. So your program doesn't know
when it loads a plugin if the plugin is loaded dynamically or 
if the pre-loaded code is used instead. No changes are required
to your program. If you try to load a plugin which is NOT preloaded
then it is loaded dynamically, the usual way.

I have added special syntax to the Felix language to make writing
the preloaders relatively easy.

Now I will digress to the object system for a moment.
If you want a library with many functions in it, plugins pose a problem: you're
only allowed one function. General shared libraries can support any number
of functions, but to use them you have to write a C interface, and then write
a Felix binding to it in the usual way for a C library. Plugins save all that
hassle, but you only get one function "for free".

The solution is to return a record of functions, which is exactly what an
object is. If you get the type of the record right, then the type of all the
functions in it will be right too.

The best way to do this is to have the plugin function return the object
constructor function. Then you invoke that with some arguments and get
your object back. The advantage of this method is that you can have many
different objects created. Now remember each plugin load creates a separate
instance, and the instance frame contains variables shared between all objects
created by the object constructor. Of course an object constructor is just
a function returning a record of function closures which are all bound
into the constructor context, i.e. each function shares with the others
the local variables of the constructor function. Because the constructor is
a function, we have functional abstraction, which ensures that the
instance data of each object is entirely invisible except to the object
methods. This is "perfect OO" generated as a side effect of the implementation
technique. The technology is much more flexible than your usual class
based OO. It's also slightly slower, and one should note that flexibility
is ALWAYS obtained at the expense of extra complications implementing
simple things. You can do inheritance with these objects but it is not
quite as easy as with classes because you can also do one heck of a
lot more.

Anyhow, I'm now up to the point of this whole long rant.

There is a special kind of plugin, which accepts a list of strings
as the argument of its main function, and returns an int.

I will call this a command. So what is special about a command plugin?

Well, of course, its a command. After all programs are just functions
accepting a list of string arguments from the shell. So now, suppose
we have a set of command plugins. These can do grep, ls, rm,
flx .. and shell like command can be made as a plugin INSTEAD
of as a program.

Then we can do two things. We can write a little stub program like
"grep" which just loads "grep_plugin" as a plugin and runs it.
Remember we can then statically link it as well using the preloading
feature method above. So we can end up with an actual statically
linked grep program. But now, any Felix program can run grep
by running the plugin variant, WITHOUT calling the system()
command to invoke the shell (and remember that can in turn
be preloaded!)

But there's more. Since all these plugins have the same type,
they can be invoked with exactly the same piece of code:
we just need the string name of the plugin and the list of strings
with arguments. So a single program can be written which can 
invoke ANY command.

In fact, that program would take a list of arguments and strip
off the first one and treat it as the command name and use the rest
of the arguments as the arguments to that command.

Now .. there is a special name given to this program that runs commands.

Its name is SHELL.

Shell is important because we have an API (the Felix library) and we have shell
and the consensus is if you have these two things you have something else.

OPERATING SYSTEM.

So Felix is actually a (platform independent) operating system.

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




------------------------------------------------------------------------------
DreamFactory - Open Source REST & JSON Services for HTML5 & Native Apps
OAuth, Users, Roles, SQL, NoSQL, BLOB Storage and External API Access
Free app hosting. Or install the open source package on any LAMP server.
Sign up and see examples for AngularJS, jQuery, Sencha Touch and Native!
http://pubads.g.doubleclick.net/gampad/clk?id=63469471&iu=/4140/ostg.clktrk
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to