On 26/03/2012, at 12:40 AM, Shayne Fletcher wrote:

CC'd to lists because lots of info here.

Also CC'd to Erick, because if fbuild doesn't work right, he may be
interested in upgrading it.

The bottom lines are:

* this is going to be very hard

* it cannot be done by one or even two people: we need
some more developers because quite a bit of difficult DESIGN
work is required here. It isn't just a matter of a few patches.

* it cannot be done by one person working on Windows
and another separate person working on Posix.

Otherwise the turnaround time for checking changes
work on BOTH platforms will be huge. We will end up
with code that doesn't build on either platform.

Dual booting isn't enough. Someone needs BOTH platforms
running simultaneously with high speed access to the
repository .. ideally on a shared local disk.

This might be done with a hypervisor like Xen or something
that can run both OS together and even share desktop
space. Otherwise another good way is to use Windows
with a X Window as a console to a Linux server.

I used to own two identical desktop machines and ran Linux
on one and Windows on the other. Even that was hard to manage,
even with Samba to share disk: that's probably the only effective
way to do it.

Cygwin can be useful. However a Cygwin build is very tricky.
It is good I think to use Cygwin to run the build process but
still *target* pure Win32/MSCV++. You can run MSVC++
(and any other windows programs) from inside Cygwin.
This gives you bash and all the other build tools.
You can also try a mingw build inside Cygwin to get Felix
running on Windows, but that is only a transient solution
because it is using gcc (mingw port), not MSVC++. 

We definitely want MSVC++ builds in the long run.

> What was it you suggested earlier? Run up ``make build`` from a MinGW`` bash 
> shell and see where it goes?


Yes. 

To build Felix to a useful state you need flx_pkgconfig.
This tool is an essential part of the compilation process.
It gathers information from a database in response to the
*.resh file generated by flxg and generates a #include file
which the C++ code generated by flxg #includes.

flx_pkgconfig itself is written in Felix, and the #include
file required is "pre-calculated" and part of the repository.
All other builds, including the "flx" tool, require flx_pkgconfig.
See
        src/flx_pkgconfig/flx_pkgconfig.includes:

which says:

#include <iostream>
#include "flx_ioutil.hpp"
#include "flx_strutil.hpp"
#include "flx_rtl.hpp"
#include "flx_gc.hpp"

Even if you cannot build flx_pkgconfig under MSVC++ it may help
if you have an executable that works. That way, if you finally
get "flx" to compile and generated buildable code you have
the tool to complete the compilation process.

Secondly, you need to get "flx" to work. In the old days there was
a bash script that did the job, and also a flx.bat file for windows.
Then that got replaced by a Python script. Finally that got replaced
by a program written in Felix itself.

So the second challenge is to get "flx" to build. You do NOT need "flx"
to make Felix programs. You can manually run "flxg" and then
compile the resulting C++ code "by hand" with MSVC++.
It's a pain, but a *.BAT script or Python script that can build flx_pkgconfig
and flx itself under Windows would be very useful.

Flxg itself is written in Ocaml and should compile on Windows.
At least the 32 bit version should compile.

[Last I looked 64 bit Ocaml on Windows had a number of bugs
in the bignum library due to bad coding by Xavier Leroy:
he assumed "long" was 64 bits. On Windows it is only 32 bits.
I put in a ticket but AFAIK it never got fixed. INRIA doesn't care
about Windows :]

The biggest problem you'll have initially is filenames.
Flxg tries to ensure it will work with the native file system,
but without testing it is hard to be sure I didn't use "/"
as a separator in some places instead of Filename.sep.

The filename problem will occur in

fbuild
flxg
flx_pkgconfig
flx

as well as a lot of the library code.

The "general" rule for filenames is this: conceptually all filenames
consist of two parts:

        (a) a native prefix
        (b) a relative file 

The (a) part is 

        * platform dependent
        * always provided by the environment eg command line 
        * never manipulated by any code

For example on Posix:

        /usr/local/lib/felix

and on Windows:

        C:\program files (x86)\felix

The second part of the filename is ALWAYS IN UNIX FORMAT.
All literals in code use Unix relative filenames.

To make a native filename, the UNix part is converted to native
format and prefixed by the native prefix with a separator possibly
stuck in between. You should find some Ocaml code that does this.
However it may not be rigorously applied!

The point here is that any literal filenames in flxg (and possibly
in Felix code as well) if given in Unix format:

        std/list.flx

are correct as written. They should NOT be converted to Windows
filenames as literals. The conversion SHOULD be done by 
the code that adds that file to a prefix. But I may have neglected
to do this in all cases in flxg (Ocaml) and I can *promise* I have
not done it in all the Felix code floating around.

We need to actually review and design a proper filename
handling library. The existing code is minimal (it provides
only Filename::sep and a join function or so, which is NOT
enough: I dont remember but we'll have to sit down and
make the rules.

In theory, strings should NOT be allowed for filenames,
it should be

        Relative_Filename "...." (Unix format)

and

        Native_Filename ... (Windows or Posix depending).
        Windows_Filename...
        Posix_Filename ...
        
and all the functions accepting filenames should require
values of filename type (NOT strings).

IMNSHO (in my not so humble opinion) the correct layout
for a filename is:

        file:///......

i.e. we should use a URI. Of course that would mean

        open("http://....:";)

would eventually have to work :)

You may also have problems with Async I/O (sockets,
event manager using IO completion ports: this USED to work.
A long time ago).

Async I/O is NOT required for flx or flx_pkgconfig, only things that
use sockets of timers need it. But it has to work eventually.

A lot of code uses Posix. For example the file copy program
flx_cp and the listing flx_ls both rely on Posix.

The BIG challenge to get everything working is getting rid of all
the Posix dependencies.

There are three ways to do this. All are required.

The first way is to provide an emulation in C++.
This is already done for semaphores, for example, which Windows
doesn't provide: it provides WaitForSingleObject, and there is code
that uses that to emulate Posix semaphores. 

Where possible, emulations of Posix are the easiest way to solve 
problems, because the Felix code is left unchanged. The only problem
is with the build system, making the emulation libraries, and ensuring
that they get linked in: flx_pkgconfig should handle this if set up 
correctly.

In many cases, Felix uses a C++ abstraction, for example threads
are implemented in C++ in such a way the interface is the same
for Posix or Windows. This is not quite as nice as a Posix emulation,
because an abstraction has to be designed which supports all the
required functionality, and then it has to be implemented for both
Posix and Windows.

A really NASTY example of this is flx_dynload, which provides
dynamic loading abstraction that works on both Posix with dlopen
and Windows with LoadLibrary. Its nasty because the implementations
on Unix also differ a bit (cg Cygwin, OSX). AND because we have to
statically link much code as an alternative .. with the same interface
to the code (it's done with some tricky macros .. :)

The third technique is to use Felix. There are two techniques:

(a) conditional compilation. This SUCKS and should be avoided.
The Faio interface uses this at the moment. Even some parts of the
webserver uses it (and the Windows code isn't written).

Generally, conditional compilation of bits and pieces should be avoided.

(b)  Abstraction.

I think this is the right way. The idea here -- and there's no implementation
using this idea yet -- is to provide a Felix type class with virtual functions,
and provide two instances: one for Windows and one for Posix.

Code (such as webservers) can then just use the abstraction presented
by the class, and we can somehow use a SMALL bit of conditional
compilation to select the appropriate instance.

YOU NEED TO KNOW ABOUT

        lpsrc/flx_maker.pak

This file is the "remnant" of the old interscript based build system.
It is used to generate platform dependent code.
You will find code it generates like:

        build/release/lib/plat/config.flx

all such files say 

        //GENERATED during config

at the top. Ahem actually the most IMPORTANT one doesn't:

        build/release/plat/flx.flxh

which says, on my box:

macro val PLAT_WIN32 = false;
macro val PLAT_POSIX = true;
macro val PLAT_LINUX = false;
macro val PLAT_MACOSX = true;
macro val PLAT_CYGWIN = false;
macro val PLAT_SOLARIS = false;
macro val PLAT_BSD = true;

you can see my platform is POSIX and OSX and BSD -- its a Mac ;(

For windows PLAT_WIN32 should come out true.

Conditional compilation in Felix is done with ORDINARY conditionals:

if PLAT_WIN32 do
        fun basename (x:string) => split (x, "\\");
else
    fun basename (x:string) => split(x,"/";
done

The rule is that if the condition of a conditional is 
a "compile time constant" then the code which is not 
selected is *deleted*. In other words, it doesn't have to
be type correct. It has to parse, that's all.

Sometimes this is a pain: you can write:

        fun basename(x:string) => split(x, 
                if PLAT_WIN32 then "\\" else "/" endif);

for example, but you cannot write

        typedef socket = if PLAT_WIN32 then HANDLE else int endif;

because there only statements and expression have conditionals.
Not patterns, attributes, header or body insertions, etc etc.

Actually types DO have conditionals but I don't think the constant
folder respects them; you can write

typedef socket =
        typematch OS_TYPE with
        | WIN_TYPE => HANDLE 
        | POSIX_TYPE => int
        endmatch
;

and this is a perfectly valid type expression, but it isn't a type
until it is reduced: the constant folder doesn't do type reductions
at the moment. The reduction may be done too late for overloading,
etc, to actually work. 

I could fix this, but it only improves things a bit, maybe perhaps .. :)
You can always just conditionally compile one of two typedefs so it
isn't clear this upgrade is worthwhile. 

Note I am looking for a way to make this stuff work WITHOUT
coarse conditional compilation. That is, something like:

        typedef socket = int when POSIX;
        typedef socket = HANLE when WIN32;

This is still conditional compilation, but it is not as crude a gross
if/do/else/done construction: it's more like "guarded code" and
similar to the

        requires tag

clauses, only instead of yanking in dependencies based on use,
it selects code based on environment. I've been looking for
a way to do this nicely for some time!

The hard bit here is that it isn't just POSIX vs WINDOWS.
The environment is factored in a complex way (see above,
I run POSIX OSX BSD. And also POSIX has option XSI
(X/Open extensions, mainly from BSD).

YMMV :)

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




------------------------------------------------------------------------------
This SF email is sponsosred by:
Try Windows Azure free for 90 days Click Here 
http://p.sf.net/sfu/sfd2d-msazure
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to