#line 103 "/home/travis/build/felix-lang/felix/src/packages/toolchain.fdoc"
  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 = 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;
    }
  
  
  }