#line 1602 "/home/travis/build/felix-lang/felix/src/packages/flx.fdoc"
  include "std/felix/flx/flx_control";
  
  class FlxDepvars
  {
  typedef dvars_type = (
      filebase:string,
      cpp_filebase:string,
      args: list[string],
      use_ext:string,
      FLX_STD_LIBS: list[string],
      GRAMMAR_DIR: string,
      STDGRAMMAR: string,
      AUTOMATON: string,
      DEBUGSWITCH:list[string],
      STATIC_ENV:list[string],
      VERBOSE: list[string]
    );
  
  gen cal_depvars(
    toolchain: clang_config_t -> toolchain_t,
    config:Config::config_type,
    control:&FlxControl::control_type,
    loopctl:FlxControl::loopctl_type)
    : dvars_type
    =
  {
    proc debugln[T with Str[T]] (x:T) {
      if control*.DEBUG_FLX call fprintln (cstderr, "[flx] " + str x);
    }
    fun / (d:string, f:string) => Filename::join (d,f);
  
    var dflt_clang_config = (
        header_search_dirs = Empty[string],
        macros = Empty[string],
        library_search_dirs= Empty[string],
        ccflags= Empty[string],
        dynamic_libraries= Empty[string],
        static_libraries= Empty[string],
        debugln = debugln[string]
    );
    var tc = toolchain dflt_clang_config;
    var EXT_LIB = #(tc.static_library_extension);
    var EXT_SHLIB = #(tc.dynamic_library_extension);
    var EXT_EXE = #(tc.executable_extension);
    var EXT_STATIC_OBJ = #(tc.static_object_extension);
    var EXT_SHARED_OBJ = #(tc.dynamic_object_extension);
    var DEBUG_FLAGS = #(tc.debug_flags);
  
  
    debugln$ "Felix package manager config directories are "+config.FLX_CONFIG_DIRS.str;
    // make a list of any *.cpp files (or other g++ options ..)
  
    debugln$ "FileDir= " + loopctl.dir;
    var rel_filebase = if loopctl.dir == "." then loopctl.base else Filename::join(loopctl.dir,loopctl.base);
    debugln$ "Rel_filebase= " + rel_filebase;
    debugln$ "Given Extension=" + loopctl.ext;
  
      // this is a hack! We should resolve the filename first.
    var use_ext = if loopctl.ext != "" then loopctl.ext else
      #{
         var flxt = FileStat::dfiletime (rel_filebase+".flx",#FileStat::past_time);
         var fdoct = FileStat::dfiletime (rel_filebase+".fdoc",#FileStat::past_time);
         return
           if flxt > fdoct then ".flx"
           elif fdoct > flxt then ".fdoc"
           else ""
         ;
      }
    ;
    debugln$ "Computed Extension=" + use_ext;
    var filebase = Directory::mk_absolute_filename$ rel_filebase;
    debugln$ "User program base is " + filebase;
    var cpp_filebase =
      match control*.BUNDLE_DIR with
      | Some dir => Filename::join(dir,Filename::basename filebase)
      | #None =>if config.FLX_OUTPUT_DIR=="" then filebase
               else cache_join(config.FLX_OUTPUT_DIR,filebase)
               endif
      endmatch;
    debugln$ "C++ file base is " + cpp_filebase;
  
    // if we're supposed to check output against an expect file,
    // and no stdout file name is given, then direct output
    // into the cache.
    if control*.CHECK_EXPECT != 0 and control*.STDOUT == "" do
      control.STDOUT <- cache_join (config.FLX_OUTPUT_DIR,filebase + ".stdout");
      debugln$ "Set stdout to " + control*.STDOUT;
    done
  
    if control*.SET_STDIN != 0 and control*.STDIN == "" do
      var stdin_name = filebase + ".input";
      if FileStat::fileexists stdin_name  do
        control.STDIN <- stdin_name;
      elif control*.INREGEX == "" do
        eprintln$ "WARNING: computed input file " + stdin_name + " doesn't exist!";
      done
      debugln$ "Set stdin to " + control*.STDIN;
    done
  
  
    // if we're supposed to check output against an expect file,
    // and no expect file name is given, then use the filebase
    // with extension .expect.
    if control*.CHECK_EXPECT != 0 and control*.EXPECT == "" do
      var expect_name = filebase + ".expect";
      if FileStat::fileexists expect_name do
        control.EXPECT <- expect_name;
      elif control*.INREGEX == "" do
        eprintln$ "WARNING: computed expect file " + expect_name + " doesn't exist!";
      done
      debugln$ "Set expect to " + control*.EXPECT;
    done
  
  
    // Find absolute pathname
  
    if loopctl.path == "" do
      fprint$ cstderr, ("No such felix program: "+loopctl.path+"\n");
      System::exit(1);
    done
  
    control*.FLX_INTERFACE_FILENAME =
      match control*.BUNDLE_DIR with
      | Some dir => Filename::join(dir,Filename::basename filebase+"_interface.flx")
      | #None => cache_join (config.FLX_OUTPUT_DIR,filebase+"_interface.flx")
      endmatch;
    debugln$ "Flx interface filename is " + control*.FLX_INTERFACE_FILENAME;
  
    control*.CXX_INTERFACE_FILENAME =
      match control*.BUNDLE_DIR with
      | Some dir => Filename::join(dir,Filename::basename filebase+".hpp")
      | #None => cache_join (config.FLX_OUTPUT_DIR,filebase+".hpp")
      endmatch;
    debugln$ "C++ interface filename is " + control*.FLX_INTERFACE_FILENAME;
  
    if control*.LINKER_OUTPUT_FILENAME == "" do
      if control*.LINKIT == 1 or control*.RUNONLY == 1 do
        if control*.STATICLIB == 1 do
          var f = filebase+EXT_LIB;
        elif control*.STATIC == 0 do // dynamic
          if control*.LINKEXE == 1 do
            f = filebase+EXT_LIB;
          else // DLL
            f = filebase+EXT_SHLIB;
          done
        else
          f = filebase+EXT_EXE;
        done
      else // No link, name specifies object file only.
        if control*.STATIC == 1 do
          f = filebase+EXT_STATIC_OBJ;
        else
          f = filebase+EXT_SHARED_OBJ;
        done
      done
      control*.LINKER_OUTPUT_FILENAME = cache_join (config.FLX_CACHE_DIR,f);
      debugln$ "Felx writing output binary to " + control*.LINKER_OUTPUT_FILENAME;
    elif control*.OUTPUT_FILENAME_WITHOUT_EXTENSION_SPECIFIED == 1 do
      if control*.LINKIT == 1 or control*.RUNONLY == 1 do
        if control*.STATICLIB == 1 do
          *control.LINKER_OUTPUT_FILENAME += EXT_LIB;
        elif control*.STATIC == 0 do // dynamic
          if control*.LINKEXE == 1 do
            *control.LINKER_OUTPUT_FILENAME += EXT_EXE;
          else
            *control.LINKER_OUTPUT_FILENAME += EXT_SHLIB;
          done
        else
          *control.LINKER_OUTPUT_FILENAME += EXT_EXE;
        done
      else // No link, name specifies object file only.
        if control*.STATIC == 1 do
          *control.LINKER_OUTPUT_FILENAME += EXT_STATIC_OBJ;
        else
          *control.LINKER_OUTPUT_FILENAME += EXT_SHARED_OBJ;
        done
      done
    elif control*.OUTPUT_DIRECTORY_SPECIFIED == 1 do
      var basename = Filename::basename (Filename::strip_extension filebase);
      if control*.LINKIT == 1 or control*.RUNONLY == 1 do
        if control*.STATICLIB == 1 do
          control.LINKER_OUTPUT_FILENAME <- control*.LINKER_OUTPUT_FILENAME / basename + EXT_LIB;
        elif control*.STATIC == 0 do // dynamic
          if control*.LINKEXE == 1 do
            control.LINKER_OUTPUT_FILENAME <- control*.LINKER_OUTPUT_FILENAME / basename + EXT_EXE;
          else
            control.LINKER_OUTPUT_FILENAME <- control*.LINKER_OUTPUT_FILENAME / basename + EXT_SHLIB;
          done
        else
          control.LINKER_OUTPUT_FILENAME <- control*.LINKER_OUTPUT_FILENAME / basename + EXT_EXE;
        done
      else // No link, name specifies object file only.
        if control*.STATIC == 1 do
          control.LINKER_OUTPUT_FILENAME <- control*.LINKER_OUTPUT_FILENAME / basename + EXT_STATIC_OBJ;
        else
          control.LINKER_OUTPUT_FILENAME <- control*.LINKER_OUTPUT_FILENAME / basename + EXT_SHARED_OBJ;
        done
      done
    done
    control.LINKER_OUTPUT_FILENAME <-  Directory::mk_absolute_filename control*.LINKER_OUTPUT_FILENAME;
    control.LINKER_OUTPUT_FILENAME <-
     match control*.BUNDLE_DIR with
      | Some dir => Filename::join(dir,Filename::basename control*.LINKER_OUTPUT_FILENAME)
      | #None => control*.LINKER_OUTPUT_FILENAME
      endmatch;
    debugln$ "Linker output filename " + control*.LINKER_OUTPUT_FILENAME;
  
  
    val args = control*.USER_ARGS;
    debugln$ "Target program args = "+args.str;
  
    if control*.NOSTDLIB == 1 do
      var FLX_STD_LIBS=Empty[string];
    else
      match control*.FLX_STD_LIBS with
      | #Empty => FLX_STD_LIBS = list[string] ("std");
      | x => FLX_STD_LIBS = x;
      endmatch;
    done
    debugln$ "Felix standard (cached) libraries: " + str FLX_STD_LIBS;
  
    var STDGRAMMAR = Directory::mk_absolute_filename control*.STDGRAMMAR;
    var GRAMMAR_DIR = Directory::mk_absolute_filename control*.GRAMMAR_DIR;
    var AUTOMATON = Directory::mk_absolute_filename control*.AUTOMATON;
  
    var DEBUGSWITCH=Empty[string];
    if control*.DEBUG_COMPILER == 1 do DEBUGSWITCH=list[string]$ "--debug"; done
  
    var STATIC_ENV=Empty[string];
    if control*.DEBUG_COMPILER == 1 do STATIC_ENV=list[string] ("env","FLX_DEBUG=1"); done
  
    debugln$ "RECOMPILE="+str control*.RECOMPILE;
    debugln$ "RUNIT="+str control*.RUNIT;
  
    var VERBOSE = Empty[string];
    if control*.DEBUG_COMPILER == 1 do
      VERBOSE=list[string] "-v";
      debugln "Compiler debugging on";
    else
      VERBOSE=list[string]$  "-q";
      debugln "Compiler debugging off";
    done
  
    if control*.DEBUG==1 do
      control.CCFLAGS <- control*.CCFLAGS+DEBUG_FLAGS;
    done
  
  
    return struct {
      var filebase=filebase;
      var cpp_filebase=cpp_filebase;
      var args = args;
      var use_ext = use_ext;
      var FLX_STD_LIBS=FLX_STD_LIBS;
      var AUTOMATON=AUTOMATON;
      var GRAMMAR_DIR=GRAMMAR_DIR;
      var STDGRAMMAR=STDGRAMMAR;
      var DEBUGSWITCH=DEBUGSWITCH;
      var STATIC_ENV=STATIC_ENV;
      var VERBOSE = VERBOSE;
    };
  
  } // fun cal_depvars
  } // class FlxDepvars