Package: src/packages/toolchain.fdoc

C and C++ toolchains

key file
flx_find_cxx_packages.flx $PWD/src/tools/flx_find_cxx_packages.flx
flx_gen_cxx_includes.flx $PWD/src/tools/flx_gen_cxx_includes.flx
key file
toolchain_config.flx share/lib/std/felix/toolchain_config.flx
toolchain_interface.flx share/lib/std/felix/toolchain_interface.flx
flx_cxx.flx share/lib/std/felix/flx_cxx.flx
flx_depchk.flx share/lib/std/felix/flx/flx_depchk.flx
flx_mklib.flx share/lib/std/felix/flx_mklib.flx
key file
gcc_linux.flx share/lib/std/felix/toolchain/gcc_linux.flx
gcc_macosx.flx share/lib/std/felix/toolchain/gcc_macosx.flx
clang_linux.flx share/lib/std/felix/toolchain/clang_linux.flx
clang_macosx.flx share/lib/std/felix/toolchain/clang_macosx.flx
clang_iOS_generic.flx share/lib/std/felix/toolchain/clang_iOS_generic.flx
msvc_win.flx share/lib/std/felix/toolchain/msvc_win.flx
cygwin.fpc $PWD/src/config/cygwin.fpc
cygwin.flx share/lib/std/cygwin/cygwin.flx
key file
toolchain_gcc_linux.flx share/lib/plugins/toolchain_gcc_linux.flx
toolchain_gcc_macosx.flx share/lib/plugins/toolchain_gcc_macosx.flx
toolchain_clang_linux.flx share/lib/plugins/toolchain_clang_linux.flx
toolchain_clang_macosx.flx share/lib/plugins/toolchain_clang_macosx.flx
toolchain_iphoneos.flx share/lib/plugins/toolchain_iphoneos.flx
toolchain_iphonesimulator.flx share/lib/plugins/toolchain_iphonesimulator.flx
toolchain_msvc_win.flx share/lib/plugins/toolchain_msvc_win.flx
flx_plugin.flx share/lib/plugins/flx_plugin.flx
key file
build_flx_rtl_gcc_linux.fpc $PWD/src/config/build_flx_rtl_gcc_linux.fpc
build_flx_rtl_gcc_macosx.fpc $PWD/src/config/build_flx_rtl_gcc_macosx.fpc
build_flx_rtl_clang_linux.fpc $PWD/src/config/build_flx_rtl_clang_linux.fpc
build_flx_rtl_clang_macosx.fpc $PWD/src/config/build_flx_rtl_clang_macosx.fpc
build_flx_rtl_clang_iphoneos.fpc $PWD/src/config/build_flx_rtl_clang_iphoneos.fpc
build_flx_rtl_msvc_win.fpc $PWD/src/config/build_flx_rtl_msvc_win.fpc

Find C++ packages.

Doesn’t really belong here but had to go somewhere!

Scans a C or C++ files and produces a list of required packages on standard output. To be redirected to a *.resh file.

Felix compiler generates *.resh file for Felix generated C++, and puts the #include “filename.includes” into filename.hpp. For C++ only builds, the user has to put the #include in themselves. The resulting C++ won’t work. This tool makes the filename.resh file which can then be fed to flx_pkgconfig along with a request for the include field, to help generate the include file.

//[flx_find_cxx_packages.flx]

// FIXME: this function cut and paste from flx.fdoc
// hidden inside an object

  fun find_cxx_pkgs (src:string) : list[string] =
  {
    //eprintln$ "[flx_find_cxx_pkgs] Scanning " + src + " for package requirements";
    var out = Empty[string];
    var pat = RE2('.*@requires package ([A-Za-z][A-Za-z0-9_-]*).*');
    var f = fopen_input_text src;
    if valid f do
      for line in f do
        var result = Match (pat,line);
        match result do
        | #None => ;
        | Some v => out = v.1  + out;
        done
      done
      fclose f;
    else
      eprintln("Can't find C++ source file " + src);
      System::exit(1);
    done
    out = rev out;
    //if out != Empty[string] call
    //  eprintln$ "[flx_find_cxx_packages] C++ file "+src+" requires packages " + str (out);
    return out;
  }



var filename = System::argv_dflt 1 "";
if filename == "" do
  println$ "Usage: flx_find_cxx_packages filename.cxx > filename.resh";
  System::exit 1;
done

var pkgs = find_cxx_pkgs filename;

for pkg in pkgs perform println$ pkg;
//[flx_gen_cxx_includes.flx]
include "std/felix/flx_pkgconfig";

var pkgconfig_flags = tail #System::args;
//println$ "Args to flx_gen_cxx_includes=" + pkgconfig_flags.str;

var infile = stdin;
var pkgdata = load infile;
var pkgs = split (pkgdata, "\n");
pkgs = filter (fun (x:string) => x != "") pkgs;
//for pkg in pkgs perform println$ "PKG=" +  pkg;
//var err, result = System::get_stdout("flx_pkgconfig " + cat " " pkgconfig_flags + " --field=includes " + cat " " pkgs);
var allargs = pkgconfig_flags + "--field=includes" + pkgs;
//println$ "Calling flx_pkgconfig with args = " + allargs.str;
var err,result = FlxPkgConfig::flx_pkgconfig(allargs);

if err == 0 do
  //println$ "Result = " + result;
  //var files = split (result," "); // won't work on Windows well ... spaces .. ugg
  var files = result;
  for file in files perform println$ "#include " + file;
else
  eprintln$ "Error " + err.str + " running flx_pkgconfig";
done

Toolchain support

//[toolchain_config.flx]

typedef toolchain_config_t = (
  c_compiler_executable: string,
  cxx_compiler_executable: string,
  header_search_dirs: list[string],
  macros : list[string],
  library_search_dirs: list[string],
  ccflags: list[string],
  dynamic_libraries: list[string],
  static_libraries: list[string],
  debugln : string -> void
);
//[toolchain_interface.flx]
interface toolchain_t {
  whatami : 1 -> string;
  host_os : 1 -> string;
  target_os : 1 -> string;
  cxx_compiler_vendor : 1 -> string;

  // Note: this information is available for
  // the host platform in the Filename class.
  // and for any platform using the Filename_class[os]
  // class. The methods below, however, reflect a cross-compilation
  // target filesystem. For example, on Linux with shared libs .so
  // you can target Windows with shared libs .dll if you have a
  // cross compiler.
  //
  // This toolchain facility should be separated from
  // the compiler object, even though the extensions are primarily
  // about compiler product file names, because other tools may wish
  // to assist building by, for example, deleting all object files.
  // Currently you'd have to instantiate a toolchain object to find
  // this information, needlessly providing dummy header files,
  // macros, etc, which are primarily useful to compilers.
  dependency_extension: 1 -> string;
  executable_extension : 1 -> string;
  static_object_extension: 1 -> string;
  dynamic_object_extension: 1 -> string;
  static_library_extension: 1 -> string;
  dynamic_library_extension: 1 -> string;
  pathname_separator : 1 -> string;
  get_base_c_compile_flags: 1 -> list[string];
  get_base_cxx_compile_flags: 1 -> list[string];

  cxx_dependency_generator : (src:string) -> int * string;
  c_dependency_generator : (src:string) -> int * string;
  dependency_parser : string -> list[string];

  cxx_static_object_compiler : (dst:string,src: string) -> int;
  cxx_static_library_object_compiler : (dst:string,src: string) -> int;
  c_static_object_compiler : (dst:string,src: string) -> int;
  static_library_linker : (dst:string,srcs:list[string]) -> int;
  static_executable_linker : (dst:string,srcs:list[string]) -> int;
  dynamic_executable_linker : (dst:string,srcs:list[string]) -> int;

  cxx_dynamic_object_compiler : (dst:string,src: string) -> int;
  c_dynamic_object_compiler : (dst:string,src: string) -> int;
  dynamic_library_linker : (dst:string,srcs: list[string]) -> int;

  debug_flags : 1 -> list[string];
}

Generic C/C++ compiler

For compilers with a gcc like command line interface: gcc and clang basically.

//[flx_cxx.flx]
class CxxCompiler
{
  typedef cxx_dep_spec_t =
  (
    CCDEP: string,
    CCFLAGS: list[string],
    INCLUDE_DIRS: list[string],
    MACROS: list[string],
    debugln: string -> 0
  );
  fun mkinc (s:string) => "-I" + s;
  fun mkincs (ss:list[string]) => map mkinc ss;

  fun mkmac (s:string) => "-D" + s;
  fun mkmacs (ss:list[string]) => map mkmac ss;

  //---------------------------------------------------------------
  // Generating #include dependencies
  //---------------------------------------------------------------

  gen generic_cxx_gen_deps (spec: cxx_dep_spec_t) (src:string) : int * string =
  {
    var cmd=
      spec.CCDEP !
      spec.CCFLAGS +
      mkincs spec.INCLUDE_DIRS +
      mkmacs spec.MACROS +
      src
    ;
    var CMD = catmap ' ' Shell::quote_arg cmd;
    spec.debugln$ "C++ generate dependencies : " + CMD;
    var result, data = System::get_stdout(CMD);
    if result != 0 do
      eprintln $ "C++ command="+CMD + " FAILED";
    done
    return result, data;
  }

  // parse the "make" file generated by gcc -M
  // GIGO: this routine can't fail, but it can return rubbish
  gen generic_dependency_parser (data:string) : list[string] =
  {
    var pcolon = match find (data ,':') with | Some i => i+1uz | #None => 0uz;
    var txt = data.[pcolon to];
    txt = search_and_replace (txt,'\\\n','');
    var files = respectful_split txt;
    files = unbox (map Directory::mk_absolute_filename files);
    return files;
  }

  //---------------------------------------------------------------
  // Compiling object files for dynamic links
  //---------------------------------------------------------------

  typedef cxx_dynamic_spec_t =
  (
    CCOBJ_DLLIB: string,
    CCFLAGS: list[string],
    INCLUDE_DIRS: list[string],
    MACROS: list[string],
    SPEC_OBJ_FILENAME:string,
    debugln: string -> 0
  );

  gen generic_cxx_compile_for_dynamic (spec: cxx_dynamic_spec_t) (src:string, dst:string) : int =
  {
    var cmd=
      spec.CCOBJ_DLLIB !
      spec.CCFLAGS +
      mkincs spec.INCLUDE_DIRS +
      mkmacs spec.MACROS +
      src
    ;
    var CMD = catmap ' ' Shell::quote_arg cmd + ' ' +
      (spec.SPEC_OBJ_FILENAME+Shell::quote_arg dst)
    ;
   spec.debugln$ "C++ compile: " + CMD;
    var result = System::system(CMD);
    if result != 0 do
      eprintln $ "C++ command="+CMD + " FAILED";
    done
    return result;
  }


  //---------------------------------------------------------------
  // Compiling object files for static links
  //---------------------------------------------------------------

  typedef cxx_compile_static_t =
  (
    CCOBJ_STATIC_LIB:string,
    CCFLAGS:list[string],
    INCLUDE_DIRS:list[string],
    MACROS:list[string],
    SPEC_OBJ_FILENAME:string,
    debugln: string -> 0
  );

  gen generic_cxx_compile_for_static
    (spec:cxx_compile_static_t)
    (src:string, dst:string) : int =
  {
    var cmd=
      spec.CCOBJ_STATIC_LIB !
      spec.CCFLAGS +
      mkincs spec.INCLUDE_DIRS +
      mkmacs spec.MACROS +
      src
    ;
    var CMD = catmap ' ' Shell::quote_arg cmd + ' ' +
      (spec.SPEC_OBJ_FILENAME+Shell::quote_arg dst)
    ;

    spec.debugln$ "C++ command="+CMD;
    var result=System::system(CMD);

    if result != 0 do
      eprintln$ "C++ compilation "+src+" failed";
    done
    return result;

  }


  //---------------------------------------------------------------
  // Making a shared library or DLL
  //---------------------------------------------------------------

  typedef link_lib_dynamic_spec_t =
  (
    CCLINK_DLLIB: string,
    CCFLAGS: list[string],
    EXT_SHARED_OBJ:string,
    SPEC_EXE_FILENAME: string,
    LINK_STRINGS: list[string],
    debugln: string -> 0
  );

  gen generic_link_lib_dynamic
    (spec:link_lib_dynamic_spec_t)
    (cppos: list[string],
    LINKER_OUTPUT_FILENAME:string)
  : int =
  {
    var cmd =
      spec.CCLINK_DLLIB !
      spec.CCFLAGS +
      cppos
    ;
    // This weird shit is because Unix use -o filename (space)
    // But Windows uses /Fefilename (no space)
    var CMD = catmap ' ' Shell::quote_arg cmd + ' ' +
      spec.SPEC_EXE_FILENAME+Shell::quote_arg LINKER_OUTPUT_FILENAME+ ' ' +
      catmap ' ' Shell::quote_arg spec.LINK_STRINGS
    ;
    spec.debugln$ "Link command="+CMD;
    var result = System::system(CMD);
    if result != 0 do
      eprintln $ "Dynamic link command="+CMD + " FAILED";
    done
    return result;
  }


  //---------------------------------------------------------------
  // Making a executable which uses shared libraroes
  //---------------------------------------------------------------

  typedef generic_link_exe_dynamic_t =
  (
    CCLINK_STATIC: string, // yeah, weird, but it means linker for executables ..
    CCFLAGS: list[string],
    SPEC_EXE_FILENAME: string,
    LINK_STRINGS: list[string],
    debugln: string->0
  );

  gen generic_link_exe_dynamic
    (spec:generic_link_exe_dynamic_t)
    (cppos:list[string], LINKER_OUTPUT_FILENAME:string) : int =
  {
/*
println$ "[generic_link_exe_dynamic] cppos=" + cppos.str;
println$ "[generic_link_exe_dynamic] link strings=" + spec.LINK_STRINGS.str;
*/
    var CMD =
        Shell::quote_arg spec.CCLINK_STATIC + ' ' +
        catmap ' ' Shell::quote_arg spec.CCFLAGS + ' ' +
        (spec.SPEC_EXE_FILENAME+Shell::quote_arg(LINKER_OUTPUT_FILENAME)) + ' ' +
        catmap ' ' Shell::quote_arg cppos + ' ' +
        catmap ' ' Shell::quote_arg spec.LINK_STRINGS
    ;

    spec.debugln$ "Link command="+CMD;
    var result=System::system(CMD);
    if result != 0 do
      eprintln$ "Link command="+CMD+ " FAILED";
    done
    return result;
  }

  //---------------------------------------------------------------
  // Making a fully linked statically executable
  //---------------------------------------------------------------

  typedef generic_link_exe_static_t =
  (
    CCLINK_STATIC: string,
    CCFLAGS: list[string],
    SPEC_EXE_FILENAME: string,
    LINK_STRINGS: list[string],
    debugln: string->0
  );

  gen generic_link_exe_static
    (spec:generic_link_exe_static_t)
    (cppos:list[string], LINKER_OUTPUT_FILENAME:string) : int =
  {
    var CMD =
        Shell::quote_arg spec.CCLINK_STATIC + ' ' +
        catmap ' ' Shell::quote_arg spec.CCFLAGS + ' ' +
        (spec.SPEC_EXE_FILENAME+Shell::quote_arg(LINKER_OUTPUT_FILENAME)) + ' ' +
        catmap ' ' Shell::quote_arg cppos + ' ' +
        catmap ' ' Shell::quote_arg spec.LINK_STRINGS
    ;

    spec.debugln$ "Link command="+CMD;
    var result=System::system(CMD);
    if result != 0 do
      eprintln$ "Link command="+CMD+ " FAILED";
    done
    return result;
  }

  //---------------------------------------------------------------
  // Making a library archive
  //---------------------------------------------------------------
  typedef generic_lib_static_t =
  (
    CCLINK_STATIC_LIB: string,
    CCFLAGS : list[string],
    SPEC_LIB_FILENAME: string,
    debugln: string->0
  );

  gen generic_static_library
    (spec:generic_lib_static_t)
    (cppos:list[string], LINKER_OUTPUT_FILENAME:string) : int =
  {
    var CMD =
        Shell::quote_arg(spec.CCLINK_STATIC_LIB) + ' ' +
        catmap ' ' Shell::quote_arg spec.CCFLAGS + ' ' +
        (spec.SPEC_LIB_FILENAME+Shell::quote_arg(LINKER_OUTPUT_FILENAME)) + ' ' +
        catmap ' ' Shell::quote_arg cppos
    ;

    spec.debugln$ "Library archive command="+CMD;
    var result=System::system(CMD);
    if result != 0 do
      eprintln$ "Library archive command="+CMD+ " FAILED";
    done
    return result;
  }


}

Dependency Checker

The dependency checker is used to examine a single C or C++ source file and check if the file, or any of dependencies, has changed. To do this it records a dependency file with a “.d” suffix as its output which lists all the files which are depended on as well as the command line switches used to invoke the compiler. The dependent file list is generated by the underlying compiler, which must support this ability.

//[flx_depchk.flx]
include "std/felix/toolchain_interface";

  gen cxx_depcheck (tc: toolchain_t, src:string, dst:string) : bool =
  {
    fun == (a:list[string], b:list[string]) =
    {
      match a,b with
      | #Empty,Empty => return true;
      | Cons (h1,t1), Cons (h2,t2) =>
         if h1 != h2 do
           return false;
         done
         return t1 == t2; // tail call
      | _ =>return false;
      endmatch;
    }

    fun maxf (t:double) (f:string) => max (t, FileStat::dfiletime (f, #FileStat::future_time));

    var new_switches = cat ' ' #(tc.get_base_cxx_compile_flags);

    var result, deps = tc.cxx_dependency_generator (src=src);
    if result != 0 do
      println$ "[flx_depchk] C++ Dependency generator FAILED on " + src;
      return false;
    done
    var newdeps = tc.dependency_parser deps;
    var depfile = dst + ".d";
    var olddeptxt = load depfile;
    var old_switches, olddeps =
      match filter (fun (s:string)=> s != "") (split (olddeptxt,"\n")) with
      | h ! t => h,t
      | _ => "",Empty[string]
    ;

    var samedeps = new_switches == old_switches and newdeps == olddeps;
    //if not samedeps do
    //  println$ "DEPS CHANGED";
    //  println$ "Old deps = " + olddeps.str;
    //  println$ "New deps = " + newdeps.str;
    //done
    save$ depfile, new_switches ! newdeps;
    var fresh = samedeps and #{
      var t = fold_left maxf #FileStat::past_time newdeps;
      return t < FileStat::dfiletime (dst, #FileStat::past_time);
    };
    //println$ "[flx] Output " + dst + " is " + if fresh then "FRESH" else "STALE" endif;
    return fresh;
  }

  gen c_depcheck (tc: toolchain_t, src:string, dst:string) : bool =
  {
    fun == (a:list[string], b:list[string]) =
    {
      match a,b with
      | #Empty,Empty =>  return true;
      | Cons (h1,t1), Cons (h2,t2) =>
         if h1 != h2 do
           return false;
         done
         return t1 == t2; // tail call
      | _ => return false;
      endmatch;
    }

    fun maxf (t:double) (f:string) =>
      max(t, FileStat::dfiletime (f, #FileStat::future_time))
    ;

    var new_switches = cat ' ' #(tc.get_base_c_compile_flags);
    var result, deps = tc.c_dependency_generator (src=src);
    if result != 0 do
      println$ "[flx_depchk] C Dependency generator FAILED on " + src;
      return false;
    done
    var newdeps = tc.dependency_parser deps;
    var depfile = dst + ".d";
    var olddeptxt = load depfile;
    var old_switches, olddeps =
      match filter (fun (s:string)=> s != "") (split (olddeptxt,"\n")) with
      | h ! t => h,t
      | _ => "",Empty[string]
    ;

    var samedeps = new_switches == old_switches and newdeps == olddeps;
    save$ depfile, new_switches ! newdeps;
    var fresh = samedeps and #{
      var t = fold_left maxf #FileStat::past_time newdeps;
      return t < FileStat::dfiletime (dst, #FileStat::past_time);
    };
    //println$ "[flx] Output " + dst + " is " + if fresh then "FRESH" else "STALE" endif;
    return fresh;
  }

Library Builder

Builds a complete library from a flx_pkgconfig database specification. Used by the flx_build_rtl tool.

//[flx_mklib.flx]
include "std/felix/toolchain_config";
include "std/felix/flx_pkg"; // only for "fix2word_flags"
include "std/felix/flx_cp";
include "std/felix/flx/flx_depchk";

class FlxLibBuild
{
  private fun / (x:string,y:string) => Filename::join(x,y);

  noinline gen make_lib
  (
    db: FlxPkgConfig::FlxPkgConfigQuery_t,
    toolchain-maker: toolchain_config_t -> toolchain_t,
    c_compiler_executable: string,
    cxx_compiler_executable: string,
    src_dir:string,
    target_dir:string,
    share_rtl:string,
    pkg:string,
    tmpdir:string,
    static_only:bool,
    debug: bool
  ) () : bool =
  {
    proc dbug (x:string) => if debug call println$ '[make_lib: '+pkg+']' x;

    proc ehandler () {
      eprintln$ "toolchain: make_lib failed, temporary ehandler invoked";
      System::exit 1;
    }


    println$ "------------";
    println$ "Make lib " + pkg;
    println$ "------------";
    var srcdir = db.getpkgfielddflt ehandler (pkg,"srcdir");
    var srcpath = src_dir / srcdir;
println$ "[make_lib] source directory " + srcpath;

    var build_includes= db.getpkgfield ehandler (pkg,"build_includes");
    var result3,ddeps= db.query$ list$ pkg, "--keepleftmost", "--field=requires_dlibs";
    ddeps = FlxPkg::fix2word_flags ddeps;
    var deps = db.getpkgfield ehandler (pkg,"Requires");
    var result,depdlibs =  db.query("--field=provides_dlib"+deps); // packaged dlibs
    var macros = db.getpkgfield ehandler (pkg,"macros");
    var result2,ccflags = db.query$ list$ pkg, "--keepleftmost", "--field=cflags";
    var toolchain_config =
      (
        c_compiler_executable = c_compiler_executable,
        cxx_compiler_executable = cxx_compiler_executable,
        header_search_dirs= list[string] (target_dir, srcpath, share_rtl)+build_includes,
        macros= macros,
        ccflags = ccflags,
        library_search_dirs= list[string] ("-L"+target_dir), // HACK!!!
        dynamic_libraries= ddeps+depdlibs,
        static_libraries= Empty[string],
        debugln = dbug
      )
    ;
    var toolchain = toolchain-maker toolchain_config;
    println$ #(toolchain.whatami);

    // THIS DOES NOT SEEM RIGHT, we're copying headers from share/src
    // into share/lib/rtl
    //
    // previously we copied into host/lib/rtl but that's even wronger
    // because only calculated configuration headers go there
    //
    // the thing is, the share directory is supposed to be read-only,
    // and the files in it immutable, so the contents should already
    // have been put there direct from the repository
    //
    // of course, for add on packages, share may need updating ..
    // its all confusing :)
    //
    // Leave this in there for now because demux is not actually packaged.
    // the fbuild process has put stuff in share already though!

    var headers = db.getpkgfielddflt ehandler (pkg,"headers");
    if headers == "" do headers = r".*\.h(pp)?"; println$ "copying all header files"; done
    var hsrc, hdst = "","";
    match split (headers, ">") with
    | #Empty => ;
    | Cons (h,#Empty) => hsrc = h;
    | Cons (h,Cons (d,#Empty)) => hsrc = h; hdst = d;
    | _ => println$ "Header file too many > characters " + headers;
    endmatch;

    if hdst == "" do hdst = "${0}"; done
    println$ "Copying headers " + hsrc + " > " + hdst;
    CopyFiles::copyfiles (srcpath, hsrc,share_rtl/hdst,true, true);

    var pats = db.getpkgfield ehandler (pkg,"src");
    var pat = catmap '|' (fun (x:string)=>"("+x+")") pats;
  //println$ "Finding Sources in "+srcpath;
  //println$ "Matching pattern "+pat;
    var files = FileSystem::regfilesin (srcpath,pat);
  //println$ "Sources = " + str files;
    if not static_only
    do
      begin
        fun objname (file:string) => let
            dstobj = file.Filename::strip_extension + #(toolchain.dynamic_object_extension) in
            tmpdir/ dstobj
        ;

        for file in files do
          var srcfile = srcpath/ file;
          var dst = objname file;
          Directory::mkdirs (Filename::dirname dst);
          match Filename::get_extension srcfile with
          | x when x == ".cc" or x == ".cpp" =>
            var fresh = cxx_depcheck (toolchain, srcfile, dst);
            if fresh do
              println$ "C++: Up to date [dynamic] " + file " -> " + objname file;
              result = 0;
            else
              println$ "C++: Compiling  [dynamic] " + file " -> " + objname file;
              result = toolchain.cxx_dynamic_object_compiler (src=srcfile, dst=dst);
            done
          | ".c" =>
            fresh = c_depcheck (toolchain, srcfile, dst);
            if fresh do
              println$ "C:   Up to date [dynamic] " + file " -> " + objname file;
              result = 0;
            else
              println$ "C:   Compiling  [dynamic] " + file " -> " + objname file;
              result = toolchain.c_dynamic_object_compiler (src=srcfile, dst=dst) ;
            done

          | x =>
            println$ "Unknown extension " + x;
            goto bad;
          endmatch
          ;
          if result != 0 do
            println$ "Compiler result " + str result;
            goto bad;
          done
        done

        var objs = unbox (map objname files);
        var libname =
          let dlib_root = db.getpkgfield1 ehandler (pkg,"provides_dlib") in
          if prefix (dlib_root,"-l") then "lib"+dlib_root.[2 to]
          elif prefix (dlib_root,"/DEFAULTLIB:") then dlib_root.[12 to]
          else dlib_root
          endif
          +#(toolchain.dynamic_library_extension)
        ;
        var dstlib = target_dir/libname;
        println$ "Dynamic Linking library " + dstlib;
        //println$ "  Source object files = " + objs.str;
        result = toolchain.dynamic_library_linker(srcs=objs, dst=dstlib);
        if result != 0 do
          println$ "Linker result " + str result;
          goto bad;
        done
      end
    done

    begin
      fun objname (file:string) => let
          dstobj = file.Filename::strip_extension + #(toolchain.static_object_extension) in
          tmpdir/ dstobj
      ;

      for file in files do
        var srcfile = srcpath/ file;
        var dst = objname file;
        Directory::mkdirs (Filename::dirname dst);
        match Filename::get_extension srcfile with
        | x when x == ".cc" or x == ".cpp" =>
          var fresh = cxx_depcheck (toolchain, srcfile, dst);
          if fresh do
            println$ "C++: Up to date [static] " + file " -> " + objname file;
            result = 0;
          else
            println$ "C++: Compiling [static] " + file " -> " + objname file;
            result = toolchain.cxx_static_library_object_compiler (src=srcfile, dst=dst);
          done
        | ".c" =>
          fresh = c_depcheck (toolchain, srcfile, dst);
          if fresh do
            println$ "C:   Up to date [static] " + file " -> " + objname file;
            result = 0;
          else
            println$ "C:   Compiling [static] " + file " -> " + objname file;
            result = toolchain.c_static_object_compiler (src=srcfile, dst=dst);
          done
        | x => println$
          "Unknown extension " + x;
          println$ "Compiler result " + str result;
          goto bad;
        endmatch
        ;
        if result != 0 do
          println$ "Compiler result " + str result;
          goto bad;
        done
      done

      var objs = unbox (map objname files);
      var libname =
        let dlib_root = db.getpkgfield1 ehandler (pkg,"provides_slib") in
        if prefix (dlib_root,"-l") then  "lib"+dlib_root.[2 to]
        elif prefix (dlib_root,"/DEFAULTLIB:") then dlib_root.[12 to]
        else dlib_root
        endif
        +#(toolchain.static_library_extension);
      ;
      var dstlib = target_dir/libname;
      println$ "Static Linking Library " + dstlib;
      //println$ "  Source object files = " + objs.str;
      result = toolchain.static_library_linker(srcs=objs, dst=dstlib);
      if result != 0 do
        println$ "Linker result " + str result;
        goto bad;
      done
    end
    return true;
bad:>
    return false;
  }
}

Toolchains

Toolchains for specific vendor compilers and operating system combinations.

Each specific toolchain is an object which implements the toolchain interface.

Object for gcc on Linux

//[gcc_linux.flx]
include "std/felix/toolchain_interface";
include "std/felix/toolchain_config";
include "std/felix/flx_cxx";

object toolchain_gcc_linux (config:toolchain_config_t) implements toolchain_t =
{

  var cxx_compile_warning_flags = list$ "-w",
    "-Wfatal-errors",
    "-Wno-invalid-offsetof",
    "-Wno-parentheses",
    "-Wno-unused-variable",
    "-Wno-unused-label",
    "-Wno-unused-function",
    "-Wno-sign-compare",
    "-Wno-missing-braces"
  ;
  var c_compile_warning_flags = list[string]$ "-w", "-Wfatal-errors";

  var c_compiler = let x = config.c_compiler_executable in if x == "" then "gcc" else x;
  var cxx_compiler = let x = config.cxx_compiler_executable in if x == "" then "g++" else x;
  var linker = cxx_compiler;

  var ccflags_for_dynamic_link = list[string] ("-shared");
  var base_c_compile_flags =
    "-D_POSIX" ! "-g" ! "-c" ! "-O1" ! "-fno-common"
    ! "-fno-strict-aliasing" ! (c_compile_warning_flags+config.ccflags)
  ;
  var base_cxx_compile_flags =
    "-D_POSIX" ! "-g"! "-c" ! "-O1" ! "-fno-common"
    ! "-fno-strict-aliasing" ! "-std=gnu++14" ! (cxx_compile_warning_flags+config.ccflags)
  ;

  method fun whatami () => "toolchain_gcc_linux (version 2)";
  method fun host_os () => "LINUX";
  method fun target_os () => "LINUX";
  method fun cxx_compiler_vendor () => "GNU";

  method fun dependency_extension () => ".d";
  method fun executable_extension () => "";
  method fun static_object_extension () => "_static.o";
  method fun dynamic_object_extension () => "_dynamic.o";
  method fun static_library_extension () => ".a";
  method fun dynamic_library_extension () => ".so";
  method fun pathname_separator () => "/";
  method fun debug_flags () =>list[string] "-g";
  method fun get_base_c_compile_flags () => base_c_compile_flags;
  method fun get_base_cxx_compile_flags () => base_cxx_compile_flags;

// Boilerplate

  method gen c_dependency_generator (spec:(src:string)) =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=c_compiler,
          CCFLAGS = "-MM" ! "-D_POSIX" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen cxx_dependency_generator (spec:(src:string)) =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=cxx_compiler,
          CCFLAGS = "-MM" ! "-D_POSIX" ! "-std=gnu++14" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen dependency_parser (data:string) : list[string] =>
     CxxCompiler::generic_dependency_parser data
  ;

  method gen c_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
  // case 2 of dflt
      (
        CCOBJ_STATIC_LIB = c_compiler,
        CCFLAGS = "-fvisibility=hidden" ! base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen c_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = c_compiler,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = "-fvisibility=hidden" !"-g"! "-c" ! "-O1" ! "-fno-common"! "-fno-strict-aliasing"
          ! "-D_POSIX" ! "-std=gnu++14" ! "-D_GLIBCXX_USE_CXX11_ABI=1"
          ! (cxx_compile_warning_flags+config.ccflags),
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen cxx_static_library_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = "-fvisibility=hidden" ! "-D_GLIBCXX_USE_CXX11_ABI=1"!base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = "FLX_STATIC_LINK"+config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen cxx_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = linker,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! "-D_GLIBCXX_USE_CXX11_ABI=1"! base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen static_library_linker (spec:(dst:string, srcs:list[string])): int =
  {
    var result =
      CxxCompiler::generic_static_library
      (
        CCLINK_STATIC_LIB = "ar",
        CCFLAGS = list[string]("-rcs"),
        SPEC_LIB_FILENAME = "",
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen static_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_static
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.static_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen dynamic_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_dynamic
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen dynamic_library_linker (spec:(dst:string,srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_lib_dynamic
      (
        CCLINK_DLLIB = linker,
        CCFLAGS = ccflags_for_dynamic_link,
        EXT_SHARED_OBJ = #dynamic_library_extension,
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }
}

Object for gcc on OSX

//[gcc_macosx.flx]
include "std/felix/toolchain_interface";
include "std/felix/toolchain_config";
include "std/felix/flx_cxx";

object toolchain_gcc_macosx (config:toolchain_config_t) implements toolchain_t =
{

  var cxx_compile_warning_flags = list$ "-w",
    "-Wfatal-errors",
    "-Wno-invalid-offsetof"
  ;
  var c_compile_warning_flags = list[string]$ "-w","-Wfatal-errors";

  var c_compiler = let x = config.c_compiler_executable in if x == "" then "gcc" else x;
  var cxx_compiler = let x = config.cxx_compiler_executable in if x == "" then "g++" else x;
  var linker = cxx_compiler;

  var ccflags_for_dynamic_link = list[string] ("-dynamiclib");

  var base_c_compile_flags =
    "-g"! "-c" ! "-O1" ! "-fno-common"! "-fno-strict-aliasing" ! (c_compile_warning_flags+config.ccflags)
  ;
  var base_cxx_compile_flags =
    "-g"! "-c" ! "-O1" ! "-std=c++14" ! "-fno-common"! "-fno-strict-aliasing" !(cxx_compile_warning_flags+config.ccflags)
  ;

  method fun whatami () => "toolchain_gcc_macosx (version 2)";
  method fun host_os () => "OSX";
  method fun target_os () => "OSX";
  method fun cxx_compiler_vendor () => "GNU";

  method fun dependency_extension () => ".d";
  method fun executable_extension () => "";
  method fun static_object_extension () => "_static.o";
  method fun dynamic_object_extension () => "_dynamic.o";
  method fun static_library_extension () => ".a";
  method fun dynamic_library_extension () => ".dylib";
  method fun pathname_separator () => "/";
  method fun debug_flags () => list[string] "-g";
  method fun get_base_c_compile_flags () => base_c_compile_flags;
  method fun get_base_cxx_compile_flags () => base_cxx_compile_flags;

// Boilerplate

  method gen c_dependency_generator (spec:(src:string)) =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=c_compiler,
          CCFLAGS = "-MM" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result , data;
  }

  method gen cxx_dependency_generator (spec:(src:string)) =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=cxx_compiler,
          CCFLAGS = "-MM" ! '-std=c++14' ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen dependency_parser (data:string) : list[string] =>
     CxxCompiler::generic_dependency_parser data
  ;

  method gen c_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = c_compiler,
        CCFLAGS = base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen c_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = c_compiler,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen cxx_static_library_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = "FLX_STATIC_LINK" + config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = linker,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen static_library_linker (spec:(dst:string, srcs:list[string])): int =
  {
    var result =
      CxxCompiler::generic_static_library
      (
        CCLINK_STATIC_LIB = "ar",
        CCFLAGS = list[string]("-rcs"),
        SPEC_LIB_FILENAME = "",
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen static_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_static
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.static_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen dynamic_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_dynamic
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }


  method gen dynamic_library_linker (spec:(dst:string,srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_lib_dynamic
      (
        CCLINK_DLLIB = linker,
        CCFLAGS = ccflags_for_dynamic_link,
        EXT_SHARED_OBJ = #dynamic_library_extension,
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }
}

Object for clang on Linux

//[clang_linux.flx]
include "std/felix/toolchain_interface";
include "std/felix/toolchain_config";
include "std/felix/flx_cxx";

object toolchain_clang_linux (config:toolchain_config_t) implements toolchain_t =
{

  var cxx_compile_warning_flags = list$  "-w",
    "-Wfatal-errors",
    "-Wno-invalid-offsetof",
    "-Wno-logical-op-parentheses",
    "-Wno-bitwise-op-parentheses",
    "-Wno-parentheses-equality",
    "-Wno-parentheses",
    "-Wno-return-stack-address",
    "-Wno-tautological-compare",
    "-Wno-return-type-c-linkage",
    "-Wno-unused-variable",
    "-Wno-unused-function",
    "-Wno-c++11-narrowing",
    "-Wno-missing-braces"
  ;
  var c_compile_warning_flags = list[string]$ "-w","-Wfatal-errors";

  var c_compiler = let x = config.c_compiler_executable in if x == "" then "clang" else x;
  var cxx_compiler = let x = config.cxx_compiler_executable in if x == "" then "clang++" else x;
  var linker = cxx_compiler;

  var ccflags_for_dynamic_link = list[string] ("-shared");

  var base_cxx_compile_flags =
     "-std=c++14"! "-g"! "-c" ! "-O1" ! "-fno-common"! "-fno-strict-aliasing" ! (cxx_compile_warning_flags+config.ccflags)
  ;

  var base_c_compile_flags =
     "-g"! "-c" ! "-O1" ! "-fno-common"! "-fno-strict-aliasing" ! (c_compile_warning_flags+config.ccflags)
  ;


  method fun whatami () => "toolchain_clang_linux (version 2)";
  method fun host_os () => "LINUX";
  method fun target_os () => "LINUX";
  method fun cxx_compiler_vendor () => "clang";

  method fun dependency_extension () => ".d";
  method fun executable_extension () => "";
  method fun static_object_extension () => "_static.o";
  method fun dynamic_object_extension () => "_dynamic.o";
  method fun static_library_extension () => ".a";
  method fun dynamic_library_extension () => ".so";
  method fun pathname_separator () => "/";
  method fun debug_flags () => list[string] "-g";
  method fun get_base_c_compile_flags () => base_c_compile_flags;
  method fun get_base_cxx_compile_flags () => base_cxx_compile_flags;

// Boilerplate

  method gen c_dependency_generator (spec:(src:string)) =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=c_compiler,
          CCFLAGS = "-MM" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen cxx_dependency_generator (spec:(src:string)) =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=cxx_compiler,
          CCFLAGS = "-MM" ! "-std=c++14" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen dependency_parser (data:string) : list[string] =>
     CxxCompiler::generic_dependency_parser data
  ;

  method gen c_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = c_compiler,
        CCFLAGS = base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen c_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = c_compiler,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen cxx_static_library_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = "FLX_STATIC_LINK" + config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = linker,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen static_library_linker (spec:(dst:string, srcs:list[string])): int =
  {
    var result =
      CxxCompiler::generic_static_library
      (
        CCLINK_STATIC_LIB = "ar",
        CCFLAGS = list[string]("-rcs"),
        SPEC_LIB_FILENAME = "",
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen static_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_static
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.static_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen dynamic_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_dynamic
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }


  method gen dynamic_library_linker (spec:(dst:string,srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_lib_dynamic
      (
        CCLINK_DLLIB = linker,
        CCFLAGS = ccflags_for_dynamic_link,
        EXT_SHARED_OBJ = #dynamic_library_extension,
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }
}

Object for clang on OSX

//[clang_macosx.flx]
include "std/felix/toolchain_interface";
include "std/felix/toolchain_config";
include "std/felix/flx_cxx";

object toolchain_clang_macosx (config:toolchain_config_t) implements toolchain_t =
{

  var cxx_compile_warning_flags = list$
    "-w", // turn off all the warnings (but not hard errors)
    "-Wfatal-errors", // stop compiling on the first hard error
    "-Wno-return-type-c-linkage",
    "-Wno-invalid-offsetof"
  ;
  var c_compile_warning_flags = list$ "-w",
    "-Wfatal-errors",
    "-Wno-array-bounds"
  ;
  var c_compiler = let x = config.c_compiler_executable in if x == "" then "clang" else x;
  var cxx_compiler = let x = config.cxx_compiler_executable in if x == "" then "clang++" else x;
  var linker = cxx_compiler;

  var ccflags_for_dynamic_link = list[string] ("-dynamiclib");
  var base_c_compile_flags =
    "-g"! "-c" ! "-O1" ! "-fno-common"! "-fno-strict-aliasing" ! (c_compile_warning_flags+config.ccflags)
  ;

  var base_cxx_compile_flags =
    "-g"! "-c" ! "-O1" ! "-fno-common"! "-fno-strict-aliasing" ! "-std=c++14" ! (cxx_compile_warning_flags+config.ccflags)
  ;

  method fun whatami () => "toolchain_clang_macosx (version 2)";
  method fun host_os () => "OSX";
  method fun target_os () => "OSX";
  method fun cxx_compiler_vendor () => "clang";

  method fun dependency_extension () => ".d";
  method fun executable_extension () => "";
  method fun static_object_extension () => "_static.o";
  method fun dynamic_object_extension () => "_dynamic.o";
  method fun static_library_extension () => ".a";
  method fun dynamic_library_extension () => ".dylib";
  method fun pathname_separator () => "/";
  method fun debug_flags () => list[string] "-g";
  method fun get_base_c_compile_flags () => base_c_compile_flags;
  method fun get_base_cxx_compile_flags () => base_cxx_compile_flags;

// Boilerplate

  method gen c_dependency_generator (spec:(src:string)) : int * string =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=c_compiler,
          CCFLAGS = "-MM" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result,  data;
  }

  method gen cxx_dependency_generator (spec:(src:string)) : int * string =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=cxx_compiler,
          CCFLAGS = "-MM" ! "-std=c++14" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen dependency_parser (data:string) : list[string] =>
     CxxCompiler::generic_dependency_parser data
  ;

  method gen c_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = c_compiler,
        CCFLAGS = base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen c_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = c_compiler,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen cxx_static_library_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = "FLX_STATIC_LINK"+config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = linker,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen static_library_linker (spec:(dst:string, srcs:list[string])): int =
  {
    var result =
      CxxCompiler::generic_static_library
      (
        CCLINK_STATIC_LIB = "ar",
        CCFLAGS = list[string]("-rcs"),
        SPEC_LIB_FILENAME = "",
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen static_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_static
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.static_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen dynamic_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_dynamic
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }


  method gen dynamic_library_linker (spec:(dst:string,srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_lib_dynamic
      (
        CCLINK_DLLIB = linker,
        CCFLAGS = ccflags_for_dynamic_link,
        EXT_SHARED_OBJ = #dynamic_library_extension,
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }
}

Cygwin interface.

//[cygwin.flx]
class Cygwin
{
  requires package "cygwin";

  // outputs absolute filenames: src,dst
  private gen p_cygwin_to_win: +char * +char * size -> int =
     "cygwin_conv_path(CCP_POSIX_TO_WIN_A || CCP_ABSOLUTE,$1,$2,$3)"
  ;
  private gen p_win_to_cygwin: +char * +char * size -> int =
    "cygwin_conv_path(CCP_WIN_TO_POSIX)A || CCP_ABSOLUTE,$1,$2,$3)"
  ;

  // This function should ALWAYS work
  fun cygwin_to_win (var s:string) =
  {
     var outbuf : +char;
     var psiz = p_cygwin_to_win (s.cstr,outbuf,0uz);
     outbuf = array_alloc[char] psiz;
     var err = p_cygwin_to_win (s.cstr,outbuf,psiz.size);
     assert err == 0; // hackery!
     var t = string outbuf;
     free outbuf;
     return t;
  }

  // This function has two kinds of output:
  // if the win filename is inside C:/cygwin we get name relative to /
  // if the filename is outside, we get /cygdrive/driveletter/rest-of-path
  fun win_to_cygwin(var s:string) =
  {
     var outbuf : +char;
     var psiz = p_win_to_cygwin(s.cstr,outbuf,0uz);
     outbuf = array_alloc[char] psiz;
     var err = p_win_to_cygwin(s.cstr,outbuf,psiz.size);
     assert err == 0; // hackery!
     var t = string outbuf;
     free outbuf;
     return t;
  }
}

Cygwin config

//[cygwin.fpc]
Descriptrion: Cygwin Dll
provides_dlib: -L/usr/bin -lcygwin
includes: '"sys/cygwin.h"'

Object for MSVC++ on Windows

//[msvc_win.flx]
include "std/felix/toolchain_interface";
include "std/felix/toolchain_config";
include "std/felix/flx_cxx";

object toolchain_msvc_win (config:toolchain_config_t) implements toolchain_t =
{

  var c_compiler = let x = config.c_compiler_executable in if x == "" then "cl" else x;
  var cxx_compiler = let x = config.cxx_compiler_executable in if x == "" then "cl" else x;
  var linker = cxx_compiler;

  var base_c_compile_flags = Empty[string];
  var base_cxx_compile_flags = Empty[string];

  method fun whatami () => "toolchain_msvc_win (version 2)";
  method fun host_os () => "Win32";
  method fun target_os () => "Win32";
  method fun cxx_compiler_vendor () => "microsoft";

  method fun dependency_extension () => ".d";
  method fun executable_extension () => ".exe";
  method fun static_object_extension () => "_static.obj";
  method fun dynamic_object_extension () => "_dynamic.obj";
  method fun static_library_extension () => ".lib";
  method fun dynamic_library_extension () => ".dll";
  method fun pathname_separator () => "\\";
  method fun debug_flags () => list[string] "-g";
  method fun get_base_c_compile_flags () => base_c_compile_flags;
  method fun get_base_cxx_compile_flags () => base_cxx_compile_flags;

  var include_switches = unbox (map (fun (s:string) => "/I"+s) config.header_search_dirs);
  include_switches = include_switches + filter
    (fun (s:string)=> prefix (s,"/I") or prefix (s,"-I"))
    config.ccflags
  ;

  var macros = unbox (map (fun (s:string) => "/D"+s) config.macros);
  // for executable
  var static_link_strings =
    let fun fixup (s:string) => if prefix (s,"-L") then "/LIBPATH:"+s.[2 to] else s in
    unbox (map fixup (config.library_search_dirs + config.static_libraries))
  ;
  // for DLL
  var dynamic_link_strings =
    let fun fixup (s:string) => if prefix (s,"-L") then "/LIBPATH:"+s.[2 to] else s in
    unbox (map fixup (config.library_search_dirs + config.dynamic_libraries))
  ;

  gen xpopen(cmd:list[string]) = {
    //var CMD = catmap ' ' Shell::quote_arg cmd;
    var CMD = strcat ' ' cmd;
    var result, data = System::get_stdout(CMD);
    if result != 0 do
      eprintln $ "Shell command="+CMD + " FAILED";
    done
    return result, data;
  }

  gen shell(cmd:list[string]) = {
    var CMD = catmap ' ' Shell::quote_arg cmd;
    var result = System::system(CMD);
    if result != 0 do
      eprintln $ "Shell command="+CMD + " FAILED";
    done
    return result;
  }

  proc checkwarn (result:int, text:string)
  {
    if result != 0 do
       print text;
    else
      for line in split(text,char "\n") do
        if
          stl_find (line,"warning") != stl_npos or
          stl_find (line, "note:") != stl_npos
        do
          eprintln$ line;
        done
      done
    done
  }

// Boilerplate

  method gen c_dependency_generator (spec:(src:string)) : int * string =
  {
    var cmd :list[string] = ("cl.exe" ! "/nologo" ! "/MDd" ! "/Zs" ! "/showIncludes" ! "/c" ! "/Tc"+spec.src ! macros) +
       include_switches;
    var result,text =xpopen cmd;
    return result,text;
  }

  method gen cxx_dependency_generator (spec:(src:string)) : int * string =
  {
    var cmd : list[string] = ("cl.exe" ! "/nologo" ! "/wd4190" ! "/MDd" ! "/Zs" ! "/showIncludes" ! "/c" ! "/EHs" ! macros) +
      include_switches + (spec.src ! Empty[string]);
    var result,text =xpopen cmd;
    return result,text;
  }

  method gen dependency_parser (data:string) : list[string] = {
   var lines = split (data, "\n");
   var files = Empty[string];
   for line in lines do
     if prefix (line, "Note: including file: ") do
       var name = strip (line.[22 to]);
       if not prefix (name,"C:\\Program Files")
       and not prefix (name,"c:\\program files")
       do
         if name not in files do
           files = name ! files;
         done
       done
     done
   done
   return rev files;
  }

  method gen c_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result,text = xpopen$ ("cl.exe" ! "/nologo" ! "/DFLX_STATIC_LINK" ! "/MDd" ! "/Zi" ! "/c" ! "/Tc"+spec.src ! macros) +
      include_switches + ("/Fo"+spec.dst);
    checkwarn(result,text);
    return result;
  }

  method gen c_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result,text =xpopen$ ("cl.exe" ! "/nologo" ! "/MDd" ! "/Zi" ! "/c" ! "/Tc"+spec.src ! macros) +
       include_switches + ("/Fo"+spec.dst);
    checkwarn(result,text);
    return result;
  }


  method gen cxx_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result,text =xpopen$ ("cl.exe" ! "/nologo" ! "/wd4190" ! "/DFLX_STATIC_LINK" ! "/MDd" ! "/Zi" ! "/c" ! "/EHs" ! macros) +
      include_switches + spec.src + ("/Fo"+spec.dst);
    checkwarn(result,text);
    return result;
  }

  method gen cxx_static_library_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result,text =xpopen$ ("cl.exe" ! "/nologo" ! "/wd4190" ! "/DFLX_STATIC_LINK" ! "/MDd" ! "/Zi" ! "/c" ! "/EHs" ! macros) +
       include_switches + (spec.src ! ("/Fo"+spec.dst) ! Empty[string]);
    checkwarn(result,text);
    return result;
  }

  method gen cxx_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result,text =xpopen$ ("cl.exe" ! "/nologo" ! "/wd4190" ! "/MDd" ! "/Zi" ! "/c" ! "/EHs" ! macros) +
      include_switches + (spec.src ! ("/Fo"+spec.dst) ! Empty[string]);
    checkwarn(result,text);
    return result;
  }

  method gen static_library_linker (spec:(dst:string, srcs:list[string])): int =
  {
    var result,text =xpopen$ "lib.exe" ! "/OUT:"+spec.dst ! spec.srcs;
    checkwarn(result,text);
    return result;
  }

  method gen static_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    // Windows requires the object files before the /link and the libraries after
    // our generic interface can't deal with that so we have to parse ..
    var link_specs = Empty[string];
    var obj_specs = Empty[string];
    for term in spec.srcs + static_link_strings do
      if prefix (term, "/DEFAULTLIB:") do link_specs += term;
      elif prefix (term, "/LIBPATH:") do link_specs += term;
      elif suffix (term, ".obj") or suffix (term, ".obj") do obj_specs += term;
      else
        obj_specs += term; // dunno what to do with it!
      done
    done
    var result,text =xpopen$  "cl.exe" ! "/nologo" ! "/DFLX_STATIC_LINK" ! "/MDd" ! obj_specs + ("/Fe"+spec.dst) + "/link" + link_specs;
    checkwarn(result,text);
    return result;
  }

  method gen dynamic_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    // Windows requires the object files before the /link and the libraries after
    // our generic interface can't deal with that so we have to parse ..
    var link_specs = Empty[string];
    var obj_specs = Empty[string];
    for term in spec.srcs + static_link_strings do
      if prefix (term, "/DEFAULTLIB:") do link_specs += term;
      elif prefix (term, "/LIBPATH:") do link_specs += term;
      elif suffix (term, ".obj") or suffix (term, ".obj") do obj_specs += term;
      else
        obj_specs += term; // dunno what to do with it!
      done
    done
    var result,text = xpopen$ "cl.exe" ! "/nologo" ! "/MDd" ! obj_specs + ("/Fe"+spec.dst) + "/link" + link_specs;
    checkwarn(result,text);
    return result;
  }

  method gen dynamic_library_linker (spec:(dst:string,srcs:list[string])) : int =
  {
    var result,text =xpopen$  "cl.exe" ! "/nologo" ! "/MDd" ! spec.srcs + ("/Fe"+spec.dst) +  "/link" + "/DLL" + dynamic_link_strings;
    checkwarn(result,text);
    return result;
  }
}

Object for clang on iOS

//[clang_iOS_generic.flx]
include "std/felix/toolchain_interface";
include "std/felix/toolchain_config";
include "std/felix/flx_cxx";

object toolchain_clang_apple_iOS_maker (sdk_tag:string, archs:list[string])
  (config:toolchain_config_t) implements toolchain_t =
{
  //eprintln$ "toolchain_clang_apple_iOS_maker sdk=" + sdk_tag + ", arches=" + archs.str;
  gen get (s:string):string = {
    var err, res = System::get_stdout s;
    if err != 0 do
      var msg = "Abort: Error executing shell command " + s;
      eprintln$ msg;
      System::abort;
    done
    return res;
  }

  var clang = strip(get("xcrun --sdk " + sdk_tag + " --find clang"));
  var clangxx = strip(get("xcrun --sdk " + sdk_tag + " --find clang++"));
  var sdk = strip(get("xcrun --sdk " + sdk_tag + " --show-sdk-path"));

  //eprintln$ "C compiler " + clang;
  //eprintln$ "C++ compiler " + clangxx;
  //eprintln$ "sdk path " + sdk;

  var cxx_compile_warning_flags = list$
    "-w", // turn off all the warnings (but not hard errors)
    "-Wfatal-errors", // stop compiling on the first hard error
    "-Wno-return-type-c-linkage",
    "-Wno-invalid-offsetof"
  ;
  var c_compile_warning_flags = list$ "-w",
    "-Wfatal-errors",
    "-Wno-array-bounds"
  ;

  var c_compiler = clang;
  var cxx_compiler = clangxx;
  var linker = clangxx;
  var archlist = unbox (rev (fold_left (fun (acc:list[string]) (arch:string) => arch ! "-arch" ! acc) Empty[string] archs));

  var ccflags_for_dynamic_link = list[string]("-dynamiclib", "-isysroot", sdk) + archlist;
  var base_c_compile_flags =
    "-g"! "-c" ! "-isysroot" ! sdk ! "-O1" !
    "-fno-common"! "-fno-strict-aliasing" ! "-fembed-bitcode" !
    (archlist + c_compile_warning_flags+config.ccflags)
  ;
  var base_cxx_compile_flags =
    "-g"! "-c" ! "-isysroot" ! sdk ! "-O1" !
    "-fno-common"! "-fno-strict-aliasing" ! "-fembed-bitcode" ! "-std=c++14" !
    (archlist + cxx_compile_warning_flags+config.ccflags)
  ;

  method fun whatami () => "toolchain_clang_apple_iOS sdk="+sdk_tag+", archs="+cat "," archs;
  method fun host_os () => "OSX";
  method fun target_os () => "iOS";
  method fun cxx_compiler_vendor () => "clang";

  method fun dependency_extension () => ".d";
  method fun executable_extension () => "";
  method fun static_object_extension () => "_static.o";
  method fun dynamic_object_extension () => "_dynamic.o";
  method fun static_library_extension () => ".a";
  method fun dynamic_library_extension () => ".dylib";
  method fun pathname_separator () => "/";
  method fun debug_flags () => list[string] "-g";
  method fun get_base_c_compile_flags () => base_c_compile_flags;
  method fun get_base_cxx_compile_flags () => base_cxx_compile_flags;

// Boilerplate

  method gen c_dependency_generator (spec:(src:string)) : int * string =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=c_compiler,
          CCFLAGS = "-isysroot" ! sdk ! "-MM" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result,  data;
  }

  method gen cxx_dependency_generator (spec:(src:string)) : int * string =
  {
     var result, data =
       CxxCompiler::generic_cxx_gen_deps
       (
          CCDEP=cxx_compiler,
          CCFLAGS = "-std=c++14" ! "-isysroot" ! sdk ! "-MM" ! config.ccflags,
          INCLUDE_DIRS=config.header_search_dirs,
          MACROS=config.macros,
          debugln = config.debugln
       )
       (spec.src)
     ;
     return result, data;
  }

  method gen dependency_parser (data:string) : list[string] =>
     CxxCompiler::generic_dependency_parser data
  ;

  method gen c_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = c_compiler,
        CCFLAGS = base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen c_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = c_compiler,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_c_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_static_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen cxx_static_library_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_static
      (
        CCOBJ_STATIC_LIB = cxx_compiler,
        CCFLAGS = base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = "FLX_STATIC_LINK"+config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }


  method gen cxx_dynamic_object_compiler (spec:(dst:string, src:string)) : int =
  {
    var result =
      CxxCompiler::generic_cxx_compile_for_dynamic
      (
        CCOBJ_DLLIB = linker,
        CCFLAGS = "-fPIC" ! "-fvisibility=hidden" ! base_cxx_compile_flags,
        INCLUDE_DIRS = config.header_search_dirs,
        MACROS = config.macros,
        SPEC_OBJ_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.src, spec.dst)
    ;
    return result;
  }

  method gen static_library_linker (spec:(dst:string, srcs:list[string])): int =
  {
    var result =
      CxxCompiler::generic_static_library
      (
        CCLINK_STATIC_LIB = "libtool",
        CCFLAGS = list[string]("-static"),
        SPEC_LIB_FILENAME = "-o ",
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen static_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_static
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.static_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }

  method gen dynamic_executable_linker  (spec:(dst:string, srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_exe_dynamic
      (
        CCLINK_STATIC = linker,
        CCFLAGS = Empty[string],
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }


  method gen dynamic_library_linker (spec:(dst:string,srcs:list[string])) : int =
  {
    var result =
      CxxCompiler::generic_link_lib_dynamic
      (
        CCLINK_DLLIB = linker,
        CCFLAGS = ccflags_for_dynamic_link,
        EXT_SHARED_OBJ = #dynamic_library_extension,
        SPEC_EXE_FILENAME = "-o ",
        LINK_STRINGS = config.library_search_dirs + config.dynamic_libraries,
        debugln = config.debugln
      )
      (spec.srcs, spec.dst)
    ;
    return result;
  }
}

gen toolchain_clang_apple_iPhoneOS_armv7_arm64 (config:toolchain_config_t) : toolchain_t =>
  toolchain_clang_apple_iOS_maker ("iphoneos",(["armv7","arm64"])) config
;

gen toolchain_clang_apple_iPhoneSimulator (config:toolchain_config_t) : toolchain_t = {
  return toolchain_clang_apple_iOS_maker ("iphonesimulator",(["x86_64","i386"])) config;
}

Toolchain Plugins

These are wrappers around the toolchain objects previously defined which convert them from objects into plugins, that is, which provide the architectural support for separate compilation and loading of binary shared libraries (DLLs).

The MSVC++ plugin for Windows is missing because the object implementing it is only a stub.

iPhone Plugin

//[toolchain_iphoneos.flx]
include "std/felix/toolchain/clang_iOS_generic";

// varies macosx vs linus,  gcc vs clang

export fun toolchain_clang_apple_iPhoneOS_armv7_arm64 of (toolchain_config_t) as "toolchain_iphoneos";

fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  eprintln$ "Setup toolchain iphoneos " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_iphoneos_setup";
//[toolchain_iphonesimulator.flx]
include "std/felix/toolchain/clang_iOS_generic";

// varies macosx vs linus,  gcc vs clang

export fun toolchain_clang_apple_iPhoneSimulator of (toolchain_config_t) as "toolchain_iphonesimulator";

fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  eprintln$ "Setup toolchain iphonesimulator " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_iphonesimulator_setup";

Plugin for gcc on Linux

//[toolchain_gcc_linux.flx]
include "std/felix/toolchain/gcc_linux";

export fun toolchain_gcc_linux of (toolchain_config_t) as "toolchain_gcc_linux";

fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  //eprintln$ "Setup toolchain gcc_linux " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_gcc_linux_setup";

Plugin for gcc on OSX

//[toolchain_gcc_macosx.flx]
include "std/felix/toolchain/gcc_macosx";

export fun toolchain_gcc_macosx of (toolchain_config_t) as "toolchain_gcc_macosx";

fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  //eprintln$ "Setup toolchain gcc+macosx " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_gcc_macosx_setup";

Plugin for clang on Linux

//[toolchain_clang_linux.flx]
include "std/felix/toolchain/clang_linux";

// varies macosx vs linus,  gcc vs clang

export fun toolchain_clang_linux of (toolchain_config_t) as "toolchain_clang_linux";


fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  //eprintln$ "Setup toolchain clang_linux " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_clang_linux_setup";

Plugin for clang on OSX

//[toolchain_clang_macosx.flx]
include "std/felix/toolchain/clang_macosx";

// varies macosx vs linus,  gcc vs clang

export fun toolchain_clang_macosx of (toolchain_config_t) as "toolchain_clang_macosx";

fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  //eprintln$ "Setup toolchain clang_macosx " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_clang_macosx_setup";

MSVC++ Plugin for Win32

//[toolchain_msvc_win.flx]
include "std/felix/toolchain/msvc_win";

// varies macosx vs linus,  gcc vs clang

export fun toolchain_msvc_win of (toolchain_config_t) as "toolchain_msvc_win";

fun setup(config_data:string) = {
   C_hack::ignore (config_data); // due to bug in Felix
  //eprintln$ "Setup toolchain msvc_win " + config_data;
  return 0;
}

export fun setup of (string) as "toolchain_msvc_win_setup";

Flx Plugin

A wrapper around “flx” command.

//[flx_plugin.flx]
include "std/felix/flx/flx";
export fun flx_plugin_setup(x:string)=>0;
export fun flx_plugin (args:list[string]) = { return Flx::runflx (args); }