I decided some time ago to "factor" the build tools so they compile
a lot faster. On my old Macbook pro, it takes ages to compile
the build tools themselves. Chucking some stuff out of the 
auto included parts of the std library helped but more radical
action is needed. 

So here's an experiment that worked to stage 1.

Most of the build tools use flx_pkgconfig. In the old days this
was a stand alone program called using popen(). Argument
passing by shells isn't reliable though, and it's tricky to ensure
the executable can be found on the path. 

Compiling the sources into the code with include directives
 is more certain .. but much slower! This technique refactors
the old program into two parts: a library class in an include
file in the library, which contains all the logic, and a stub
executable in tools directory which just calls it passing
#System::args as arguments. Now we have, more or less
transparently, obtains a library function as well as an executable.
*Most* of the tools are built this way, so for example the 
functionality of the executable

        flx_cp

can be called under program control with proper type checking,
but will have the same effect. Because the executable was original
and the library function new, the build system will remain unchanged
building the executable, however calls to popen to invoke it in
programs must be modified to use the programatic interface.


This situation is more complicated with the tool I'm looking at first:
flx_pkgconfig. Here, flx and the build tools are converted to the
programatic interface, however the executable is special because
it is used by the Python build to build flx. This means the standard
build of flx_pkgconfig must be simple (since I don't really know how
to change the fbuild system to do complex things emulating flx
and I can't actually use flx because it isn't built yet).

So as an experiment what I did was copy 

        src/lib/std/felix/flx_pkgconfig.flx -> fpclib.flx

Then I commented out the code doing queries using object FlxPkgConfigQuery
to simplify the situation. Then I took at the function in class FlxPkgConfig:

        gen flx_pkgconfig_impl (args:list[string]) : int * list[string] =

which I would like to export. Only I cannot do that, because it returns a tuple,
and tuples cannot cross compilation boundaries easily. So I did this instead:

class FlxPkgConfig
{
  open Lexer;
  export struct flx_pkgconfig_return {
    int return_code;
    list[string] result;
  };

  export gen flx_pkgconfig_exported (args:list[string]) : flx_pkgconfig_return 
= 
  {
    var r = flx_pkgconfig args;
    return flx_pkgconfig_return (r.0, r.1);
  }

  gen flx_pkgconfig (args:list[string]) : int * list[string] = .....

That is, I added a struct to replace the tuple, and exported it.
Then I made an export version of the original function.
Now we compile with:

flx -c --force --staticlib --od . fpclib

This adds three files to the current directory:

~/felix>ls fpclib*
fpclib.a                fpclib.flx              fpclib.hpp              
fpclib_interface.flx


To use this I wrote this client, fpcc.flx:

///////////
include "./fpclib_interface";
var r = fpclib_interface::flx_pkgconfig_exported(#System::args);
var return_code, result = r.return_code, r.result;


print$ strip$ cat ' ' result; endl;
System::exit return_code;
////////////////

which I compile and link with

flx --static -c -od . fpclib.a fpcc

and now I can test with:

~/felix>./fpcc --path=build/release/host/config --list ld faio dl
faio dl

Yea! It works!

You can also build the library with and link with:

--staticlib             --> fpclib.a
--nolink                        --> fpclib.os
 --static --nolink      --> fpclib.o
[no option]             --> fpclib.dylib (on OSX). 

I don't actually know what the last thing does but it is unlikely
to work on Linux with fpclib.so unless you put it in the LD_LIBRARY_PATH:
OSX uses absolute filenames for dylibs so it also won't work if you move
the library, unless you put it in the DYLD_LIBRARY_PATH.

<rant>
Note the confusion here (and everywhere with crappy x86_64 ABI)
between static link code and -fPIC code. --staticlib implies --static
but it probably shouldn't. Archives can contain both PIC and non PIC
code. Static linkage (on OSX at least) works fine against both PIC
and non PIC code. Dynamic libraries, however, require PIC code.
non-PIC is supposedly faster. Apple is removing non-PIC code
in newer OSX versions, because of the confusion created by the demands
of archaic OS technology.
</rant>

With some trivial wrapping in a header file, we can do this: any program
doing this:

        include "std/felix/flx_pkgconfig";
        ...
        var return_code, result = FlxPkgConfig::flx_pkgconfig (... )

can be modified to use the new wrapper, by simply replacing the include
and the call. in fact, with some risk, the call can be wrapped so it works
without modification, and only the include needs changing.

Note that at present Felix syntax doesn't allow you to export an object.
I will have to fix that! Also note, objects return records, which cannot
be exported. What a pain! We'll have to use a cast. So there is a bit
of fiddling to refactor our build tools to *link* a shared flx_pkgconfig
instead of compiling the source every time, but it will significantly
reduce compile times. Trickily this will work for "flx" too because
the Python build does NOT build flx, it builds instead "bootflx" which 
is copied to flx. Bootflx does everything by source inclusion.
Takes ages to build, but only have to be done once when bootstrapping.

There is one further lesson here. There are two problems to note:

1. I originally tested the various kinds of output (object, dylib, archive)
for linkage by removing all the products from the library compilation
in the current directory and got a shock when I realised --staticlib
didn't produce fpclib_interface.flx. Dang, a bug! Only it isn't.
flx is too smart. It uses the C++ from the previous compile and
doesn't generate the interface because flxg does that as a side
effect. If you don't call flxg, the interface isn't generated. The --force
flag fixed that. It's a bug in the dependency checking I probably
won't fix until there are more complaints :)

2. The linkage requires including the library binary file name
on the command line: fpclib.a, fpclib.o, fpclib.os, fpclib.dylib.
All these are platform dependent names, so build scripts
will have to be customised for the OS. That's no good!
The -ox and -od switches were introduced precisely to avoid
platform dependent extensions.

I will note also our output library would normally be 

        libfpclib.a  .. etc

to use with

        -lfpclib

on Unix. This DOES matter in general because with linkers like
Unix ld placing an archive on the command line does not search
the library, it links the whole library in (AFAIK). So I need to figure
a way to fix that .. :)


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




------------------------------------------------------------------------------
CenturyLink Cloud: The Leader in Enterprise Cloud Services.
Learn Why More Businesses Are Choosing CenturyLink Cloud For
Critical Workloads, Development Environments & Everything In Between.
Get a Quote or Start a Free Trial Today.
http://pubads.g.doubleclick.net/gampad/clk?id=119420431&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