I would like to announce a MAJOR breakthrough in Felix: separate compilation.

There are caveats, and the tooling is not complete. However I want to show
what this is about.

First, here is a library:

///////////////  xt.flx 
////////////////////////////////////////////////////////////////
export fun setup (x:int) => x+10;
class A {
  export fun setup2 (x:int) => x+100;
}

export inline cfun setup3 (x:int) => x+1000;
export "fred" inline cfun setup4 (x:int) => x+10000;

cfun setup5 (x:int) => 100000;
export cfun setup5 of (int) as "joe";

export proc p99 (x:int) { println$ "p99=" + str (x + 99); }
export cproc p100 (x:int) { println$ "p100=" + str (x +100); }

println$ "Done " + 22.setup.str;
/////////////////////////////////////////////////////////////////////////////////////////

You can run this as a program too. There are some variations
on exports shown here, for testing. Exported entities are ready
for dlsym() when the code is loaded at run time, however
that's not new.  

When Felix compiles this code, it sees that there are exports
and produces a new file:


////////// xt_interface.flx 
/////////////////////////////////////////////////////////////////////////
class xt_interface {
  // FELIX FUNCTION setup
  // binding for export fun _i41924_f41924_setup as setup
  fun setup : int -> int = "setup(ptf,$1)"
    requires
      property "needs_ptf",
      header
       """
       extern "C" FLX_IMPORT int setup(void *, int);
       """
  ;

  // FELIX C FUNCTION setup3
  // binding for export cfun _i41933_f41933_setup3 as setup3
  fun setup3 : int -> int = "setup3($1)"
    requires
      header
       """
       extern "C" FLX_IMPORT int setup3(int);
       """
  ;

  // FELIX C FUNCTION fred
  // binding for export cfun setup4 as fred
  fun fred : int -> int = "fred($1)"
    requires
      header
       """
       extern "C" FLX_IMPORT int fred(int);
       """
  ;

  // FELIX C FUNCTION joe
  // binding for export cfun setup5 as joe
  fun joe : int -> int = "joe($1)"
    requires
      header
       """
       extern "C" FLX_IMPORT int joe(int);
       """
  ;

  // FELIX FUNCTION p99
  // binding for export proc _i41942_p41942_p99 as p99
  proc p99 : int = "p99(ptf,$1);"
    requires
      property "needs_ptf",
      header
       """
       extern "C" FLX_IMPORT ::flx::rtl::con_t *  p99(void *, int);
       """
  ;

  // FELIX C FUNCTION p100
  // binding for export cproc _i41945_p41945_p100 as p100
  proc p100 : int = "p100($1);"
    requires
      header
       """
       extern "C" FLX_IMPORT ::flx::rtl::con_t *  p100(int);
       """
  ;

  // FELIX FUNCTION setup2
  // binding for export fun _i41929_f41929_setup2 as setup2
  fun setup2 : int -> int = "setup2(ptf,$1)"
    requires
      property "needs_ptf",
      header
       """
       extern "C" FLX_IMPORT int setup2(void *, int);
       """
  ;

}
/////////////////////////////////////////////////

This file contains Felix bindings for the libraries extern "C" wrappers
for the Felix functions which were exported.  The file is currently
plonked into the cache, so I copied it out manually. 
I'll show the script in a second.

Now, to use this file we will write a little test client:

///////// xtclient.flx ///////////////////////////////////////////
include "./xt_interface";
open xt_interface;

println$ setup 1;
println$ setup2 2;
println$ setup3 3;
println$ fred 4;
println$ joe 5;
p99(60);
p100(70);
///////////////////////////////////////////////////////////////////////////////

And that's it! I decided to put the interface in a class for some obscure reason
so after including the interface, I opened the class (but you can use qualified 
names
instead if you want).

Here's my script:

build/release/host/bin/flx --test=build/release -c --nolink -o xt.o xt
cp ~/.felix/cache/text/Users/johnskaller/felix/xt_interface.flx  .
build/release/host/bin/flx --test=build/release xt.o xtclient
11
102
1003
10004
100000
p99=159
p100=170


Apart from tooling issues, there's a MAJOR caveat. Or three.

(1) You have to use shared bindings of known C types as function 
arguments and returns.  Note this is a dual requirement!

For the C types, you will have to share them so the bindings are
the same type in both library and client. The types generated for
Felix anonymous data types like tuples, records and unions have
distinct name in distinct compilations. So the C types names
generated in the interface will be those used in the library
and won't agree with the C names generated for the same
Felix types in the client.

So you more or less have to use Felix types which are bindings to
types defined in C, and share both the bindings between the library
and client, AND the C headers.

Some relief may be available by exporting types (you can do that too),
but type exports are just typedefs in the felix generated C++ *.hpp
file. The machinery above does NOT use the generated *.hpp header
file (the interface is self contained up to the Felix RTL)

(2) If you export a Felix function with "fun" instead of "cfun", the wrapper
requires a thread frame pointer for the library. In the the generated
interface I CHEAT:

  fun setup2 : int -> int = "setup2(ptf,$1)"
    requires
      property "needs_ptf",
      header
       """
       extern "C" FLX_IMPORT int setup2(void *, int);
       """
  ;

Here the type pass in is void * which accepts anything.
That is NOT the correct type, the correct type is actually

        flxusr::xt::thread_frame_t *

but we have no access to that. So instead, I am just passing the
client's thread frame pointer "ptf". The requires property "needs_ptf"
annotation ensures it exists. That thread frame agrees with all others
as far as the common initial fields go, which includes the GC and
program arguments (and some standard files, although at present println
etc use ::std::cout instead of the ones actually passed in).

I any procedure in the library you call through the interface actually tries to 
access
any variable (read or write) in the thread frame all hell will break lose 
(because
we cheated and passed in the wrong one).

If you really wanted to create a thread frame for the library you could, but 
because
of the cheat .. there's no way to pass it. Plugins do this. I may have to fix it
so you can either cheat or not... :) :)

The point of the cheat is to allow the GC to be used, even from C calls.
After all the GC is just an ordinary C library itself. (C++ actually but lets
not pick knits here).

Note that the file xt.hpp generated is already a precise interface for the 
library
but it contains cruft. It should be usable from C++, but there's no way
you could publish it in a Debian package as a normal C library!

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




------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&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