#line 1329 "/home/travis/build/felix-lang/felix/src/packages/buildtools.fdoc"
  include "std/felix/toolchain_clang_config";
  include "std/felix/toolchain_interface";
  include "std/felix/flx_cp";
  include "std/felix/flx_pkgconfig";
  include "std/felix/flx_pkg"; // only for "fix2word_flags"
  include "std/felix/flx/flx_plugin_client";
  
  class FlxCoreBuild
  {
  
    fun / (x:string,y:string) => Filename::join(x,y);
  
    proc build_plugins(target_dir:string, target_bin:string, plugins:list[string])
    {
      for plugin in plugins do
        println$ "Building plugin " + plugin;
        var result = Flx_client::runflx$ list ('[flx]','--test='+target_dir,
          '-c', '-ox',target_dir/target_bin/'lib'/'rtl'/plugin,
          target_dir/'share'/'lib'/'plugins'/plugin);
        if result != 0 do
          println$ "plugin (dynamic) build failed";
          System::exit 1;
        done
  
        result = Flx_client::runflx$ list ('[flx]','--test='+target_dir,
          '-c', '--nolink','-ox', target_dir/target_bin/'lib'/'rtl'/plugin,
          target_dir/'share'/'lib'/'plugins'/plugin);
        if result != 0 do
          println$ "plugin (dynamic obj) build failed";
          System::exit 1;
        done
  
        result = Flx_client::runflx$ list ('[flx]','--test='+target_dir,
          '--static','-c', '--nolink','-ox', target_dir/target_bin/'lib'/'rtl'/plugin,
          target_dir/'share'/'lib'/'plugins'/plugin);
        if result != 0 do
          println$ "plugin (static obj) build failed";
          System::exit 1;
        done
      done
  
    }
  
    proc build_exes(target_dir:string, target_bin:string, tools:list[string])
    {
      println$ "build exes";
      for exe in tools do
        var src = Filename::join ("tools",exe);
        println$ src + " -> " + exe;
        var result = Flx_client::runflx$ list ('[flx]','--test='+target_dir, '--static','-c',
          '-ox', target_dir/target_bin/'bin'/exe, target_dir/'share'/'src'/src);
        if result != 0 do
          println$ "exe build failed";
          System::exit 1;
        done
      done
    }
  
    proc build_flx_tools (target_dir:string, target_bin:string, tools:list[string])
    {
      println$ "build flx build tools";
      for exe in tools do
        var src = Filename::join ("tools",exe);
        println$ src + " -> " + exe;
        var result = Flx_client::runflx$ list ('[flx]','--test='+target_dir, '--static','-c',
          '-ox', target_dir/target_bin/'bin'/exe, target_dir/'share'/'src'/src);
        if result != 0 do
          println$ "exe build failed";
          System::exit 1;
        done
      done
    }
  
    proc build_flx_web (target_dir:string, target_bin:string, web_plugins:list[string])
    {
      if PLAT_WIN32 do
        var obj_extn = "_static.obj"; // HACK!!!!!!!!
      else
        var obj_extn = "_static.o"; // HACK!!!!!!!!
      done
  
      println$ "dflx_web  -> dflx_web object file";
      var result = Flx_client::runflx$ list ('[flx]','--test='+target_dir, '--static','-c','--nolink',
        '-o', target_dir/target_bin/'lib'/'rtl'/'dflx_web'+obj_extn, target_dir/'share'/'src'/'tools'/'dflx_web');
      if result != 0 do
        println$ "dflx_web build failed";
        System::exit 1;
      done
      var web_plugin_objs =
        map
          (fun (s:string) => target_dir/target_bin/'lib'/'rtl'/s+obj_extn)
          web_plugins
      ;
  
      println$ "Build flx_web. Note: requires --build-web-plugins";
      println$ "flx_web  -> flx_web executable";
      result = Flx_client::runflx$
        list (
          '[flx]','--test='+target_dir, '--static','-c',
          '-ox', target_dir/target_bin/'bin'/'flx_web') +
        web_plugin_objs +
        list (
          target_dir/target_bin/'lib'/'rtl'/'dflx_web' + obj_extn,
          target_dir/'share'/'src'/'tools'/'flx_web.flx')
      ;
      if result != 0 do
        println$ "exe build failed";
        System::exit 1;
      done
    }
  
    proc build_flx (target_dir:string, target_bin:string, toolchain_plugins:list[string])
    {
      if PLAT_WIN32 do
        var obj_extn = ".obj"; // HACK!!!!!!!!
      else
        var obj_extn = ".o"; // HACK!!!!!!!!
      done
      println$ "dflx  -> dflx object file";
      var result = Flx_client::runflx$ list ('[flx]','--test='+target_dir, '-c','--nolink', '--static',
        '-o', target_dir/target_bin/'lib'/'rtl'/'dflx'+obj_extn, target_dir/'share'/'src'/'tools'/'dflx');
      if result != 0 do
        println$ "dflx build failed";
        System::exit 1;
      done
  
      println$ "Compile of dflx"+obj_extn+" SUCCEEDED";
  
      var toolchain_objects = map (fun (p:string) =>
        target_dir/target_bin/'lib'/'rtl'/p + "_static"+obj_extn)
        toolchain_plugins
      ;
  
      println$ "Linking dflx"+obj_extn+" with toolchains "+toolchain_objects.str;
  
      println$ "Build flx. Note: requires --build-toolchain-plugins";
      println$ "flx  -> flx";
      result = Flx_client::runflx$ list ('[flx]','--test='+target_dir, '--static','-c',
        '-ox', target_dir/target_bin/'bin'/'flx') + toolchain_objects +
        (target_dir/target_bin/'lib'/'rtl'/'dflx' + obj_extn) +
        (target_dir/'share'/'src'/'tools'/'flx.flx')
      ;
      if result != 0 do
        println$ "exe build failed";
        System::exit 1;
      done
      println$ "Build flx: SUCCEEDED";
    }
  
    proc flx_build(cmd: cmd_type)
    {
      println$ "bootpkg=" + cmd.boot_package;
      var pkgdir = Filename::join (cmd.target_dir, cmd.target_bin, "config");
      var db = FlxPkgConfig::FlxPkgConfigQuery (list[string] pkgdir);
      gen getbootfields (field:string) => db.getpkgfield (cmd.boot_package, field);
      var toolchain_plugins = getbootfields ("toolchain_plugin");
      var cygwin_toolchain_plugins = getbootfields ("cygwin_toolchain_plugin");
      var web_plugins = getbootfields ("web_plugin");
      var flx_tools = getbootfields ("flx_tool");
      var tools = getbootfields ("tool");
  
      // at this point, the build proceeds using host tools, but only target sources.
      if PLAT_CYGWIN do // requires cygwin dll and headers so only on Cygwin!
        if cmd.build_toolchain_plugins call
          build_plugins(cmd.target_dir, cmd.target_bin,
          toolchain_plugins+cygwin_toolchain_plugins+"flx_plugin")
        ;
        if cmd.build_flx call
          build_flx(cmd.target_dir, cmd.target_bin, toolchain_plugins+cygwin_toolchain_plugins)
        ;
      else
        if cmd.build_toolchain_plugins call
          build_plugins(cmd.target_dir, cmd.target_bin, toolchain_plugins+"flx_plugin")
        ;
        if cmd.build_flx call
          build_flx(cmd.target_dir, cmd.target_bin, toolchain_plugins)
        ;
      done
  
      if cmd.build_flx_tools call build_flx_tools(cmd.target_dir, cmd.target_bin, flx_tools);
      if cmd.build_web_plugins call build_plugins(cmd.target_dir, cmd.target_bin, web_plugins);
      if cmd.build_tools call build_exes(cmd.target_dir, cmd.target_bin, tools);
      if cmd.build_flx_web call build_flx_web (cmd.target_dir, cmd.target_bin, web_plugins);
      println$ "Build Complete";
    }
  
    proc print_help()
    {
      println$ "Usage: flx_build_boot ";
      println$ "";
      println$ "# locations";
      println$ "";
      println$ "  --pkg=bootpkg               default: build_boot";
      println$ "  --target-dir=target_dir     default: build/release";
      println$ "  --target-bin=target_bin     default: host";
      println$ "";
      println$ "";
      println$ "# compilation options";
      println$ "";
      println$ "  --build-toolchain-plugins   Felix compile the toolchain plugins";
      println$ "  --build-flx                 Felix compile flx";
      println$ "  --build-flx-tools           Felix compile flx build tools";
      println$ "  --build-web-plugins         Felix compile the webserver plugins";
      println$ "  --build-tools               Felix compile standard tools";
      println$ "  --build-flx-web             Felix compile web server executable";
      println$ "";
      println$ "  --debug                     do stuff verbosely";
      println$ "";
      println$ "# Environment variables";
      println$ "";
      println$ "FLX_SHELL_ECHO=1              echo all shell callouts (system, popen)";
      println$ "FLX_DEBUG_FLX=1               make 'flx' explain its processing decisions";
      println$ "";
      println$ "Purpose: Build new Felix target: stuff written in Felix";
      println$ "";
      println$ "Ensures target_dir contains:";
      println$ "";
      println$ "  (a) Repository source in $target_dir/share/src";
      println$ "  (b) Share library in $target_dir/share/lib";
      println$ "  (c) config db, C++ headers, libraries and executables in $target_dir/$target_bin/*";
      println$ "";
    }
  
    typedef cmd_type = typeof (parse_args Empty[string]);
  
    noinline fun parse_args (args: list[string]) =
    {
       var cmd = (
         boot_package="",
         target_dir="build"/"release",
         target_bin="host",
  
         build_web_plugins=false,
         build_toolchain_plugins=false,
         build_flx=false,
         build_flx_tools=false,
         build_tools=false,
         build_flx_web=false,
         debug = false
       );
  
       for arg in args do
         // location options
         if prefix(arg,"--pkg=") do
           &cmd.boot_package <- arg.[6 to];
         elif prefix(arg,"--target-dir=") do
           &cmd.target_dir <- arg.[13 to];
         elif prefix(arg,"--target-bin=") do
           &cmd.target_bin <- arg.[13 to];
         elif arg == "--debug" do
           &cmd.debug <- true;
  
         // operation options: compilation
         elif arg == "--build-web-plugins" do
           &cmd.build_web_plugins<- true;
         elif arg == "--build-toolchain-plugins" do
           &cmd.build_toolchain_plugins<- true;
         elif arg == "--build-flx" do
           &cmd.build_flx <- true;
         elif arg == "--build-flx-tools" do
           &cmd.build_flx_tools <- true;
         elif arg == "--build-tools" do
           &cmd.build_tools<- true;
         elif arg == "--build-flx-web" do
           &cmd.build_flx_web <- true;
         elif arg == "--build-all" do
           &cmd.build_web_plugins<- true;
           &cmd.build_toolchain_plugins<- true;
           &cmd.build_flx <- true;
           &cmd.build_flx_web <- true;
           &cmd.build_flx_tools <- true;
           &cmd.build_tools<- true;
         elif arg == "--help" do
           print_help();
           System::exit(0);
         else
           println$ "Unknown switch " + arg;
           print_help();
           System::exit(1);
         done
       done
  
       // Note: unrelated to boot package used by flx_build_rtl
       if cmd.boot_package == "" do &cmd.boot_package <- "build_boot"; done
       return cmd;
    }
  
    noinline proc build_felix (xargs:list[string])
    {
      if xargs.len.int < 2 do
        print_help();
        System::exit(1);
      done
      var cmd = parse_args (tail xargs);
      println$ "flx_build_boot v1.3";
      println$ "  build_package = " + cmd.boot_package;
      println$ "  target_dir    = " + cmd.target_dir;
      println$ "  target_bin    = " + cmd.target_bin;
  
      flx_build (cmd);
    }
  
  }
  
  Flx_client::setup;
  FlxCoreBuild::build_felix (#System::args);
  
  System::exit (0);