#!/usr/bin/perl
$bsp_library_dir   = 
"/usr/local/BSP//";
%mpi_library_dir = ("SGICHALL264","/usr/lib64/", "SGICHALL64","/usr/local/mpich/lib/IRIX/ch_shmem/", "RS6000",    "/users/jonh/MPI/mpich/lib/rs6000/ch_p4/", "SP2",       "/amd_fs/sgi-scratch/djb/mpich/lib/rs6000/ch_eui/", "OSF1",      "/homes/hilly/MPI/mpich/lib/alpha/ch_p4/", "SunOS",     "/scratch/jonh/MPI/lib/sun4/ch_p4/");































%bspfrontOptimisationPackages = (
  "SGICHALL64", "-fcheck-syncs -bspnobuffers 3 -bspbuffer 80K   ".
                "-bspfifo 500 -fcombine-puts   -fcombine-puts-buffer 62K",

  "SGI",        "-fcheck-syncs -bspnobuffers 2 -bspbuffer 10K   ".
                "-bspfifo 500 -fcombine-puts   -fcombine-puts-buffer 20K",

  "SP2",        "-fcheck-syncs -bspnobuffers 1 -bspbuffer 1024K ".
                "-bspfifo 500 -fcombine-puts   -fcombine-puts-buffer 31K",

  "CONVEXSPP",  "-fcheck-syncs -bspnobuffers 3 -bspbuffer 80K   ".
                "-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 31K",

  "PARSYTEC",   "-fcheck-syncs -bspnobuffers 1 -bspbuffer 1K    ".
                "-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 20K",

  "HITACHIMPP", "-fcheck-syncs -bspnobuffers 1 -bspbuffer 1024K ".
                "-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 10K",

  "CRAYT3D",    "-fcheck-syncs -bspnobuffers 1 -bspbuffer 1024K ".
                "-bspfifo 100 -fnocombine-puts -ffixed-bsmp-buffers 100",
  "RS6000",     "-fcheck-syncs -bspnobuffers 2 -bspbuffer 10K   ".
                "-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 20K",

  "SunOS",      "-fcheck-syncs -bspnobuffers 2 -bspbuffer 10K   ".
		"-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 20K",

  "Solaris",    "-fcheck-syncs -bspnobuffers 2 -bspbuffer 10K   ".
		"-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 20K",

  "LINUX",      "-fcheck-syncs -bspnobuffers 2 -bspbuffer 10K   ".
		"-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 20K",

  "OSF1",       "-fcheck-syncs -bspnobuffers 2 -bspbuffer 10K   ".
		"-bspfifo 300 -fcombine-puts   -fcombine-puts-buffer 20K"
);










push(@INC,"$bsp_library_dir/include/");
($Pgm = $0) =~ s|.*/||;
$Version           = "0.7alpha, Tue Nov 19 1996";
$bug_reports_to    = 'bsplib-bugs@comlab.ox.ac.uk';
$Arch   = `$bsp_library_dir/bin/bsparch -arch`;
$Device = `$bsp_library_dir/bin/bsparch -device`;
$FPP    = "$bsp_library_dir/bin/bspfpp";

%ccArch        = (
  "SGICHALL64",  "cc",
  "SGI",         "cc",
  "SP2",         "mpcc",
  "CONVEXSPP",   "/usr/convex/bin/cc",
  "PARSYTEC",    "px ancc",
  "RS6000",      "cc",
  "SunOS",       "gcc",
  "LINUX",       "gcc",
  "Solaris",     "cc",
  "OSF1",        "cc",
  "HITACHIMPP",  "srcc",
  "CRAYT3D",     "cc");

%cplusplusArch   = (
  "SGICHALL64",  "CC",
  "SGI",         "CC",
  "SP2",         "mpc++",
  "CONVEXSPP",   "/usr/convex/bin/cc",
  "PARSYTEC",    "px ancc",
  "RS6000",      "CC",
  "SunOS",       "g++",
  "LINUX",       "g++",
  "Solaris",     "CC",
  "OSF1",        "CC",
  "HITACHIMPP",  "srCC",
  "CRAYT3D",     "CC");

%cppArch        = (
  "SGICHALL64",  "/lib/cpp",
  "SGI",         "/lib/cpp",
  "SP2",         "/lib/cpp",
  "CONVEXSPP",   "/lib/cpp",
  "PARSYTEC",    "/lib/cpp",
  "RS6000",      "/lib/cpp",
  "SunOS",       "/lib/cpp",
  "LINUX",       "/lib/cpp",
  "Solaris",     "/lib/cpp",
  "OSF1",        "/lib/cpp",
  "HITACHIMPP",  "/lib/cpp",
  "CRAYT3D",     "/lib/cpp");

%f77Arch = (
  "SGICHALL64","f77",
  "SGI",       "f77",
  "SP2",       "mpxlf",
  "CONVEXSPP", "/usr/convex/bin/fc",
  "PARSYTEC",  "px f77",
  "RS6000",    "xlf",
  "SunOS",     "f77",
  "LINUX",     "f77",
  "Solaris",   "f77",
  "OSF1",      "f77",
  "HITACHIMPP","srf77",
  "CRAYT3D",   "cf77");


%f77doesCpp = (
  "SGICHALL64",1);

# Flags to the underlying Compilers
%ccompFlagsArch = (
  "SGICHALL64", "-64 -mips4",
  "SGI",        "",
  "SP2",        "",
  "CONVEXSPP",  "-or none",
  "PARSYTEC",   "",
  "HITACHIMPP", "-kcubix",
  "RS6000",     "",
  "SunOS",      "",
  "Solaris",    "-Xt -w",
  "LINUX",      "",
  "OSF1",       "",
  "CRAYT3D",    "-Tcray-t3d");

%fcompFlagsArch = (
  "SGICHALL64", "-static -64 -mips4 -col120",
  "SGI",        "",
  "SP2",        "",
  "CONVEXSPP",  "",
  "PARSYTEC",   "",
  "HITACHIMPP", "-kcubix -i,U",
  "RS6000",     "",
  "SunOS",      "-e -fnonstd",
  "LINUX",      "-e -fnonstd",
  "Solaris",    "-e -fnonstd",
  "OSF1",       "-extend_source",
  "CRAYT3D",    "-C cray-t3d");

%coptFlagsArch = (
  "SGICHALL64-O1", "-O",
  "SGICHALL64-O2", "-O2",
# "SGICHALL64-O3", "-O3 -sopt,-o=5,-cachesize=16",
  "SGICHALL64-O3", "-O3",

  "SGI-O1",        "-O",
  "SGI-O2",        "-O2",
  "SGI-O3",        "-O3",

  "SP2-O1",        "-O",
  "SP2-O2",        "-O2",
  "SP2-O3",        "-O3",

  "CONVEXSPP-O1",  "-O",
  "CONVEXSPP-O2",  "-O2",
  "CONVEXSPP-O3",  "-O3",

  "PARSYTEC-O1",   "-O",
  "PARSYTEC-O2",   "-O2",
  "PARSYTEC-O3",   "-O3",

  "HITACHIMPP-O1", "-O",
  "HITACHIMPP-O2", "-O",
  "HITACHIMPP-O3", "-O",

  "CRAYT3D-O1",    "-O",
  "CRAYT3D-O2",    "-O2",
  "CRAYT3D-O3",    "-O3",

  "RS6000-O1",     "-O",
  "RS6000-O2",     "-O2",
  "RS6000-O3",     "-O3",

  "SunOS-O1",      "-O",
  "SunOS-O2",      "-O2",
  "SunOS-O3",      "-O3",

  "Solaris-O1",    "-O",
  "Solaris-O2",    "-xO3",
  "Solaris-O3",    "-xO4",

  "LINUX-O1",      "-O",
  "LINUX-O2",      "-O2",
  "LINUX-O3",      "-O3",

  "OSF1-O1",       "-O",
  "OSF1-O2",       "-O5 -migrate",
  "OSF1-O3",       "-O5 -migrate");

%foptFlagsArch = (
  "SGICHALL64-O1", "-O",
  "SGICHALL64-O2", "-O2",
  "SGICHALL64-O3", "-sopt,-cachesize=16,-roundoff=3,-scalaropt=3 -GCM:aggressive_speculation=ON -GCM:static_load_speculation=ON -TENV:X=5 -O3",

  "SGI-O1",        "-O",
  "SGI-O2",        "-O2",
  "SGI-O3",        "-O3",

  "SP2-O1",        "-O",
  "SP2-O2",        "-O2",
  "SP2-O3",        "-Pk -Wp,-r=3 -O3",

  "CONVEXSPP-O1",  "-O",
  "CONVEXSPP-O2",  "-O2",
  "CONVEXSPP-O3",  "-O3",

  "PARSYTEC-O1",   "-O",
  "PARSYTEC-O2",   "-O2",
  "PARSYTEC-O3",   "-O3",

  "HITACHIMPP-O1", "-O",
  "HITACHIMPP-O2", "-O",
  "HITACHIMPP-O3", "-O",

  "CRAYT3D-O1",    "-O scalar1",
  "CRAYT3D-O2",    "-O scalar2",
  "CRAYT3D-O3",    "-O scalar3",

  "RS6000-O1",     "-O",
  "RS6000-O2",     "-O2",
  "RS6000-O3",     "-Pk -Wp,-r=3 -O3",

  "SunOS-O1",      "-O",
  "SunOS-O2",      "-O2",
  "SunOS-O3",      "-O3",

  "Solaris-O1",    "-O",
  "Solaris-O2",    "-O2",
  "Solaris-O3",    "-O3",

  "LINUX-O1",      "-O",
  "LINUX-O2",      "-O2",
  "LINUX-O3",      "-O3",

  "OSF1-O1",       "-O",
  "OSF1-O2",       "-O5",
  "OSF1-O3",       "-O5");


%ldFlagsArch   = (
  "SGICHALL64", "-woff all",
  "SGI",        "",
  "SP2",        "",
  "CONVEXSPP",  "",
  "PARSYTEC",   "-L/usr/lang/ppc/lib/PowerPC/",
  "RS6000",     "",
  "SunOS",      "",
  "LINUX",      "",
  "Solaris",    "",
  "OSF1",       "-non_shared",
  "CRAYT3D",    "-Wl,\"-j $bsp_library_dir/include/t3d_bsp_ld\"");

%librariesArch = ( # ignore the first -l 
  "SGICHALL64",  "m",
  "SGI",         "m",
  "SP2",         "m",
  "CONVEXSPP",   "m",
  "PARSYTEC",    "m",
  "HITACHIMPP",  "m",
  "RS6000",      "m",
  "SunOS",       "m",
  "LINUX",       "m",
  "Solaris",     "m",
  "OSF1",        "m -lots -lutil",
  "CRAYT3D",     "m");







# Various helper programs---they do the real work :-)
$CC        = $ccArch{$Arch};
$CPLUSPLUS = $cplusplusArch{$Arch};
$F77       = $f77Arch{$Arch};
$CPP       = $cppArch{$Arch};
$UNLIT     = "litToPgm";
$LD_is_f77 =0;


if ($Pgm eq "bspf77") {
  $LD= $f77Arch{$Arch};
  $LD_is_f77 = 1;
} elsif ($Pgm eq "bspc++") {
  $LD= $cplusplusArch{$Arch};
} else {
  $LD= $ccArch{$Arch};
}



select(STDERR); $| = 1; select(STDOUT); # no STDERR buffering, please.

$Status            = 0;
$Verbose           = 0;
$Debug             = 0;
$UnixDebug         = 0;
$isSharedMemory    = 0;
$Mpi               = 0;
$Prof              = 0;
$Stat              = 0;
$Optimisaton       = 0;
$LibraryLevel      = 0;
$KeepTemps         = 0;
$Given_output_file = "";

$Opt_fcombine_puts        = 1;
$Opt_fcontention_resolve  = 1;

@Input_files       = ();
@Link_files        = ();
@Files_to_tidy     = ();
  
# Set up the signal handler
$SIG{'INT'}  = 'tidy_up_and_die';
$SIG{'QUIT'} = 'tidy_up_and_die';

$Tmpfile_prefix = "bspfront$$";





@CComp_flags    = ($ccompFlagsArch{$Arch});  # Fortran specific flags 
@FComp_flags    = ($fcompFlagsArch{$Arch});  # C specific flags
@Comp_flags     = ();                        # Language independant flags
@Ld_flags       = ($ldFlagsArch{$Arch});
@Import_dir     = ('.',$bsp_library_dir . "include/");
@Library_dir    = ('.',$bsp_library_dir . "lib/$Arch"); #-L things
@Library_user   = ();    
@Library_sys    = ();    
@Cpp_defines    = ('_BSPFRONT_');   
@Cpp_undefines  = (); 
@Inject_includes= ();
@Inject_bspcpp  = ();
$User_overide_compiler= 0;

$CC_extra_flags  = "";
$F77_extra_flags = "";
$LD_extra_flags  = "";




$bsp_check_syncs          = 1;
$bsp_no_buffers           = 3;
$bsp_buffer_size          = 16384;
$bsp_throttle_procs       = 0;
$bsp_comm_fifo_size       = 200;
$Opt_fcombine_puts_size   = $bsp_buffer_size;
$Opt_fbsmp_buffers        = -1;   # Infinite buffers as default



$Do_cc       =1;
$Do_cplusplus=1;
$Do_f77      =0;
$Do_fpp      =1;
$Do_ld       =1;
$Device      =~ /SHMEM/     && ($isSharedMemory =1);
$Device      =~ /MPASS_MPI/ && do {$Mpi = 1;
                                   push(@Library_dir,$mpi_library_dir{$Arch});
                                  };

$bsp_log_usage = 1;  #Log linkages to the above file
$bsp_log_name  = "bspfront";
&main();
&tidy_up();
exit(0);






sub LongUsage {
  local($pager) = "more";
 
  $pager = $ENV{'PAGER'} if ($ENV{'PAGER'});
  if      (-e $bsp_library_dir . "/man/cat1/bspfront.1") {
    &run_something("$pager " . $bsp_library_dir . "/man/cat1/bspfront.1");
  } elsif (-e $bsp_library_dir . "/man/man1/bspfront.1") {
    &run_something("nroff -man " . $bsp_library_dir . "/man/man1/bspfront.1".
                   "| $pager");
  } else {
    print STDERR "Unable to find manual page in directory ",
                 $bsp_library_dir , "/man/man1/bspfront.1\n";
  }

}






sub main {
  local($i,$j);

  unshift(@ARGV,split(/\s+/,$bspfrontOptimisationPackages{$Arch}));
arg: while($_=$ARGV[0]) {
  shift(@ARGV);

  #--------HELP------------------------------------------------
  /^-(help|man)$/ && do { &LongUsage(); exit(0);};
  
  #--------VERBOSE---------------------------------------------
  /^-v$/i   && do {$Verbose = 1; next arg;};

  #--------Optimisation----------------------------------------
  /^-O$/    && do {$Optimisation=1;
                   next arg;};

  /^-O2$/   && do {$Optimisation=2; 
                   next arg;};

  /^-O3$/   && do {$Optimisation=3; 
                   next arg;};

  /^-flibrary-level$/ &&
                  do {$LibraryLevel = &grab_next_arg("-flibrary-level");
 
                      if ($LibraryLevel  =~ /^(\d+)$/) {
                        $LibraryLevel = int($1);
                        if ($LibraryLevel<0 ||  $LibraryLevel>2) {
                          print STDERR 
                                "$Pgm: -flibrary-level requires an ",
                                "optimisation level in range 0--2\n";
                        $Status++;
                        }
                      } else {
                        print STDERR 
                              "$Pgm: -flibrary-level requires an ",
                              "optimisation level\n";
                        $Status++;
                      }
                      next arg;};

  /^-fcombine-puts$/ && 
                  do {$Opt_fcombine_puts=1;next arg;};

  /^-fcombine-puts-buffer$/ && 
                  do {$Opt_fcombine_puts_size 
                        = &grab_next_arg("-fcombine-puts-buffer");
                      if      ($Opt_fcombine_puts_size =~ /^(\d+)K$/i) {
                        $Opt_fcombine_puts_size= 1024*int($1);
                      } elsif ($Opt_fcombine_puts_size =~ /^(\d+)$/i) {
                        $Opt_fcombine_puts_size = int($1); 
                      } else {
                        print STDERR 
                              "$Pgm: -fcombine-puts-buffer requires an ",
                              "integer argument\n";
                        $Status++;
                      }
                      next arg;};

  /^-fnocombine-puts$/ && 
                  do {$Opt_fcombine_puts=0;next arg;};

  /^-fcontention-resolve$/ &&
                  do {$Opt_fcontention_resolve 
                        = &grab_next_arg("-fcontention-resolve");
 
                      if ($Opt_fcontention_resolve  =~ /^(\d+)$/) {
                        $Opt_fcontention_resolve = $1;
                      } else {
                        print STDERR 
                              "$Pgm: -fcontention-resolve requires an ",
                              "optimisation level\n";
                        $Status++;
                      }
                      next arg;};

  #--------Debugging-------------------------------------------
  /^-debug$/   && do {$Debug    = 1; 
                      push(@Cpp_defines,"DEBUG");
		      push(@Comp_flags,"-g");
                      next arg;};

  /^-g$/       && do {$UnixDebug= 1; 
		      push(@Comp_flags,"-g");
                      next arg;};

  /^-keep$/    && do {$KeepTemps= 1; next arg;};

  /^-fcheck-syncs$/   && do {$bsp_check_syncs= 1; next arg;};
  /^-fnocheck-syncs$/ && do {$bsp_check_syncs= 0; next arg;};

  #--------Profiling-------------------------------------------
  /^-stat$/  && do {$Stat     = 1; next arg;};
  /^-prof$/  && do {$Prof     = 1; next arg;};
  /^-nof77munging$/
             && do {$Do_fpp    =0; next arg;};

  /^-fthrottle-procs$/   && do {$bsp_throttle_procs = 1; next arg;};
  /^-fnothrottle-procs$/ && do {$bsp_throttle_procs = 0; next arg;};
  

  #--------Suppress linker-------------------------------------
  /^-c$/    && do {$Do_ld = 0; next arg;};

  #--------Output file-----------------------------------------
  # -o <file>
  /^-o$/    && do {$Given_output_file = &grab_next_arg("-o");
                   if ($Given_output_file =~ /\/[^\/]*$/) {
                     if (! -d $`) {
                        print STDERR "$Pgm: no such directory $`\n";
                        $Status++;
                     }
                   }
                   next arg;
                  };
  #--------CPP Defines----------------------------------------
  /^-D/     && do {push(@Cpp_defines,$'); next arg;};
  /^-U/     && do {push(@Cpp_undefines,$'); next arg;};

  #--------FLAGS passed straight onto a compiler phase--------
  /^-f77$/      && do {$LD       = $f77Arch{$Arch}; 
                       $LD_is_f77=1;
                       next arg;};

  /^-c\+\+$/&& do {$LD = $cplusplusArch{$Arch};next arg;};

  /^-cflags$/   && do {$CC_extra_flags=&grab_next_arg("-cflags");  
                       next arg;};

  /^-c\+\+flags$/ && do {$CC_extra_flags=&grab_next_arg("-cflags");  
                       next arg;};

  /^-f77flags$/ && do {$F77_extra_flags=&grab_next_arg("-f77flags"); 
                       next arg;};

  /^-ldflags$/  && do {$LD_extra_flags=&grab_next_arg("-ldflags");  
                       next arg;};

  /^-overridecc$/ && do {$CC=&grab_next_arg("-overridecc");
                         $User_overide_compiler=1;
                         next arg;};

  /^-overridec\+\+$/ && do {$CPLUSPLUS=&grab_next_arg("-overridec++");
                         $User_overide_compiler=1;
                         next arg;};

  /^-overridef77$/ && do {$F77=&grab_next_arg("-overridef77");
                         $User_overide_compiler=1;
                         next arg;};

  /^-overrideld$/  && do {$LD=&grab_next_arg("-overrideld");
                         $User_overide_compiler=1;
                         next arg;};

  #--------Set runtime buffer sizes---------------------------
  /^-bspbuffer$/&& do {$bsp_buffer_size = &grab_next_arg("-bspbuffer");
                       if      ($bsp_buffer_size =~ /^(\d+)K$/i) {
                         $bsp_buffer_size = 1024*int($1);
                       } elsif ($bsp_buffer_size =~ /^(\d+)$/i) {
                         $bsp_buffer_size = int($1); 
                       } else {
                         print STDERR "$Pgm: -bspbuffer requires an ",
                                      "integer argument\n";
                         $Status++;
                       }
                       next arg;};

  /^-bspnobuffers$/&& 
                    do {$bsp_no_buffers = &grab_next_arg("-bspnobuffers");
                        if      ($bsp_no_buffers =~ /^(\d+)$/i) {
                          $bsp_no_buffers = int($1);
                        } else {
                         print STDERR "$Pgm: -bspnobuffers requires an ",
                                      "integer argument\n";
                         $Status++;
                       }
                       next arg;};

  

  /^-bspfifo$/  && do {$bsp_comm_fifo_size = &grab_next_arg("-bspfifo");
                       if      ($bsp_comm_fifo_size =~ /^(\d+)K$/i) {
                         $bsp_comm_fifo_size = 1024*int($1);
                       } elsif ($bsp_comm_fifo_size =~ /^(\d+)$/i) {
                         $bsp_comm_fifo_size = int($1); 
                       } else {
                         print STDERR "$Pgm: -bspfifo requires an ",
                                      "integer argument\n";
                         $Status++;
                       }
                       next arg;};

  /^-ffixed-bsmp-buffers$/  
                && do {$Opt_fbsmp_buffers= 
                          &grab_next_arg("-ffixed-bsmp-buffers");
                       if      ($Opt_fbsmp_buffers =~ /^(\d+)K$/i) {
                         $Opt_fbsmp_buffers = 1024*int($1);
                       } elsif ($Opt_fbsmp_buffers =~ /^(\d+)$/i) {
                         $Opt_fbsmp_buffers = int($1); 
                       } else {
                         print STDERR "$Pgm: -ffixed-bsmp-buffers requires ",
                                      "an integer argument\n";
                         $Status++;
                       }
                       next arg;};

  /^-finfinite-bsmp-buffers$/ && do {$Opt_fbsmp_buffers=-1;next arg;};

  #--------Libraries------------------------------------------
  /^-l/   && do {push(@Library_user,$'); next arg;};

  /^-L/   && do {if (-d $') {
                     push(@Library_dir,$'); 
                  } else {
                     print STDERR "$Pgm: Library directory \"$'\" does",
                                  "not exist";
                     $Status++;
                  }
                  next arg;};
  #--------BSP library munging--------------------------------

  /^-mpi$/    && do {$Mpi = 1;
                     push(@Library_dir,$mpi_library_dir{$Arch});
                     next arg;
                     };
  #--------Imports---------------------------------------------

  /^-I/ && do {if (-d $') {
                     push(@Import_dir,$'); 
                  } else {
                     print STDERR "\n**warning** Import directory \"$'\"",
                                  " does not exist\n";
                  }
                  next arg;};

  #--------Special options-------------------------------------

  /^-showlog$/&& do {if (!opendir(LIBDIR,"$bsp_library_dir/lib/")) {
                       print STDERR "$Pgm: unable to open the directory ",
                                    "$bsp_library_dir/lib\n";
                       $Status++;
                     }
                     foreach $i (sort (readdir(LIBDIR))) {
                       $j = "$bsp_library_dir/lib/$i/$bsp_log_name";
                       if (-e $j.".pag") {
                         print "Reading usage for $i\n" if $Verbose;
                         &readUsageInformation($j,$i);
                       }
                     }
                     closedir(LIBDIR);
                     next arg;};

  #--------Input file-----------------------------------------
  /\.(o|a)$/   && do {push(@Link_files, $_); 
                   next arg;};

  if (/\.lf$/    || /\.f$/     || 
      /\.lc$/    || /\.c$/     || 
      /\.lc\+\+/ || /\.c\+\+$/ ||
      /\.lcc/    || /\.cc$/) {
      if (-f $_) {
        push(@Input_files,$_);
      } else {
        print STDERR "$Pgm: input file doesn't exit: $_\n";
        $Status++;
      }
  } elsif (/^-/) {
    push(@Comp_flags,$_);
  } else {
    push(@Link_files, $_); 
  }
  }

  if (($#Input_files <0) && ($#Link_files<0)) {
    printf STDERR "$Pgm: no input files specified\n";
    $Status++;
  }
  
  if ($Status > 0) {
    print STDERR "\n$Pgm usage: for basic information, try ",
                 "the `-help' option\n";
    exit(1);
  }
  
  &driverTag()     if $Verbose;
  local($file);
  
  push(@Input_files,&preloadInitFile(@Input_files,@Link_files)) if $Do_ld;
  foreach $file (@Input_files) {
    &compileFile($file);
  }
  if ($Do_ld) {
   foreach $file (@Input_files) {
     $file =~ /\.[^\.]+$/ && (push(@Link_files,$`.".o"));
   }
   
   if ($Mpi) {
     push(@Library_sys,"bspcorempi". &libraryExtension());
     push(@Library_sys,"mpi");
     push(@Library_sys,"mpihack")  if (!$LD_is_f77);
   } else {
     push(@Library_sys,"bspcore". &libraryExtension());
   }

   push(@Library_sys,"bsplevel1_O$LibraryLevel");
   push(@Library_sys,$librariesArch{$Arch});
   ($Given_output_file eq "") && ($Given_output_file = "a.out");

   if ($LD_is_f77) {
     $LD_extra_flags .= " " . &addprefix_concat(" ",@FComp_flags);
   } else {
     $LD_extra_flags .= " " . &addprefix_concat(" ",@CComp_flags);
   }
   &run_something("$LD " .
                      &addprefix_concat(" ",@Comp_flags)     .
                      &addprefix_concat(" ",@Ld_flags)       .
                      " $LD_extra_flags "                    .
                      &addprefix_concat(" -I",@Import_dir)   .
                      " -o $Given_output_file "              .
                      join(" ",@Link_files)                  .
                      &addprefix_concat(" -L",@Library_dir)  .
                      &addprefix_concat(" -l",@Library_user) .
                      &addprefix_concat(" -l",@Library_sys)  ,
                  "Unix linker");                  
    print STDERR 
        "**warning** to run the program on N processors use:\n",
        "\tmpirun -machinefile <host-list> -np N ",
        "$Given_output_file\n" if $Mpi;
    &logUsageInformation() if $bsp_log_usage;

    if ($LibraryLevel!=2) {
      print STDERR
        "**warning** programs may run slow at ",
        "-flibrary-level $LibraryLevel. See $Pgm(1).\n";
    }
  }
}

sub libraryExtension {
   local($prefix);

   $prefix = "_O";
   $Debug     && ($prefix = "_G");
   $UnixDebug && ($prefix = "_g");
   $Prof      && ($prefix = "_P");
   return ("$prefix$LibraryLevel");
}






sub compileFile {
  local($filename) =$_[0];
  local($CCcomp);
  local($basename);
  local($filename_postlit); 
  local($filename_precpp);
  local($filename_postcpp);
  local($filename_bspcpp);
  local($filename_object);
  local($f77infile);
  local($cfile_extension)=".c";

  $filename =~ /\.[^\.]+$/ && ($basename = $`);

  if      ($filename =~ /\.lc$/) {
     &run_something("$UNLIT $filename", 
                    "Program that extracts C from a literate program");
     $filename_postlit = $basename . ".c";
     push(@Files_to_tidy,$filename_postlit) if (!$UnixDebug);
     $CCcomp = $CC;
  }
  elsif ($filename =~ /\.lc\+\+$/) {
     &run_something("$UNLIT $filename", 
                    "Program that extracts C from a literate program");
     $filename_postlit = $basename . ".c++";
     $cfile_extension  = ".c++";
     push(@Files_to_tidy,$filename_postlit) if (!$UnixDebug);  
     $CCcomp = $CPLUSPLUS;
  } 
  elsif ($filename =~ /\.lcc$/) {
     &run_something("$UNLIT $filename", 
                    "Program that extracts C from a literate program");
     $filename_postlit = $basename . ".cc";
     $cfile_extension  = ".cc";
     push(@Files_to_tidy,$filename_postlit) if (!$UnixDebug);  
     $CCcomp = $CPLUSPLUS;
  } 
  elsif ($filename =~ /\.lf$/) {
     $Do_f77          = 1;
     $Do_cc           = 0;
     &run_something("$UNLIT $filename", 
                    "Program that extract F77 from a literate program");
     $filename_postlit = $basename       . ".f";
     push(@Files_to_tidy,$filename_postlit) if (!$UnixDebug);
  } 
  elsif ($filename =~ /\.f$/) {
     $Do_f77          = 1;
     $Do_cc           = 0;
     $filename_postlit = $filename;
  } 
  elsif ($filename =~ /\.cc$/) {
     $Do_f77          = 0;
     $Do_cc           = 1;
     $cfile_extension  = ".cc";
     $filename_postlit = $filename;
     $CCcomp = $CPLUSPLUS;
  }
  elsif ($filename =~ /\.c\+\+$/) {
     $Do_f77          = 0;
     $Do_cc           = 1;
     $filename_postlit = $filename;
     $cfile_extension  = ".c++";
     $CCcomp = $CPLUSPLUS;
  }
  elsif ($filename =~ /\.c$/) {
     $Do_f77          = 0;
     $Do_cc           = 1;
     $filename_postlit = $filename;
     $CCcomp = $CC;
  }
  
  if (!$User_overide_compiler) {
    $Do_cc  && (push(@CComp_flags,$coptFlagsArch{$Arch ."-O".$Optimisation}));
    $Do_f77 && (push(@FComp_flags,$foptFlagsArch{$Arch ."-O".$Optimisation}));
  }
   
  if (!$Do_ld && $Given_output_file ne "") {
    $filename_object = $Given_output_file;
  } else {
    $filename_object = $basename . ".o";
  }


  
  if ($Do_cc) {
    &run_something("$CCcomp -c ". 
                      &addprefix_concat(" -I",@Import_dir) .
                      &addprefix_concat(" -D",@Cpp_defines) .
                      &addprefix_concat(" -U",@Cpp_undefines) .
                      &addprefix_concat(" ",@CComp_flags) .
                      &addprefix_concat(" ",@Comp_flags) .
                      " $CC_extra_flags ".
                      " $filename_postlit ",
                   "C compiler");

                               
  } else {
    if ($Do_fpp) {
      $f77infile = $Tmpfile_prefix  . ".f";
      &run_something("$FPP  ".
                       $filename         . " ".
                       $filename_postlit . " ".
                       $f77infile,
                     "BSP Fortran pre-processor");
                    
                            
    } else {
      $f77infile = $filename_postlit;
    }
    if (!$f77doesCpp{$Arch}) {
       @Cpp_defines  =();
       @Cpp_undefines=();
    }
    &run_something("$F77 -c ". 
                      &addprefix_concat(" -I",@Import_dir) .
                      &addprefix_concat(" -D",@Cpp_defines) .
                      &addprefix_concat(" -U",@Cpp_undefines) .
                      &addprefix_concat(" ",@FComp_flags) .
                      &addprefix_concat(" ",@Comp_flags) .
                      " $F77_extra_flags ".
                      " $f77infile ",
                   "Fortran 77 compiler (file $filename)");

   }

  if (-e "$Tmpfile_prefix.o") {
    &run_something("mv $Tmpfile_prefix.o $filename_object",
                   "unix mv of the temporary object file");
  } elsif (($basename . ".o") ne $filename_object) {
    &run_something("mv " . $basename . ".o $filename_object",
                   "unix mv of the temporary object file");
  }
  push(@Files_to_tidy,$basename.".o") if ($Do_ld);
}







sub preloadInitFile {
  local(@linker_files);
  local(@extra_flags);
  local($fcombine_size)=0;

  @extra_flags = ();
  push(@extra_flags,"-O$Optimisation")     if $Optimisation>0;
  push(@extra_flags,"-fcombine-puts")      if $Opt_fcombine_puts;
  $fcombine_size = $Opt_fcombine_puts_size if $Opt_fcombine_puts;
  if ($Opt_fcontention_resolve) {
    push(@extra_flags,"-fcontention-resolve $Opt_fcontention_resolve");
  } 

  print STDERR "Preload file:\n\t" 		if $Verbose;
  print STDERR "creating $Tmpfile_prefix\n"	if $Verbose;

  open(PRELOAD,"> " . $Tmpfile_prefix . "_preload.c") ||
  &tidy_up_and_die(1,"$Pgm: cannot create temporary file. File system full?");

  print PRELOAD "/* " , @linker_files , "*/\n";
  print PRELOAD<<"_ENDPRELOAD_";

#include "bsp.h"
#include <stdlib.h>
#include <string.h>

extern int BSP_DO_STAT;
extern int BSP_NBUFFERS;
extern int BSP_BUFFER_SIZE;
extern int BSP_THROTTLE_PROCS;
extern int BSP_COMM_FIFO_SIZE;
extern int BSP_OPT_CONTENTION_LEVEL;
extern int BSP_OPT_FCOMBINE_PUTS;
extern int BSP_OPT_BSMP_BUFFER_SIZE;
extern char *BSP_COMPILE_FLAGS;
extern char *BSP_ARCH;
extern char *BSP_ROOT_DIR;
extern int BSP_CHECK_SYNCS;

void _bsp_preload_init() {
   BSP_DO_STAT          = $Stat;
   BSP_NBUFFERS         = $bsp_no_buffers;
   BSP_BUFFER_SIZE      = $bsp_buffer_size;
   BSP_THROTTLE_PROCS   = $bsp_throttle_procs;
   BSP_COMM_FIFO_SIZE   = $bsp_comm_fifo_size;
   BSP_OPT_CONTENTION_LEVEL = $Opt_fcontention_resolve;
   BSP_OPT_FCOMBINE_PUTS= $fcombine_size;
   BSP_OPT_BSMP_BUFFER_SIZE =$Opt_fbsmp_buffers;
   BSP_COMPILE_FLAGS  = (char*) malloc(sizeof(char)*(1+strlen("@Comp_flags @extra_flags")));
   BSP_ARCH=(char*) malloc(sizeof(char)*(1+strlen("$Arch")));
   BSP_ROOT_DIR=(char*) malloc(sizeof(char)*(1+strlen("$bsp_library_dir")));
   if (BSP_COMPILE_FLAGS==NULL || BSP_ARCH==NULL || BSP_ROOT_DIR==NULL)
     bsp_abort("{bsp_start}: unable to malloc for compile flags");
   BSP_COMPILE_FLAGS=strcpy(BSP_COMPILE_FLAGS, "@Comp_flags @extra_flags");
   BSP_ARCH         =strcpy(BSP_ARCH,"$Arch");
   BSP_ROOT_DIR     =strcpy(BSP_ROOT_DIR,"$bsp_library_dir");
   BSP_CHECK_SYNCS  =$bsp_check_syncs;
}
_ENDPRELOAD_
  close(PRELOAD);
  return($Tmpfile_prefix . "_preload.c");
}







sub grab_next_arg {
  local($option) = $_[0];
  local($temp);
  if ($#ARGV >= 0) {
    $temp = $ARGV[0]; shift(@ARGV); 
    return($temp);
  } else {
    print STDERR "$Pgm: no argument following $option option\n";
    $Status++;
  }
}






sub addprefix_concat {
  local($prefix,@list) = @_;
  if ($#list<0) {
    return "";
  } else {
    return ($prefix . join($prefix,@list));
  }
}






sub run_something {
  local($str_to_do, $tidy_name) = @_;
  local($return_val) = 0;
  local($die_msg);

  print STDERR "\n$tidy_name:\n\t" if $Verbose;
  print STDERR "$str_to_do\n"      if $Verbose;

  system("$str_to_do");
  $return_val = $?;
  if ($return_val != 0) {
    $die_msg = "$Pgm: execution of the $tidy_name had trouble";
    $die_msg .= " (program not found)" if $return_val == 255;
    $die_msg .= " ($!)" if $Verbose && $! != 0;
    $die_msg .= "\n";
    &tidy_up_and_die($return_val, $die_msg);
  }
}






sub tidy_up {
  local($return_val, $msg) = @_;
  print STDERR "deleting... @Files_to_tidy\n" if $Verbose && 
                                                 $#Files_to_tidy >= 0;
  unlink @Files_to_tidy                       if  $#Files_to_tidy>= 0 &&
                                                 !$KeepTemps;
  system("rm -f $Tmpfile_prefix*")            if !$KeepTemps;
  print STDERR $msg;
}

sub tidy_up_and_die {
   &tidy_up(@_);
   exit(1);
}






sub driverTag {
  local($str);
  if ($Opt_fbsmp_buffers==-1) {
    $str = "-fininite-bsmp-buffers";
  } else {
    $str = "-ffixed-bsmp-buffers  = $Opt_fbsmp_buffers";
  }
print <<"_ENDTAG_";
===================================================
===  This is $Pgm version $Version.           
===  Using a $Arch to compile a BSP C or Fortran 
===  programs for a $Arch.
===================================================
BSPlib system options:
        -fcheck-syncs         = $bsp_check_syncs
	-fcombine-puts        = $Opt_fcombine_puts
    	-fcombine-puts-buffer = $Opt_fcombine_puts_size bytes
        -fcontention-resolve  = $Opt_fcontention_resolve
        $str
        -bspnobuffers         = $bsp_no_buffers per process
        -bspbuffer            = $bsp_buffer_size bytes
        -bspfifo              = $bsp_comm_fifo_size elements
===================================================
_ENDTAG_
}








sub logUsageInformation {
  local(%logfile);
  local($i,$user,$logfilename);
  local($timestr,$van0,$van1,$van2,$P0,$P1,$P2,$g0,$g1,$g2,$ext);
  require "ctime.pl";

  chop($timestr = &ctime(time) );

  $logfilename = "$bsp_library_dir/lib/$Arch/$bsp_log_name";
  print "Logging usage to $logfilename\n" if $Verbose;
  if (dbmopen(logfile,$logfilename,0777)) {
    $user = $ENV{'USER'};
    $user = "<anonymous>" if ($user eq "");
    if (!$logfile{$user}) {
      $logfile{$user} = $timestr . '@@ 0 0 0 0 0 0 0 0 0';
    } else {
      $logfile{$user}=~/(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)/;
      $van0 = int($1);
      $van1 = int($2);
      $van2 = int($3);
      $P0   = int($4);
      $P1   = int($5);
      $P2   = int($6);
      $g0   = int($7);
      $g1   = int($8);
      $g2   = int($9);
     
      $ext = &libraryExtension();
      $van0++ if ($ext eq "_O0");
      $van1++ if ($ext eq "_O1");
      $van2++ if ($ext eq "_O2");
      $P0++   if ($ext eq "_P0");
      $P1++   if ($ext eq "_P1");
      $P2++   if ($ext eq "_P2");
      $g0++   if ($ext eq "_g0");
      $g1++   if ($ext eq "_g1");
      $g2++   if ($ext eq "_g2");
      $logfile{$user} = "$timestr \@\@ $van0 $van1 $van2 $P0 $P1 $P2 $g0 $g1 $g2";
    }
    dbmclose(logfile);
  }
}



sub readUsageInformation {
  local($dbmfile,$machine)=@_;
  local(%logfile);
  local($user,$van0,$van1,$van2,$P0,$P1,$P2,$g0,$g1,$g2,$ext);
  
  format top =
____________________________________________________________________________
 Machine|  User |     Date    |  0 | 1  | 2  | P0 | P1 | P2 | g0 | g1 | g2 |
--------+-------+-------------+----+----+----+----+----+----+----+----+----|
.


  format STDOUT =
@>>>>>>>|@>>>>>>|@>>>>>>>>>>>>|@>>>|@>>>|@>>>|@>>>|@>>>|@>>>|@>>>|@>>>|@>>>|
$machine, $user,$time,$van0,$van1,$van2,$P0,$P1,$P2,$g0,$g1,$g2
.

  print "Reading usage to $bsp_logfile\n" if $Verbose;
  if (dbmopen(logfile,$dbmfile,0700)) {
    
    foreach $user (sort (keys %logfile)) {
      $logfile{$user}=~/(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)/;
      $time    = $`;
      $van0    = $1;
      $van0    = "" if $van0 eq "0";

      $van1    = $2;
      $van1    = "" if $van1 eq "0";

      $van2    = $3;
      $van2    = "" if $van2 eq "0";

      $P0      = $4;
      $P0      = "" if $P0 eq "0";

      $P1      = $5;
      $P1      = "" if $P1 eq "0";

      $P2      = $6;
      $P2      = "" if $P2 eq "0";

      $g0      = $7;
      $g0      = "" if $g0 eq "0";

      $g1      = $8;
      $g1      = "" if $g1 eq "0";

      $g2      = $9;
      $g2      = "" if $g2 eq "0";

      $time    =~ /\s*(\S+)\s+(\d+)\s+(\d+:\d+)/ && ($time = "$1 $2 $3");
      write;
    }
    dbmclose(logfile);
  }
}

