MY BUG
=======

I had a serious problem with the dependency checking appearing to
fail when compiling the build system tool flx_build_rtl.

This was a nasty problem because the make file says

        build/release/host/bin/flx --test=build/release \
                build/release/src/tools/flx_build_rtl --target=build/release 
--build-flx

which has the effect of building both flx and flx_build_rtl, both of which are 
active ("busy")
during the build. Actually I don't know how OSX handles writing to an active 
executable,
and I know even less how it works if the target is an active shared library!

However, because I'm building a static link executable but I'm RUNNING 
a Felix program, the executable being run to create itself (flx_build_rtl)
is in the cache, not the host bin directory. It's not clear why, given this
method, there's any point at all actually building it!

In any case, I got confused for a long time over stuff rebuilding when it
shouldn't, or failing to build when it should.

THE CAUSE
==========

What it turned out to be was that there are three flx programs!
The program "bootflx" is generated by Python. The reason for this
is so that you can run bootflx to generate flx (without overwriting
the executable). bootflx is compiled with the standard toolchains
included as source.

There are also two versions of flx: the one called 'dflx' is a standard
executable with no preloaded toolchains, so it requires the plugins
to be already built. But we need flx to build these plugins. When bootstrapping
we can use bootflx, but this only works on the host with the standard 
toolchains.

Just to confuse you: two platforms characterise a build tool, the host
environment in which it is run, and the target for which it generates
output. In Felix, the target "host" has "host" as both the host environment
and the target. However consider this: suppose the host environment
is 32 bit Windows, then we get everything up and running.

But now, we want to run under 64 bit windows. So we need to build
32 bit plugins that generate 64 bit output. We can build a Felix target
that does this from the 32 bit hosted 32 bit target environment.
Then, we switch to the 64 bit environment, and build another set
of tools, this time hosted in 64 bit environment generating code
for a 64 bit environment.

Confused? Yep! The point is we need THREE toolchains:

        32->32
        32->64
        64->64

32 bit flx can run the first two toolchains and build all three,
which allows generating a 64 bit flx which we can then be used
to rebuild the 64->64 system from then on.

Ok, so  all of this is to explain why I'm confused because although I am
NOT changing the environment, I have two versions of everything:
the old stuff and the new. The new stuff tends to scrub the old stuff
so the build order is rather critical, and afterwards there's some stuff
that needs to be built again (even though it's probably right, it was built
with the old tools). Very confusing!

Ok, so we also have flx, which is the same as dflx except it preloads
the standard toolchain plugins. Note this is NOT the same as bootflx!!!
Bootflx includes the standard toolchains at source level, whereas flx
requires compiling the toolchains as object files and then linking
them with the dflx object file and a stub loader that sets up the
preload dictionary then calls dflx "as if" Felix had done it directly.
bootflx stores symbols in the preload dictionary too, but no linking
is required because they're compiled in as source.

BUT .. the ACTUAL cause of the problem was much simpler
than all the confusion, and the hint is above.

I was generating "dflx" twice. First I was making an executable.
Later when building flx, I generated an object file. The first step
actually generates an object file too, but it is hidden in the cache.
The second step explicitly names the object file so it can be linked
into flx.

BUT the dependency file *.dep is based on the Felix source file
location NOT the output location. So the (same) dependency file
got generated twice. When I tried to repeat the process, the dependency
file was newer than the dflx executable so it got rebuilt, also re-running
flxg which generated the dependency file again. So now it is newer than
the second object file as well and it also gets built again (regenerating
the dependency file yet again).

THE FIXES
=========

Two fixes were required. First, I removed "dflx". It's only purpose is to
force the dynamic loading of a toolchain plugin, so you cannot
accidentally use the wrong one. flx will use a preloaded version
if it can, which has the nasty side effect that if you modify the
plugin, flx will keep using the old toolchain (because it's statically
linked in). Sometimes that's useful (if you stuff up, there's some chance
you can still use flx to fix the bad plugin since it doesn't actually load it).

Removing dflx eliminated the duplicate dependency file generation,
but it wasn't enough!

The second fix, just committed, splits the dependency checking
into two independent parts. The first part checks if flxg needs 
to be run, by checking if the dependency file itself is older than
any of the files it lists. This always includes the Felix base source file,
so if you change that, or any of the OLD dependencies, flxg will be called.
Note this will NOT work if you change the search path, you have to use
the --force switch for that at the moment. 

The second check compares the binary with the dependency file.
If the binary is older, we  have to recompile the C++ sources.

So now, I hope, the build is semi-workable. It doesn't cope with building
the same sources in two distinct ways entirely properly, but it should work
reasonably well even in that case, because the output from flxg is more
or less independent of almost everything. Note changes to the compiler
or grammar should force the whole cache to be scrubbed so we shouldn't
have to worry about an improper dependency file (it won't exist).

Exceptions: changes to the include search path, imports, inlining level,
debug comments in the sources, (and library used ?) will not be detected
at present. You will have to use the --force (or --force-compiler) switch.
These exceptions are rare enough not to bother about them yet.
Normally Felix programming doesn't change any of this stuff.
It is common (for me) to change the install directory, however this should
trigger a wipe out of the cache (even, it seems, if the testing directory
is installed, and everything in both is identical .. not sure why! However
install deliberately wipes the cache).

SImilarly, and perhaps more critically, changes to C++ compilation options
will not be detected. If you put -O2 to override the default optimisation,
the C++ sources won't be regenerated and neither will the dependency
file. So you won't get a C++ recompile. You can use --force --nofelix 
to fix this (avoiding running flxg but still forcing C++ compilation).

COMING
=======

Now the Felix compilation is working reasonably well, in the sense
I can rebuild the whole system and only things that changed get
rebuilt, its time to fix the problem that actually generating the RTL
requires a very LONG set of C++ compilations which are forced
every time.

To fix this, I'm using gcc -M -MFfile.d kind of thing to generate
an *.d file which contains a "make" readable dependency specification
generated by the C/C++ pre-processor.

We will then parse this file, and then find the time of the newest file
in the dependency list and compare it with the compiler target.
If it is older, we can skip the compilation.

That's ROUGHLY!  A new post for the messy details!

However, the point to note is that I intend to build this in at a low
enough level eventually that the C/C++ compilation toolchains
automatically do dependency checking and avoid running
the C++ compiler if it isn't necessary. We will still need a force
option because command line arguments can screw the logic up.

When this is working, you will be able to compile arbitrary C++ with
flx, using stub Felix program. The only caveat here will be you cannot
have a main() function if statically lining (because Felix provides that!).
So you'll have to rename it c_main or cxx_main or something.
Can be done by a stub file:

        // new program suitable for Felix
        #define main cxx_main
        #include "oldprogram.cpp"

[provided you don't have any methods named main, or any main functions
in non global namespace .. ]

The only reason for requiring a Felix stub is that flx command line parsing
splits off the program name from any arguments to pass to it by detecting:

        a filename without an extension
        a filename with .flx extension

So the issue is entirely related to the command line parser: you have
to say:

        flx myprog.cpp dummy.flx argument

because without the dummy.flx, argument is taken as the program!

Actually Felix convention is:

        *.cpp, *.c : a library file
        *.cxx, *.cc  : a mainline (containing main function)

however this isn't universally accepted and a lot of C++ programmers use
*.cc to mean a C++ file (not a c mainline).

I will sort this out somehow, but first to get the stub variation working.

Note that Felix ALREADY checks the time stamps of C/C++ files
on the flx command line (it just doesn't check any includes).


--
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