#line 1710 "/home/travis/build/felix-lang/felix/src/packages/toolchain.fdoc"
  include "std/felix/toolchain_interface";
  include "std/felix/toolchain_clang_config";
  include "std/felix/flx_cxx";
  
  object toolchain_msvc_win32 (config:clang_config_t) implements toolchain_t =
  {
  
    var c_compiler = "cl";
    var cxx_compiler = "cl";
    var linker = "cl";
    var base_c_compile_flags = Empty[string];
    var base_cxx_compile_flags = Empty[string];
  
    method fun whatami () => "toolchain_msvc_win32 (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 = 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 = 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
      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
      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" + "/DEBUG"+ 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" + "/DEBUG"+ 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" + "/DEBUG" + dynamic_link_strings;
      checkwarn(result,text);
      return result;
    }
  }