#!/usr/bin/perl

# BEGIN _vac/xlf_configure_
#*******************************************************************************
#*
#* Licensed Materials - Property of IBM
#* IBM XL C for OpenCL, V0.3 (technology preview)
#* technology preview
#* 
#* Copyright IBM Corp. 1989, 2007, and by others.   All Rights Reserved.
#* IBM is a registered trademark of IBM Corp. in the U.S., other
#* countries or both.
#* US Government Users Restricted Rights - Use, duplication or disclosure
#* restricted by GSA ADP Schedule Contract with IBM Corp.
#*
#* 1/21/11 1.56.30.10
#*******************************************************************************

use File::Basename;
use POSIX qw(locale_h);

{ # _beg_main_
  my $old_locale      = "";
  $old_locale         = setlocale(LC_CTYPE);
  $ENV{LANG}          = "en_US";

  local $__BG_VERSION__  = undef;
  local $__OPENCL_MODE__    = "cbe";
  local $__MASS_VERSION__   = undef;
  local $__SMP_VERSION__    = undef;
  local $__XLCPP_VERSION__  = "0.3";
  local $__XLUPC_VERSION__  = undef;
  local $__XLF_VERSION__    = undef;
  local $__XLC_PRODNAME__   = "xlc";
  local $__XLF_PRODNAME__   = "xlf";
  local $__XLCPP_PRODNAME__ = "xlc";
  local $__XLUPC_PRODNAME__ = 'upc';
  local $cProdname       = $__XLC_PRODNAME__;
  local $cxxProdname     = $__XLCPP_PRODNAME__;
  local $upcProdname     = $__XLUPC_PRODNAME__;
  local $fortranProdname = $__XLF_PRODNAME__;
  local $excld_hdrs      = undef;


  local ($umask)      = "0022";
  local (%opt)        = &optParse();
  local ($prod, $ver) = &guess_prod_name ();
  local ($smpver)     = &get_smp_ver ();
  local ($massver)    = &get_mass_ver ();
  local ($gccver, $targetgccver);
  local (@compilers);
  local (%stdinc_c, %stdinc_cxx, %libpath_c, %libpath_cxx, %dynlib_path, %append_attr);
  local (%isTLS);

  # Set the umask to the standard 0077 for root because we cannot assume
  # customer has the proper umask value
  umask oct($umask);

  local (%TEMP);
  $TEMP{'DUMMYC'}      = &gen_tempfile ("${prod}cfg_simple.c");
  $TEMP{'DUMMYCXX'}    = &gen_tempfile ("${prod}cfg_simple.cpp");
  $TEMP{'DUMMYC_TLS'}  = &gen_tempfile ("${prod}cfg_simple_tls.c");
  $TEMP{'OUTPUTC'}     = &gen_tempfile ("${prod}cfg_coutput.gcc");
  $TEMP{'OUTPUTCXX'}   = &gen_tempfile ("${prod}cfg_coutput.g++");
  $TEMP{'TEMPEXEC'}    = &gen_tempfile ("${prod}cfg_simple");
  $TEMP{'TEMPLATE'}    = &gen_tempfile ("${prod}cfg_template");
  $TEMP{'TEMPOUT'}     = &gen_tempfile ("${prod}cfg_tempout");

  my (%gcc_invok) = &set_gcc_invocations ();

  local (%exec_c) = (
    'gcc32'       => $gcc_invok{'gcc32'},
    'gcc64'       => $gcc_invok{'gcc64'},
    'targetgcc32' => $gcc_invok{'targetgcc32'},
    'targetgcc64' => $gcc_invok{'targetgcc64'},
  );

  local (%exec_cxx) = (
    'gcc32'       => $gcc_invok{'g++32'},
    'gcc64'       => $gcc_invok{'g++64'},
    'targetgcc32' => $gcc_invok{'targetg++32'},
    'targetgcc64' => $gcc_invok{'targetg++64'},
  );

  local (%opts_c);
  local (%opts_cxx);
  $opts_c{'gcc32'}   = '-m32';
  $opts_cxx{'gcc32'} = '-m32';
  $opts_c{'gcc64'}   = '-m64';
  $opts_cxx{'gcc64'} = '-m64';

  &printDebug ("###CONFIGURE### ($0) started..");
  %opt = &set_defaults  (%opt);
  %opt = &validate_args (%opt);

  my (%gnu_macros);
  my (@gnu_macros) = (
    '__GNUC__',
    '__GNUC_MINOR__',
    '__GNUC_PATCHLEVEL__',
  );
  push (@gnu_macros, '__APPLE_CC__') if (&isMacOSX);

  my (%os_macros);

  my (%exefiles);
  my (@exefiles) = (
    'as',
    'ld',
  );

  my (%exefiles_defaults) = (
    'as'             => 'as',
    'ld'             => 'ld',
  );

  my (%crtfiles);
  my (@crtfiles) = (
    'crtbegin',
    'crt2',
  );
  push (@crtfiles,
    'crt',
    'gcrt',
    'mcrt',
    'crtp',
    'crte',
    'crtbegin_s',
    'crtbegin_t',
    'crtend',
    'crtend_s',
  ) if (&isLinux);

  my (%crtfiles_defaults) = (
    'crt2'        => 'crt2.o',
    'crtbegin'    => 'crtbegin.o',
    'crtbegin_s'  => 'crtbeginS.o',
    'crtbegin_t'  => 'crtbeginT.o',
    'crtend'      => 'crtend.o',
    'crtend_s'    => 'crtendS.o',
    'crtp'        => 'crti.o',
    'crte'        => 'crtn.o',
    'gcrt'        => 'gcrt1.o',
    'mcrt'        => 'gcrt1.o',
  );

  my (%prodfiles);
  my (@prodfiles) = (
    'bolt',
    'code',
    'defaultmsg',
    'ipa',
  ); # END @prodfiles
  my (%prodfiles_defaults) = (
    'bolt'           => 'bolt',
    'ccomp'          => 'xlcentry',
    'cobjcomp'       => 'xlctpentry',
    'cpp'            => 'cpp',
    'cppcomp'        => 'xlCentry',
    'defaultmsg'     => 'en_US',
    'dis'            => 'dis',
    'hot'            => 'xlfhot',
    'ipa'            => 'ipa',
    'xlf'            => 'xlfentry',
    'xlC'            => 'xlC',
    'list'           => 'xllist',
    'xslt'           => 'XALAN',
  );

  push (@prodfiles,
    'dis',
    'list',
    'xslt',
  ) if (&isLinux);

  if (&isBG) {
    $crtfiles_defaults{'targetgcc32,crtbegin'}  = 'crtbeginT.o';
    push (@prodfiles, 'targetgcc32,bolt');
    push (@crtfiles,  'targetgcc32,crtbegin');
    if (&isBG) {
      $prodfiles_defaults{'targetgcc32,bolt'} = 'bolt';
      $prodfiles_defaults{'targetgcc32,xlC'}  = 'bgxlC';
    }
  }

  if (&isOpenCL) {
    $prodfiles_defaults{'spu-xlcl:xlC'}         = 'spu-xlcl';
    $prodfiles_defaults{'ppu-xlcl:xlC'}         = 'ppu-xlcl';
    $prodfiles_defaults{'DEFLT:xlC'}            = 'xlcl';
    $prodfiles_defaults{'ldscript_opt'}         = 'linkscript.generic.template';
    foreach ('spu-xlcl:xlC','ppu-xlcl:xlC','DEFLT:xlC','ldscript_opt') { push(@prodfiles, $_); }
    foreach ('spu-xlcl:crt','spu-xlcl:gcrt', 'spu-xlcl:crt2', 'spu-xlcl:gcrt2', 'spu-xlcl:crtp',
             'spu-xlcl:crte', 'spu-xlcl:mcrt', 'spu-xlcl:crtbegin', 'spu-xlcl:crtend', 'spu-xlcl:modes_configure',
             'spu-xlcl:__GNUC_MINOR__', 'spu-xlcl:__GNUC_PATCHLEVEL__', 'spu-xlcl:__GNUC__',
             'spu-xlcl:gcc_libdirs','spu-xlcl:gcc_c_stdinc','spu-xlcl:libdirs',
             'ppu-xlcl:gcc_libdirs','ppu-xlcl:gcc_libdirs_64',
             'ppu-xlcl:crtbegin', 'ppu-xlcl:crtbegin_s', 'ppu-xlcl:crtbegin_t', 'ppu-xlcl:crtend',
             'ppu-xlcl:crtend_s', 'ppu-xlcl:crtsavres', 'ppu-xlcl:crtbegin_64', 'ppu-xlcl:crtbegin_s_64',
             'ppu-xlcl:crtbegin_t_64', 'ppu-xlcl:crtend_64', 'ppu-xlcl:crtend_s_64', 'ppu-xlcl:crtsavres_64',
             'ppu-xlcl:__GNUC__', 'ppu-xlcl:__GNUC_MINOR__', 'ppu-xlcl:__GNUC_PATCHLEVEL__',
             'spu-xlcl:as', 'spu-xlcl:spu_as', 'spu-xlcl:ld', 'spu-xlcl:objcopy', 'spu-xlcl:readelf',
             'ppu-xlcl:as', 'ppu-xlcl:as_64', 'ppu-xlcl:ld', 'ppu-xlcl:ld_64',
             'ppu-xlcl:objcopy', 'ppu-xlcl:/ppu-readelf')
      { push(@staticfiles, $_); }
    $crtfiles_defaults{'crtsavres'}            = 'crtsavres.o';
    push (@crtfiles, 'crtsavres');
  } else {
    push (@crtfiles, 'crtsavres');
    push (@prodfiles, 'artool');
    $crtfiles_defaults{'crtsavres'}            = 'crtsavres.o';
    $prodfiles_defaults{'artool'}              = 'ar.extract';
  }

  if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
    push (@prodfiles,
      'ccomp',
    );
    push (@prodfiles,
      'cobjcomp',
    ) if (&isMacOSX);
    $prodfiles_defaults{'code'} = 'xlCcode';
  } # END _if_prod_vac_vacpp_

  if (&isCxxProd) {
    push (@prodfiles,
      'cppcomp',
      'xlC',
    );
  } # END _if_prod_vacpp_

  push (@prodfiles, 'targetgcc32,xlC') if &isCxxBgProd;

  if (&isFortranProd) {
    push (@prodfiles,
      'cpp',
      'hot',
      'xlf',
    );
    $prodfiles_defaults{'code'} = 'xlfcode';
  } # END _if_prod_xlf_

  # configuration file attributes that are allowed to be NULL
  my (@ok_to_be_null);

  # initialize the arrays in %append_attr with the appropriate separator
  %append_attr = (
    'ALL:options'    => [',',],
    'DEFLT:options'  => [',',],
  );

  #*****************************************************************************

  foreach $f (@exefiles) {
    $exefiles{$f} = read_templ_attr ($opt{'source'}, $f);
    if (!(defined ($exefiles{$f})) and (defined ($exefiles_defaults{$f}))) {
      printDebug("Attribute \"$f\" set to default \"$exefiles_defaults{$f}\"");
      $exefiles{$f} = $exefiles_defaults{$f};
    } # END _set_defaults_
    printAndDie("Template file \"$opt{'source'}\" is missing attribute \"$f\".")
      unless (defined ($exefiles{$f}));
  } # END _foreach_exefiles_

  foreach $f (@crtfiles) {
    $crtfiles{$f} = read_templ_attr ($opt{'source'}, $f);
    if (!(defined ($crtfiles{$f})) and (defined ($crtfiles_defaults{$f}))) {
      printDebug("Attribute \"$f\" set to default \"$crtfiles_defaults{$f}\"");
      $crtfiles{$f} = $crtfiles_defaults{$f};
    } # END _set_defaults_
    printAndDie("Template file \"$opt{'source'}\" is missing attribute \"$f\".")
      unless (defined ($crtfiles{$f}));
  } # END _foreach_crtfiles_

  foreach $f (@prodfiles) {
    $prodfiles{$f} = read_templ_attr ($opt{'source'}, $f);
    if (!(defined ($prodfiles{$f})) and (defined ($prodfiles_defaults{$f}))) {
      printDebug("Attribute \"$f\" set to default \"$prodfiles_defaults{$f}\"");
      $prodfiles{$f} = $prodfiles_defaults{$f};
    } # END _set_defaults_
    printAndDie("Template file \"$opt{'source'}\" is missing attribute \"$f\".")
      unless (defined ($prodfiles{$f}));
  } # END _foreach_prodfiles_

  my ($depth) = (&isBG ? 3 : 2);
  my ($libPrefix) = &getStanzaPrefix('targetgcc32');
  my (@Llist)     = ();;
  my (@Rlist)     = ();
  my (@Llist_alt)  = ();
  my (@Rlist_alt)  = ();

  if (&isOpenCL) {
  } else {
    @Rlist = (join ("/", chop_path ($opt{'smprt'}, $depth), "lib") .  &getCompilerVariation());
    push(@Llist,    "$opt{'smprt'}/lib");
    push(@Llist,    "$opt{'mass'}/lib");
  }

  push(@Llist_alt, "$opt{'smprt'}/${libPrefix}lib")      if &isBG;
  push(@Llist_alt, "$opt{'mass'}/${libPrefix}lib")       if &isBG;

  my ($Rpath_alt) = "lib" . &getCompilerVariation(). "/${libPrefix}lib";

  if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
    push (@Llist, "$opt{'vac'}/lib");

    push (@Llist_alt, "$opt{'vac'}/${libPrefix}lib")     if &isBG;
  } # END _if_vac_
  if (&isCxxProd) {
    push (@Llist, "$opt{'vacpprt'}/lib");
    push (@Llist, "$opt{'vacpp'}/lib");

    push (@Llist_alt, "$opt{'vacpprt'}/${libPrefix}lib") if &isBG;
    push (@Llist_alt, "$opt{'vacpp'}/${libPrefix}lib")   if &isBG;

    push (@Rlist, join ("/", chop_path ($opt{'vacpprt'}, $depth), "lib") . &getCompilerVariation());
    push (@Rlist, join ("/", chop_path ($opt{'vacpp'}, $depth), "lib")   . &getCompilerVariation());
    push (@Rlist_alt, join ("/", chop_path ($opt{'vacpprt'}, $depth), $Rpath_alt))   if &isBG;
  } # END _if_vacpp_
  if (&isFortranProd) {
    push (@Llist, "$opt{'xlfrt'}/lib");
    push (@Llist, "$opt{'xlf'}/lib");

    push (@Llist_alt, "$opt{'xlfrt'}/${libPrefix}lib")   if &isBG;
    push (@Llist_alt, "$opt{'xlf'}/${libPrefix}lib")     if &isBG;

    push (@Rlist, join ("/", chop_path ($opt{'xlfrt'}, $depth), "lib")   . &getCompilerVariation());
    push (@Rlist, join ("/", chop_path ($opt{'xlf'}, $depth), "lib")     . &getCompilerVariation());
    push (@Rlist_alt, join ("/", chop_path ($opt{'xlfrt'}, $depth), $Rpath_alt))   if &isBG;
  } # END _if_xlf_

  foreach ('gcc32','gcc64','targetgcc32','targetgcc64') {
    push (@compilers, $_) if (defined ($opt{$_}));
  } # _foreach_gcc_

  # Obtain configuration file values from each compiler..
  foreach $cc (@compilers) {
    # Obtain GNU macros..
    foreach $m (@gnu_macros) {
      $gnu_macros{$cc}->{$m} = &get_gnu_macro ("$opt{$cc}/$exec_c{$cc}", $m);
      printAndDie ("Could not determine value of \"$m\" macro.")
        unless (defined ($gnu_macros{$cc}->{$m}));
    } # END _foreach_gnu_macros_
    if (&isMacOSX) {
      push (@ok_to_be_null, 'crtbegin');
    } else {
      push (@ok_to_be_null, 'crt2', 'crtsavres', 'crtsavres_64');
    }

    # Obtain OS variant macros..
    set_os_macros (\%os_macros, $cc);
    foreach $o (sort keys(%{$os_macros{$cc}})) {
      printAndDie ("Could not determine value of \"$o\" macro.")
        unless (defined ($os_macros{$cc}->{$o}));
    }

    # Obtain verbose compilation output..
    my ($output_c)   = &gen_c_output ("$opt{$cc}/$exec_c{$cc} $opts_c{$cc}");
    printAndDie ("Could not obtain \"$opt{$cc}/$exec_c{$cc} $opts_c{$cc}\" -v output.  Ensure you have both 32-bit and 64-bit GCC installed from your operating system install media.")
      unless (defined ($output_c));

    # Compiler standard include paths..
    $stdinc_c{$cc}    = &get_search_path ($output_c);
    printAndDie ("Could not determine standard $cc C search paths")
      unless (defined ($stdinc_c{$cc}));
    $stdinc_c{$cc}   .= ":$opt{'vac'}/C89Amendment1Include" if (&isMacOSX);

    # Compiler library paths..
    $libpath_c{$cc}   = &get_lib_path ($output_c, undef);
    printAndDie ("Could not determine $cc C library paths")
      unless (defined ($libpath_c{$cc}));

    unless (&isOpenCL) {
      my ($output_cxx) = &gen_cxx_output ("$opt{$cc}/$exec_cxx{$cc} $opts_cxx{$cc}");
      printAndDie ("Could not obtain \"$opt{$cc}/$exec_cxx{$cc} $opts_cxx{$cc}\" -v output.  Ensure you have both 32-bit and 64-bit G++ installed from your operating system install media.")
	unless (defined ($output_cxx));
      $stdinc_cxx{$cc}  = &get_search_path ($output_cxx);
      printAndDie ("Could not determine standard $cc C++ search paths")
	unless (defined ($stdinc_cxx{$cc}));
      $stdinc_cxx{$cc} .= ":$opt{'vacpp'}/C89Amendment1Include" if (&isMacOSX);
      $libpath_cxx{$cc} = &get_lib_path ($output_cxx, undef);
      printAndDie ("Could not determine $cc C++ library paths")
	unless (defined ($libpath_cxx{$cc}));
    }

    if ($cc eq "gcc64") {
       $dynlib_path {$cc}    = &get_dynlib_path ($output_c,"64");
    } else {
       $dynlib_path {$cc}    = &get_dynlib_path ($output_c,"32");
    }

    foreach $f (keys (%crtfiles)) {

      next if ($f =~ /,/ && ($cc eq 'gcc32' || $cc eq 'gcc64'));
      # no need to re-search for attr under altInvoc if altInvoc,attr will be searched
      next if (defined $crtfiles{"$cc,$f"});

      $$f{$cc} = &get_lib_path ($output_c, "$crtfiles{$f}");
      if (!defined ($$f{$cc})) {
        if (grep("$f" eq $_, @ok_to_be_null)) {
          $$f{$cc} = 'NULL';
        } else {
          printAndDie ("Could not determine location of \"$crtfiles{$f}\"");
        } # END _if_ok_to_be_null_
      }   # END _if_not_defined_
    } # END _foreach_$f_

    foreach $f (keys (%exefiles)) {

      next if ($f =~ /,/ && ($cc eq 'gcc32' || $cc eq 'gcc64'));

      $$f{$cc} = &get_exe_path ($output_c, $opt{$cc}, "$exefiles{$f}");
      if (!defined ($$f{$cc})) {
        if (grep("$f" eq $_, @ok_to_be_null)) {
          $$f{$cc} = 'NULL';
        } else {
          printAndDie ("Could not determine location of \"$exefiles{$f}\"");
        } # END _if_ok_to_be_null_
      }   # END _if_not_defined_
    } # END _foreach_$f_

    # search for supported compiler options
    unless (&isOpenCL or &isUpcProd ) {
      $isTLS{$cc} = testCompilerOption("$opt{$cc}/$exec_c{$cc}", undef,
        gen_c_tls_program($TEMP{'DUMMYC_TLS'}), undef, 0, undef);
    }

    foreach $cleanup ($TEMP{'OUTPUTC'}, $TEMP{'OUTPUTCXX'}) { unlink ($cleanup); }
  } # END _foreach_compiler_

  # Create configuration file from template..
  my ($modes_configure) = setModesConfigure(readModesConfigure($opt{'source'}));

  my ($include_c)       = join (':', "$opt{'vac'}/include",);
  my ($include_c_alt)   = join (':', "$opt{'vac'}/include",);
  my ($include_cxx)     = join (':', "$opt{'vacpp'}/include",);
  my ($include_cxx_alt) = join (':', "$opt{'vacpp'}/include",);

  if (&isUpcProd || &isOpenCL) {
  } else {
    foreach ($include_c_alt, $include_cxx_alt) { $_ = join (':',
      "$opt{'mass'}/".&getStanzaPrefix."/include", $_); }
    foreach ($include_c, $include_cxx) { $_ = join (':',
      "$opt{'mass'}/include", $_); }
    foreach ($include_c, $include_cxx) { $_ = join (':',
      "$opt{'smprt'}/include", $_); }
  }

  # only linux requires a -R libdir entry..
  unless (&isLinux) { @Rlist = (); }

  my ($libdirs_32) = build_libdirs_list ('32', \@Llist, \@Rlist);

  my ($libdirs_32_alt);
  $libdirs_32_alt  = build_libdirs_list ('32', \@Llist_alt, \@Rlist_alt)    if &isBG;

  my ($libdirs_32_alt_cxx);

  my ($libdirs_64) = build_libdirs_list ('64', \@Llist, \@Rlist);

  my ($libdirs_64_alt);
  $libdirs_64_alt  = build_libdirs_list ('64', \@Llist_alt, \@Rlist_alt)    if &isBGQ;


  my (%attr) = (
    'modes_configure'   => "$modes_configure",
  ); # END _%attr_

  $attr{'targetgcc32,modes_configure'} = 32 if (&isBG);

  if (valueExist('-qnoenablevmx',\@{$append_attr{'DEFLT:options'}}) == 0) {
    if ((&isRHEL) and (&guess_RHEL_ver() =~ /^3/)) {
      push (@{ $append_attr{'DEFLT:options'} }, '-qnoenablevmx');
    }
  } # END _if_valueExist_

  if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
    $attr{'artool'}                = "$opt{'vac'}/exe/$prodfiles{'artool'}"            if (&isLinux);
    $attr{'bolt'}                  = "$opt{'vac'}/exe/$prodfiles{'bolt'}";
    $attr{'targetgcc32,bolt'}      = "$opt{'vac'}/exe/$prodfiles{'targetgcc32,bolt'}"  if (&isBG);
    $attr{'ipa'}                   = "$opt{'vac'}/exe/$prodfiles{'ipa'}";
    $attr{'ccomp'}                 = "$opt{'vac'}/exe/$prodfiles{'ccomp'}";
    $attr{'cobjcomp'}              = "$opt{'vac'}/exe/$prodfiles{'cobjcomp'}"          if (&isMacOSX);
    $attr{'code'}                  = "$opt{'vac'}/exe/$prodfiles{'code'}";
    $attr{'defaultmsg'}            = "$opt{'vac'}/msg/$prodfiles{'defaultmsg'}";
    $attr{'list'}                  = "$opt{'vac'}/exe/$prodfiles{'list'}"              if (&isLinux && !&isBG);
    $attr{'xslt'}                  = "$opt{'vac'}/exe/$prodfiles{'xslt'}"              if (&isLinux && !&isBG);
    $attr{'transforms'}            = "$opt{'vac'}/listings"                            if (&isLinux && !&isBG);
    $attr{'listlibs'}              = "$opt{'vac'}/lib"                                 if (&isLinux && !&isBG);
    $attr{'dis'}                   = "$opt{'vac'}/exe/$prodfiles{'dis'}"               if (&isLinux);
    $attr{'vac_path'}              = "$opt{'vac'}";
    $attr{'xlc_c_stdinc'}          = "$include_c";
    $attr{'xlcmp_path'} = "$opt{'vac'}"                                      if (&useLicPackage);
    $attr{'spu-xlcl:xlC'} = "$opt{'vac'}/bin/$prodfiles{'spu-xlcl:xlC'}" if (&isOpenCL);
    $attr{'ldscript_opt'} = "$opt{'vac'}/exe/$prodfiles{'ldscript_opt'}" if (&isOpenCL);
  } # END _if_vac_vacpp_
  if (&isUpcProd) {
    $attr{'ipa_upc'}               = "$opt{'vac'}/exe/$prodfiles{'ipa'}";
    $attr{'ccomp_upc'}             = "$opt{'vac'}/exe/$prodfiles{'ccomp'}";
    $attr{'xlcmp_path'} = "$opt{'vac'}";
    $attr{'xlC'}                   = "$opt{'vac'}/exe/xlupc";
  } # END isUpcProd
  if (&isCxxProd) {
    $attr{'xlC'}                   = "$opt{'vacpp'}/bin/$prodfiles{'xlC'}";
    $attr{'targetgcc32,xlC'}       = "$opt{'vacpp'}/bin/$prodfiles{'targetgcc32,xlC'}"     if (&isBG);
    $attr{'cppcomp'}               = "$opt{'vacpp'}/exe/$prodfiles{'cppcomp'}";
    $attr{'defaultmsg'}            = "$opt{'vacpp'}/msg/$prodfiles{'defaultmsg'}";
    $attr{'xlurt_cfg_path'}        = "$opt{'vacpp'}/urt";
    $attr{'vacpp_path'}            = "$opt{'vacpp'}";
    $attr{'xlc_cpp_stdinc'}        = "$include_cxx";
  } # END _if_vacpp_
  if (&isFortranProd) {
    $attr{'artool'}                = "$opt{'xlf'}/exe/$prodfiles{'artool'}"                if (&isLinux);
    $attr{'bolt'}                  = "$opt{'xlf'}/exe/$prodfiles{'bolt'}";
    $attr{'targetgcc32,bolt'}      = "$opt{'xlf'}/exe/$prodfiles{'targetgcc32,bolt'}"      if (&isBG);
    $attr{'code'}                  = "$opt{'xlf'}/exe/$prodfiles{'code'}";
    $attr{'cpp'}                   = "$opt{'xlf'}/exe/$prodfiles{'cpp'}";
    $attr{'defaultmsg'}            = "$opt{'xlf'}/msg/$prodfiles{'defaultmsg'}";
    $attr{'dis'}                   = "$opt{'xlf'}/exe/$prodfiles{'dis'}"                   if (&isLinux);
    $attr{'hot'}                   = "$opt{'xlf'}/exe/$prodfiles{'hot'}";
    $attr{'ipa'}                   = "$opt{'xlf'}/exe/$prodfiles{'ipa'}";
    $attr{'list'}                  = "$opt{'xlf'}/exe/$prodfiles{'list'}"                  if (&isLinux && !&isBG);
    $attr{'xslt'}                  = "$opt{'xlf'}/exe/$prodfiles{'xslt'}"                  if (&isLinux && !&isBG);
    $attr{'transforms'}            = "$opt{'xlf'}/listings"                                if (&isLinux && !&isBG);
    $attr{'listlibs'}              = "$opt{'xlf'}/lib"                                     if (&isLinux && !&isBG);
    $attr{'xlcmp_path'} = "$opt{'xlf'}"                                      if (&useLicPackage);
    $attr{'xlf'}                   = "$opt{'xlf'}/exe/$prodfiles{'xlf'}";
    $attr{'xlf_path'}              = "$opt{'xlf'}";
    $attr{'xlurt_cfg_path'}        = "$opt{'xlf'}/urt";
  } # END _if_xlf_

  foreach (@staticfiles) {
    $attr{$_}  = &read_templ_attr_value($opt{'source'}, $_);
  }

  if (&isOpenCL) {
    $attr{'spu-xlcl:gcc_c_stdinc'}  = "$opt{'vac'}/crt/include:/usr/spu/include";
    $attr{'spu-xlcl:libdirs'}       = "-L$opt{'vac'}/spu/lib";
  } # END _if_opencl_

  if (defined ($opt{'gcc32'})) {
    $attr{'libdirs'}                           = "$libdirs_32";
    $attr{'gcc_path'}                          = "$opt{'gcc32'}";
    $attr{'gcc_libdirs'}                       = "$libpath_c{'gcc32'}";
    # $attr{'gxx_libdirs'}                     = "$libpath_cxx{'gcc32'}";
    $attr{'dynlib'}                            = "$dynlib_path{'gcc32'}"; 
    foreach $crt (keys (%crtfiles))            { next if $crt =~ /,/; $attr{$crt} = "$$crt{'gcc32'}"; }
    foreach $exe (keys (%exefiles))            { next if $exe =~ /,/; $attr{$exe} = "$$exe{'gcc32'}"; }
    foreach $m (@gnu_macros)                   { $attr{$m} = "$gnu_macros{'gcc32'}->{$m}"; }
    if (&useOSMacro) {
      foreach $o (keys (%{$os_macros{'gcc32'}})) { $attr{$o} = "$os_macros{'gcc32'}->{$o}"; }
    }

    $excld_hdrs = &read_templ_attr($opt{'source'}, 'exclude_headers');
    if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
      $attr{'gcc_c_stdinc'}         = &replace_gcc_incdir($stdinc_c{'gcc32'},"$opt{'vac'}/crt/include", $excld_hdrs);
      $attr{'xlc_c_complexgccinc'}  = "$include_c:$attr{'gcc_c_stdinc'}";
      if (valueExist('-qtls','-qnotls',\@{$append_attr{'ALL:options'}}) == 0) {
        if ($isTLS{'gcc32'}) {
          push (@{ $append_attr{'ALL:options'} }, '-qtls');
        }
      } # END _if_valueExist_
    } # END _if_vac_vacpp_
    if (&isCxxProd) {
      $attr{'gcc_cpp_stdinc'}       = &replace_gcc_incdir($stdinc_cxx{'gcc32'},"$opt{'vac'}/crt/include", $excld_hdrs);
      $attr{'xlc_cpp_complexgccinc'}= "$include_cxx:$attr{'gcc_cpp_stdinc'}";
    } # END _if_vacpp_
    if (&isFortranProd) {
      $attr{'include_32'}              = "-I$opt{'xlf'}/include";
    } # END _if_xlf_
  } # END _gcc32_

  if (defined ($opt{'targetgcc32'})) {

    $attr{'targetgcc32,libdirs'}       = "$libdirs_32_alt";
    $attr{'targetgcc32,gcc_path'}      = "$opt{'targetgcc32'}";
    $attr{'targetgcc32,gcc_libdirs'}   = "$libpath_c{'targetgcc32'}";
    # $attr{'targetgcc32,gxx_libdirs'} = "$libpath_cxx{'targetgcc32'}";

    foreach $crt (grep($_ !~ /^targetgcc32,/, keys (%crtfiles))) {
      $attr{"targetgcc32,$crt"} = "$$crt{'targetgcc32'}";
    }
    foreach $crt (grep($_ =~ /^targetgcc32,/, keys (%crtfiles))) {
      $attr{$crt} = "$$crt{'targetgcc32'}";
    }

    foreach $exe (grep($_ !~ /^targetgcc32,/, keys (%exefiles))) {
      $attr{"targetgcc32,$exe"} = "$$exe{'targetgcc32'}";
    }
    foreach $exe (grep($_ =~ /^targetgcc32,/, keys (%exefiles))) {
      $attr{$exe} = "$$exe{'targetgcc32'}";
    }

    foreach $m (@gnu_macros)                         { $attr{"targetgcc32,$m"} = "$gnu_macros{'targetgcc32'}->{$m}"; }
    if (&useOSMacro) { 
      foreach $o (keys (%{$os_macros{'targetgcc32'}})) { $attr{"targetgcc32,$o"} = "$os_macros{'targetgcc32'}->{$o}"; }
     }

    $excld_hdrs = &read_templ_attr($opt{'source'}, 'targetgcc32,exclude_headers');
    if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
      $attr{'targetgcc32,gcc_c_stdinc'}         = &replace_gcc_incdir($stdinc_c{'targetgcc32'},"$opt{'vac'}/crt/include",$excld_hdrs);
      $attr{'targetgcc32,xlc_c_complexgccinc'}  = "$include_c:$attr{'targetgcc32,gcc_c_stdinc'}"     if &isBG;

      my ($prefixPattern) = &getStanzaPrefix('targetgcc32') . '.*';

      if (valueExist('-qtls','-qnotls',\@{$append_attr{"$prefixPattern:options"}}) == 0) {
        if ($isTLS{'targetgcc32'}) {
          push (@{ $append_attr{"$prefixPattern:options"} }, ',');
          push (@{ $append_attr{"$prefixPattern:options"} }, '-qtls');
        }
      } # END _if_valueExist_
    } # END _if_vac_vacpp_
    if (&isCxxProd) {
      $attr{'targetgcc32,gcc_cpp_stdinc'}        = &replace_gcc_incdir($stdinc_cxx{'targetgcc32'},"$opt{'vac'}/crt/include",$excld_hdrs);
      $attr{'targetgcc32,xlc_cpp_complexgccinc'} = "$include_cxx:$attr{'targetgcc32,gcc_cpp_stdinc'}" if &isBG;
    } # END _if_vacpp_

    my ($prefix) = &getStanzaPrefix('targetgcc32');
  } # END _targetgcc32_

  if (defined ($opt{'targetgcc64'}) && &isBGQ) {

    $attr{'targetgcc64,libdirs_64'}       = "$libdirs_64_alt";
    $attr{'targetgcc64,gcc_path_64'}      = "$opt{'targetgcc64'}";
    $attr{'targetgcc64,gcc_libdirs_64'}   = "$libpath_c{'targetgcc64'}";

    foreach $crt (grep($_ !~ /^targetgcc64,/, keys (%crtfiles))) {
      $attr{"targetgcc64,${crt}_64"} = "$$crt{'targetgcc64'}" if ($crt !~ /targetgcc[0-9]*/);
    }
    foreach $crt (grep($_ =~ /^targetgcc64,/, keys (%crtfiles))) {
      $attr{$crt} = "$$crt{'targetgcc64'}";
    }

    foreach $exe (grep($_ !~ /^targetgcc64,/, keys (%exefiles))) {
      $attr{"targetgcc64,${exe}_64"} = "$$exe{'targetgcc64'}" if ($crt !~ /targetgcc[0-9]*/);
    }
    foreach $exe (grep($_ =~ /^targetgcc64,/, keys (%exefiles))) {
      $attr{$exe} = "$$exe{'targetgcc32'}";
    }

    $excld_hdrs = &read_templ_attr($opt{'source'}, 'targetgcc64,exclude_headers');
    if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
      $attr{'targetgcc64,gcc_c_stdinc_64'}         = &replace_gcc_incdir($stdinc_c{'targetgcc64'},"$opt{'vac'}/crt/include",$excld_hdrs);
      $attr{'targetgcc64,xlc_c_complexgccinc_64'}  = "$include_c:$attr{'targetgcc64,gcc_c_stdinc_64'}"     if &isBG;

      my ($prefixPattern) = &getStanzaPrefix('targetgcc64') . '.*';

      if (valueExist('-qtls','-qnotls',\@{$append_attr{"$prefixPattern:options"}}) == 0) {
        if ($isTLS{'targetgcc64'}) {
          push (@{ $append_attr{"$prefixPattern:options"} }, ',');
          push (@{ $append_attr{"$prefixPattern:options"} }, '-qtls');
        }
      } # END _if_valueExist_
    } # END _if_vac_vacpp_
    if (&isCxxProd) {
      $attr{'targetgcc64,gcc_cpp_stdinc_64'}        = &replace_gcc_incdir($stdinc_cxx{'targetgcc64'},"$opt{'vac'}/crt/include",$excld_hdrs);
      $attr{'targetgcc64,xlc_cpp_complexgccinc_64'} = "$include_cxx:$attr{'targetgcc64,gcc_cpp_stdinc_64'}" if &isBG;
    } # END _if_vacpp_

  } # END _targetgcc64_

  if (defined ($opt{'gcc64'})) {
    $attr{'libdirs_64'}             = "$libdirs_64";
    $attr{'gcc_path_64'}            = "$opt{'gcc64'}";
    $attr{'gcc_libdirs_64'}         = "$libpath_c{'gcc64'}";
    $attr{'dynlib_64'}              = "$dynlib_path{'gcc64'}";
    # $attr{'gxx_libdirs_64'}       = "$libpath_cxx{'gcc64'}";
    foreach $crt (keys (%crtfiles)) { $attr{"${crt}_64"} = "$$crt{'gcc64'}"; }
    foreach $exe (keys (%exefiles)) { $attr{"${exe}_64"} = "$$exe{'gcc64'}"; }
    $excld_hdrs = &read_templ_attr($opt{'source'}, 'exclude_headers');
    if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
      $attr{'gcc_c_stdinc_64'}      = &replace_gcc_incdir($stdinc_c{'gcc64'},"$opt{'vac'}/crt/include",$excld_hdrs);
      $attr{'xlc_c_complexgccinc_64'} = "$include_c:$attr{'gcc_c_stdinc_64'}";
      if (valueExist('-qtls','-qnotls',\@{$append_attr{'ALL:options'}}) == 0) {
        if ($isTLS{'gcc64'}) {
          push (@{ $append_attr{'ALL:options'} }, '-qtls');
        }
      } # END _if_valueExist_
    } # END _if_vac_vacpp_
    if (&isCxxProd) {
      $attr{'gcc_cpp_stdinc_64'}     = &replace_gcc_incdir($stdinc_cxx{'gcc64'},"$opt{'vac'}/crt/include",$excld_hdrs);
      $attr{'xlc_cpp_complexgccinc_64'} = "$include_cxx:$attr{'gcc_cpp_stdinc_64'}";
    } # END _if_vacpp_
    if (&isFortranProd) {
      $attr{'include_64'}           = "-I$opt{'xlf'}/include";
    } # END _if_xlf_
  } # END _gcc64_

  $gccver = join('.',
    $attr{'__GNUC__'},
    $attr{'__GNUC_MINOR__'},
    $attr{'__GNUC_PATCHLEVEL__'},
  );

  $targetgccver = join('.',
    $attr{'targetgcc32,__GNUC__'},
    $attr{'targetgcc32,__GNUC_MINOR__'},
    $attr{'targetgcc32,__GNUC_PATCHLEVEL__'},
  );
  foreach ('','targetgcc32,') {
    delete $attr{$_.'crtsavres'} if &isCrtsavresRemove($attr{$_.'__GNUC__'},$attr{$_.'__GNUC_MINOR__'});
  }
  foreach ('','targetgcc64,') {
    delete $attr{$_.'crtsavres_64'} if &isCrtsavresRemove($attr{$_.'__GNUC__'},$attr{$_.'__GNUC_MINOR__'});
  }

  my ($template) = gen_template ($opt{'source'}, \%attr, \%append_attr, $gccver, $targetgccver);
  printAndDie ("Could not generate template from \"$opt{'source'}\"\n;")
    unless (defined ($template));

  handleOutput ($template)
    or printAndDie ("Unable to create \"$opt{'target'}\" -- $!.");

  printInfo ("GCC version used in \"$opt{'target'}\" -- \"$gccver\"");
  printInfo ("Blue Gene tool chain version used in \"$opt{'target'}\" -- \"$targetgccver\"") if &isBG;

  printDebug ("deleting temporary files");
  my $tempfiles = &gen_tempfile ("${prod}.*");
  opendir(DIR,dirname $tempfiles) || printErr("Cannot open temporary logs directory!\n");
  my @dirContents = readdir(DIR); closedir(DIR);
  foreach (@dirContents) {
    my $file = (dirname $tempfiles)."/$_";
    if ($file=~m/^$tempfiles$/) {
      printDebug ("deleting temporary file $file");
      unlink $file;
    }
  }

  printDebug ("###CONFIGURE### ($0) completed successfully");

  $ENV{LANG}="$old_locale";

  programExit (0);
} # _end_main_

sub setModesConfigure {
#*******************************************************************************
#* Sets the modes_configure attribute based on the value of the template +
#* the current configuration options.
#*******************************************************************************
  my ($previous_mode) = $_[0];
  my ($modes) = 0;
  printDebug ("Setting modes_configure + template value \"$previous_mode\"..");

  if ((defined ($opt{'gcc32'})) and (defined ($opt{'gcc64'}))) {
    $modes='32_64';
  } elsif (defined ($opt{'gcc32'})){
    if ($previous_mode =~ /64/) {
      printExtraDebug ("Template was previously configured in 64-bit");
      $modes='32_64';
    } else {
      $modes='32';
    } # END _if_prev_64_
  } elsif (defined ($opt{'gcc64'})){
    if ($previous_mode =~ /32/) {
      printExtraDebug ("Template was previously configured in 32-bit");
      $modes='32_64';
    } else {
      $modes='64';
    } # END _if_prev_32_
  } else {
    printErr ("Terribly confused over \"$previous_mode\"");
  } # END _if_gcc_or_gcc64_

  printDebug ("modes_configure set to == \"$modes\"");
  return $modes;
} # END setModesConfigure ()

sub readModesConfigure {
#*******************************************************************************
#* Searches the given configuration file for the 'modes_configure' attribute.
#*******************************************************************************
  my ($cfg)   = $_[0];
  my ($modes) = 0;
  printDebug ("Reading \"modes_configure\" in \"$cfg\"..");
  open (CFG, "$cfg") or return 0;

  my ($stanza);
  my ($prefix) = &getStanzaPrefix('targetgcc32');

  while (<CFG>) {
    if (($_ =~ /^(\S+):/)) { $stanza = $1; }
    if (/.*\s+modes_configure\s*:?=\s*(\S+)/ && $stanza !~ /^$prefix/) {
      printExtraDebug ("Found \"$1\"");
      $modes = $1;
      last;
    }
  } # END _while_cfg_
  close (CFG) or return 0;
  printDebug ("Yielded == \"$modes\"");
  return $modes;
} # END readModesConfigure ()

sub handleOutput {
#*******************************************************************************
#* Dump generated file to screen or output to target configuration file.
#*******************************************************************************
  my ($file)   = $_[0];
  if (defined ($opt{'target'})) {
    if (-e $opt{'target'}) {
      printErr ("\"$opt{'target'}\" still exists?!"); return 0;
    } else {
      printDebug ("Creating target configuration file \"$opt{'target'}\"..");
      open  (FILE,   "$file") or return 0;
      open  (TARGET, ">$opt{'target'}") or return 0;
      while (<FILE>) { print TARGET "$_"; }
      close (TARGET) or return 0;
      close (FILE)   or return 0;
    } # END _if_target_exists_
  } else {
    # No target.. dump to standard output
    open  (FILE, "$file") or return 0;
    while (<FILE>) { print STDOUT "$_"; }
    close (FILE) or return 0;
  }
  unlink ($file) or return 0;
  return 1;
} # END handleOutput ()

sub build_libdirs_list {
#*******************************************************************************
#* Builds the -L/-R library directory string based on the given lib dir lists.
#*******************************************************************************
  my ($mode)  = $_[0];
  my ($Llist) = $_[1];
  my ($Rlist) = $_[2];
  my (@libdirs);
  foreach $dir (@$Llist) {
    $dir .= '64' if ($mode eq '64');
    push (@libdirs, "-L$dir") unless (grep("-L$dir" eq $_, @libdirs));
  }

  my ($cv);

  foreach $dir (@$Rlist) {

    if ($mode eq '64') {
      if (&isBG) {
      	$cv  =  &getCompilerVariation();
        $dir =~ s/lib$cv/lib64$cv/g;
        $dir =~ s/${cv}lib/${cv}lib64/g;
      }
      else {
        $dir .= '64';
      }
    }

    push (@libdirs, "-R$dir") unless (grep("-R$dir" eq $_, @libdirs));
  }
  return join (',',@libdirs);
} # END build_libdirs_list ()

sub gen_template {
#*******************************************************************************
#* Setup target configuration file using given template. Returns the name of
#* the temporary configuration file if successful; undef otherwise.
#*******************************************************************************
  my ($source)       = $_[0];
  my ($attr)         = $_[1];
  my ($append_attr)  = $_[2];
  my ($gccver)       = $_[3];
  my ($targetgccver) = $_[4];
  my ($template)     = "$TEMP{'TEMPLATE'}.1";
  my ($targetf)      = "$TEMP{'TEMPLATE'}";
  my ($date)         = `date`; chomp ($date);
  my ($end_tag)      = '__END_OF_TEMPLATE__';
  my (@found);
  my (@attr_keys);
  my ($apply_to_stanza);
  my ($apply_to_attr);
  my ($attr_seperator);
  my ($stanza);
  my ($stanza_end);
  my ($skip_attr);

  printDebug ("Generating template configuration file from \"$source\"");
  # Make a list of all attributes we want to update..
  foreach (sort (keys (%$attr))) { push (@attr_keys,$_); }

  # Update the existing template values..
  $stanza = undef; $stanza_end = 0;
  open  (SOURCE,   "$source")    or return undef;
  open  (TEMPLATE, ">$template") or return undef;
  print  TEMPLATE  "* Configuration file generated on \"$date\"\n";
  print  TEMPLATE  "* with \"$0 @ARGV\"\n";
  print  TEMPLATE  "* GCC version used: \"$gccver\"\n";

  print  TEMPLATE  "* Blue Gene tool chain version: \"$targetgccver\"\n" if &isBG;

  my ($preAttrName, $realAttrName, $postAttrName, $attrName, $attrValue, $foundName);
  my ($prefix) = &getStanzaPrefix('targetgcc32');
  my (@altStanzas) = ();

  while ($line=<SOURCE>) {
    if (($line =~ /^(\S+):/))                          { $stanza     = $1; }
    if (($line =~ /^(\s+)$/) or ($line =~ /$end_tag/)) { $stanza_end = 1;  }

    # Find attributes lines..
    if ($line =~ /(.*?\s+)(\S+)(\s*[:\+-]?=\s*)(.*)/) {
      unless ($line =~ /^\s*\*/) { # skip over comments..

        $preAttrName  = $1;
        $realAttrName = $2;
        $postAttrName = $3;
        $attrValue    = $4;

        $skip_attr = 0;
        $attrName  = $realAttrName;
        $foundName = $realAttrName;
        $stattrName = $stanza.':'.$attrName;

        push (@altStanzas,$preAttrName) if ($preAttrName !~ m/^\s*$/
             && $realAttrName eq 'use'
             && &isAltDEFLTStanza($prefix, $attrValue));

        if (&isAltDEFLTStanza($prefix, $stanza) || grep(/\Q$stanza\E:\s*/, @altStanzas)) {
          foreach my $mode ('32', '64') {
            # if attribute has mode suffix, use that mode's attributes
            if($realAttrName =~ /^\S*_$mode$/ &&
                grep("targetgcc$mode,$realAttrName" eq $_, @attr_keys)){
              $foundName = "targetgcc$mode,$realAttrName";
              $attrName = $foundName;
            } else {
              $foundName = "targetgcc32,$realAttrName";
              $attrName = $foundName if (grep($foundName eq $_, @attr_keys));
            }
          }
        }

	foreach ('','targetgcc32,') {
	  $skip_attr = 1 if (($attrName eq "${_}crtsavres") &&
	    &isCrtsavresRemove($attr->{$_.'__GNUC__'},$attr->{$_.'__GNUC_MINOR__'}));
	}
	foreach ('','targetgcc64,') {
	  $skip_attr = 1 if (($attrName eq "${_}crtsavres_64") &&
	    &isCrtsavresRemove($attr->{$_.'__GNUC__'},$attr->{$_.'__GNUC_MINOR__'}));
	}
        next if $skip_attr;
        if (grep($stattrName eq $_, @attr_keys)) {
          printExtraDebug ("Updating ATTRIBUTE \"$realAttrName\" = \"$attr->{$stattrName}\"");
          $line = "$preAttrName$realAttrName$postAttrName$attr->{$stattrName}\n";
          push (@found, $foundName);
        } elsif (grep($attrName eq $_, @attr_keys)) {
          printExtraDebug ("Updating ATTRIBUTE \"$realAttrName\" = \"$attr->{$attrName}\"");
          $line = "$preAttrName$realAttrName$postAttrName$attr->{$attrName}\n";
          push (@found, $foundName);
        } # END _if_update_attribute_

        foreach (keys(%$append_attr)) {
          ($apply_to_stanza, $apply_to_attr) = split(/:/, $_);
          $apply_to_stanza=~s/\+/\\\+/g;
          if ($attrName eq $apply_to_attr) {
            if ((($apply_to_stanza eq 'ALL') && $stanza !~ /^$prefix/) || ($stanza =~ /^$apply_to_stanza$/)) {
              $attr_seperator = @{ $append_attr{$_} }[0];
              foreach $i (1 .. $#{ $append_attr{$_} }) {
                chomp($line);
                printExtraDebug ("Appending \"$append_attr{$_}[$i]\" to ATTRIBUTE \"$realAttrName\" in STANZA \"$stanza\"");
                if (($attrValue =~ /^\s*$/s) && ($i eq '1')) {
                  $line = "$line$append_attr{$_}[$i]\n";
                } else {
                  $line = "$line${attr_seperator}$append_attr{$_}[$i]\n";
                }
              } # END _foreach_i_
            }
          }
        } # END _foreach_append_attr__

      }   # END _unless_comment_line_
    }     # END _if_attribute_line_

    print TEMPLATE "$line";
    if ($stanza_end) { $stanza = undef; $stanza_end = 0; }
  } # END _while_source_file_
  print  TEMPLATE  "$end_tag\n";
  close (TEMPLATE) or return undef;
  close (SOURCE)   or return undef;

  # Fill in any missing attributes to generate target cfg file..
  $stanza = undef; $stanza_end = 0;
  open  (TEMPLATE, "$template") or return undef;
  open  (TARGETF,  ">$targetf")  or return undef;
  while ($line=<TEMPLATE>) {
    if (($line =~ /^(\S+):/))                          { $stanza     = $1; }
    if (($line =~ /^(\s+)$/) or ($line =~ /$end_tag/)) { $stanza_end = 1;  }

    if (defined ($opt{'dfp'})) {
      $line =~ s/lgcc_s_64/lgcc_s/g;
    }

    # Add new attributes to DEFLT stanza..
    if (($stanza eq 'DEFLT') and ($stanza_end)) {
      foreach $k (@attr_keys) {
        unless (grep($k eq $_, @found)) {

          next if $k =~ /:/;
          next if $k =~ /^targetgcc[0-9]*,/;

          if ($attr->{$k} eq 'NULL' && !&allowNullAttr) {
            printExtraDebug ("Ignoring ATTRIBUTE \"$k\" because its value is \"NULL\"");
            next;
          }

          printExtraDebug ("Adding ATTRIBUTE \"$k\" = \"$attr->{$k}\"");
          print TARGETF "        $k = $attr->{$k}\n";
        } # END _if_attr_not_found_
      } # END _foreach_attr_
    }   # END _if_end_of_deflt_stanza_

    # Add new attributes to alternate DEFLT stanza..
    if ((&isAltDEFLTStanza($prefix, $stanza)) and ($stanza_end)) {
      foreach $k (@attr_keys) {
        unless (grep($k eq $_, @found)) {
          next if $k =~ /:/;
          $realAttrName = $k;
          if ($k !~ /^targetgcc32,/ && $k !~ /^targetgcc64,/) {
            next if grep("targetgcc32,$k" eq $_, @attr_keys) || grep("targetgcc32,$k" eq $_, @found) ||
                    grep("targetgcc64,$k" eq $_, @attr_keys) || grep("targetgcc64,$k" eq $_, @found);
          }
          elsif ($k =~ m/^targetgcc32,/) {
            # skip if it's already been added by targetgcc64
            $realAttrName =~ s/^targetgcc32/targetgcc64/;
            next if grep($realAttrName eq $_, @attr_keys) || grep($realAttrName eq $_, @found);
            $realAttrName =~ s/^targetgcc64,//;
          }
          elsif ($k =~ m/^targetgcc64,/) {
            # skip if it's already been added by targetgcc32
            $realAttrName =~ s/^targetgcc64/targetgcc32/;
            next if grep($realAttrName eq $_, @attr_keys) || grep($realAttrName eq $_, @found);
            $realAttrName =~ s/^targetgcc32,//;
          }

          if ($attr->{$k} eq 'NULL' && !&allowNullAttr) {
            printExtraDebug ("Ignoring ATTRIBUTE \"$k\" because its value is \"NULL\"");
            next;
          }

          printExtraDebug ("Adding ATTRIBUTE \"$realAttrName\" = \"$attr->{$k}\"");
          print TARGETF "        $realAttrName = $attr->{$k}\n";
        } # END _if_attr_not_found_
      } # END _foreach_attr_
    }   # END _if_end_of_deflt_stanza_

    print TARGETF "$line" unless ($line =~ /$end_tag/);
    if ($stanza_end) { $stanza = undef; $stanza_end = 0; }
  } # END _while_template_file_
  close (TARGETF)  or return undef;
  close (TEMPLATE) or return undef;

  unlink ("$template");
  printDebug ("Template \"$targetf\" generated.");
  return $targetf;
} # END gen_template ()

sub validate_args {
#*******************************************************************************
#* Check arguments for correctness and set default values if none are provided.
#*******************************************************************************
  my (%opts) = @_;
  my ($err)  = 0;
  my ($inv);
  printDebug ("Validating arguments..");

  my (@validTargets);
  my $args_files=$TEMP{'TEMPOUT'}.'-args';
  push(@validTargets, ('sles', 'rhel', 'yhpc', 'bluegene', 'cell', 'fedora')) if &isLinux;

  # Ensure -target is valid
  if (&isLinux && !grep($opts{'targetPlatform'} eq $_, @validTargets)) {
    printErr ("\"-target\" can only be one of: " . join(', ', @validTargets));
    $err++;
  }

  # Ensure only one of -useInfo and -saveInfo options is used
  if (defined ($opts{'useInfo'}) and defined ($opts{'saveInfo'})) {
    printErr ("\"-useInfo\" and \"-saveInfo\" cannot be used at the same time");
    $err++;
  }

  # Ensure directory specified for -saveInfo does not exist and can be created
  if (defined ($opts{'saveInfo'})) {
    if (-d $opts{'saveInfo'}) {
      printErr ("directory \"$opts{'saveInfo'}\" specified by \"-saveInfo\" already existed");
      $err++;
    }
    unless (mkdir ($opts{'saveInfo'}, 0755)) {
      printErr ("directory \"$opts{'saveInfo'}\" specified by \"-saveInfo\" cannot be created");
      $err++;
    }
  }

  # Ensure we have a compiler to configure to..
  if (defined ($opts{'useInfo'})){

    # Ensure Info file directory exists
    unless (-d $opts{'useInfo'}) {
      printErr ("directory \"$opts{'useInfo'}\" specified by \"-useInfo\" does not exist");
      $err++;
    }

    if (defined ($opts{'gcc32'}) or defined ($opts{'gcc64'}) or 
        defined ($opts{'targetgcc32'}) or defined ($opts{'targetgcc64'})) {
      printErr ("\"-useInfo\" cannot be used together with any of \"-gcc\", \"-gcc64\",".
                " \"-targetgcc32\" or \"-targetgcc64\"");
      $err++;
    } 
    $opt{'useInfo'}=$opts{'useInfo'};
    foreach $inv ('gcc32', 'gcc64', 'targetgcc32', 'targetgcc64') {
      next unless (openInfoFile (INFO, "<$args_files-$inv"));
      while(<INFO>){
        if ($_ =~ m/^$inv\s*=\s*\"(\S+)\"/) { $opts{"$inv"} = $1; last; }
        else                                { $opts{"$inv"} = undef; }
      }
      close (INFO);
    }
  } else {
    if (&is64bitEnabled) {
      unless (defined ($opts{'gcc32'}) and defined ($opts{'gcc64'})) {
        printErr ("Both \"-gcc\" and \"-gcc64\" must be specified");
	$err++;
      }
    } else {
      unless (defined ($opts{'gcc32'})) {
        printErr ("\"-gcc\" must be specified");
	$err++;
      }
    } # END _if_is64bitEnabled_

    if (&isBG) {
      if (!defined ($opts{'targetgcc32'})) {
	printErr ("\"-targetgcc\" must be specified");
	$err++;
      }

    }
    elsif (defined ($opts{'targetgcc32'})) {
      printWarn ("\"-targetgcc\" is ignored for the compiler you are trying to configure");
      delete $opts{'targetgcc32'};
    }
    if ($err == 0) {
      $opt{'saveInfo'}=$opts{'saveInfo'};
      foreach ('gcc32', 'gcc64', 'targetgcc32', 'targetgcc64') {
        my $inv=$_;
        next unless (defined ($opts{$inv}));
        open INFO, ">$args_files-$inv";
        printInfoFile (\*INFO, "$args_files-$inv", "$inv = \"$opts{$inv}\"\n");
        close (INFO);
        unlink "$args_files-$inv";
      }
    }
  }

  if (-e $opts{'target'}) {
    if (defined ($opts{'force'})) {
      unless (unlink ($opts{'target'})) {
        printErr ("Unabled to delete \"$opts{'target'}\" -- $!");
        $err++;
      } # _unless_unlink_
    } else {
      printErr ("Output target file \"$opts{'target'}\" already exists.");
      $err++;
    } # END _if_force_
  }   # END _if_target_

  # Ensure we have a tempate file..
  if (!defined ($opts{'source'})) {
    printErr ("Template configuration file not specified.");
    $err++;
  } elsif (!(-e $opts{'source'})) {
    printErr ("Template file \"$opts{'source'}\" does not exist.");
    $err++;
  } # END _if_exists_source_

  # Ensure -ibmcmp and individual -component type flags are exclusive..
  if (defined ($opts{'ibmcmp'})) {
    if (defined($opts{'vac'})     or
        defined($opts{'vaclic'})  or
        defined($opts{'vacpp'})   or
        defined($opts{'vacpprt'}) or
        defined($opts{'xlf'})     or
        defined($opts{'xlfrt'})   or
        defined($opts{'xlflic'})  or
        defined($opts{'smprt'})   or
        defined($opts{'mass'}))
    {
      printErr ("Incorrect usage of \"-ibmcmp\""); $err++;
      # Exit immediately to avoid meaningless reporting of missing file..
      printAndDie ("Try \"$0 -h\" for more information.");
    } else {
      if (&isUpcProd){
        $opts{'vac'}     = "$opts{'ibmcmp'}/$upcProdname"     . &getCompilerVariation() . "/$ver";
        $opts{'vaclic'}  = "$opts{'ibmcmp'}/$upcProdname"     . &getCompilerVariation() . "/$ver";
      } else {
        $opts{'vac'}     = "$opts{'ibmcmp'}/$cProdname"       . &getCompilerVariation() . "/$ver";
        $opts{'vaclic'}  = "$opts{'ibmcmp'}/$cProdname"       . &getCompilerVariation() . "/$ver";
      }
      $opts{'xlf'}     = "$opts{'ibmcmp'}/$fortranProdname" . &getCompilerVariation() . "/$ver";
      $opts{'xlfrt'}   = "$opts{'ibmcmp'}/$fortranProdname" . &getCompilerVariation() . "/$ver";
      $opts{'xlflic'}  = "$opts{'ibmcmp'}/$fortranProdname" . &getCompilerVariation() . "/$ver";
      $opts{'vacpp'}   = "$opts{'ibmcmp'}/$cxxProdname"     . &getCompilerVariation() . "/$ver";
      $opts{'vacpprt'} = "$opts{'ibmcmp'}/$cxxProdname"     . &getCompilerVariation() . "/$ver";
      $opts{'smprt'}   = "$opts{'ibmcmp'}/xlsmp"  . &getCompilerVariation() . "/$smpver";
      $opts{'mass'}    = "$opts{'ibmcmp'}/xlmass" . &getCompilerVariation() . "/$massver";
    } # END _if_defined_vac_args_
  } else {
    $opts{'ibmcmp'} = '/opt/ibmcmp';
  } # END _if_defined_ibmcmp_
  unless (defined ($opts{'vac'})     and
          defined ($opts{'vaclic'})  and
          defined ($opts{'xlf'})     and
          defined ($opts{'xlfrt'})   and
          defined ($opts{'xlflic'})  and
          defined ($opts{'vacpp'})   and
          defined ($opts{'vacpprt'}) and
          defined ($opts{'smprt'})   and
          defined ($opts{'mass'}))
  {
    if (&isCProd) {
      printErr ("No values for \"-vac\",\"-smprt\",\"-mass\"")
        unless ($err > 0);
    } elsif (&isCxxProd) {
      if (&useLicPackage) {
        printErr ("No values for \"-vac\",\"-vaclic\",\"-vacpp\",\"-smprt\",\"-mass\",\"-vacpprt\"") unless ($err > 0);
      } else {
        printErr ("No values for \"-vac\",\"-vacpp\",\"-smprt\",\"-mass\",\"-vacpprt\"") unless ($err > 0);
      }
    } elsif (&isFortranProd) {
      if (&useLicPackage) {
        printErr ("No values for \"-xlf\",\"-xlfrt\",\"-xlflic\",\"-smprt\",\"-mass\"") unless ($err > 0);
      } else {
        printErr ("No values for \"-xlf\",\"-xlfrt\",\"-smprt\",\"-mass\"") unless ($err > 0);
      }
    } # END _case_prod_
    $err++;
  } # END _if_defined_vac_vacpp_smprt_mass_etc.._

  my ($validProductPaths) = 1;

  if (&isCProd || &isCxxProd) {
    $validProductPaths &= &isValidProductPath($opts{'vac'});
    $validProductPaths &= &isValidProductPath($opts{'vaclic'}) if &useLicPackage;
  }
  if (&isCxxProd) {
    $validProductPaths &= &isValidProductPath($opts{'vacpp'});
    $validProductPaths &= &isValidProductPath($opts{'vacpprt'});
  }
  elsif (&isFortranProd) {
    $validProductPaths &= &isValidProductPath($opts{'xlf'});
    $validProductPaths &= &isValidProductPath($opts{'xlflic'});
    $validProductPaths &= &isValidProductPath($opts{'xlfrt'});
  }

  unless (&isOpenCL) {
    $validProductPaths &= &isValidProductPath($opts{'mass'});
    $validProductPaths &= &isValidProductPath($opts{'smprt'});
  }

  $err++ unless $validProductPaths;


  # Argument validation.. check for crucial files
  my   (@files);
  my   (@gccfiles);

  unless (&isUpcProd or &isOpenCL) {
    push (@files, "$opts{'smprt'}/lib/libxlsmp.a");
  };
  unless (&isUpcProd or &isOpenCL) {
    push (@files, "$opts{'mass'}/lib/libmass.a");
  };

  if (defined ($opts{'gcc32'})) {
    push (@gccfiles,
      "$opts{'gcc32'}/$exec_c{'gcc32'}",
      (&isOpenCL?():"$opts{'gcc32'}/$exec_cxx{'gcc32'}"),
    );
  } # END _if_gcc32_
  if (defined ($opts{'gcc64'})) {
    push (@gccfiles,
      "$opts{'gcc64'}/$exec_c{'gcc64'}",
      (&isOpenCL?():"$opts{'gcc64'}/$exec_cxx{'gcc64'}"),
    );
  } # END _if_gcc64_

  if (defined ($opts{'targetgcc32'})) {
    push (@gccfiles,
      "$opts{'targetgcc32'}/$exec_c{'targetgcc32'}",
      "$opts{'targetgcc32'}/$exec_cxx{'targetgcc32'}",
    );
  }

  if (defined ($opts{'targetgcc64'})) {
    push (@gccfiles,
      "$opts{'targetgcc64'}/$exec_c{'targetgcc64'}",
      "$opts{'targetgcc64'}/$exec_cxx{'targetgcc64'}",
    );
  }

  if ((&isCProd) or (&isCxxProd) or (&isUpcProd)) {
    push (@files, "$opts{'vac'}/exe/xlcentry");
    if (&useLicPackage) {
      my ($ext) = &get_shr_lib_ext(); $ext .= '.1' if (&isLinux);
      push (@files, "$opts{'vac'}/lib/libxlcmptp".$ext);
    } # END _if_useLic_
  }   # END _if_vac_vacpp_
  if (&isCxxProd) {
    push (@files, "$opts{'vacpp'}/exe/xlCentry");
    push (@files, "$opts{'vacpprt'}/lib/libibmc++".&get_shr_lib_ext());
  } # END _if_vacpp_
  if (&isFortranProd) {
    push (@files, "$opts{'xlf'}/exe/xlfentry");
    push (@files, "$opts{'xlfrt'}/lib/libxlf90".&get_shr_lib_ext());
    if (&useLicPackage) {
      my ($ext) = &get_shr_lib_ext(); $ext .= '.1' if (&isLinux);
      push (@files, "$opts{'xlf'}/lib/libxlcmptp".$ext);
    } # END _if_useLic_
  }   # END _if_xlf_

  foreach (@files) { ;
    unless (-e $_) { printErr ("File \"$_\" not found"); $err++; }
  } # END _foreach_file_

  foreach (@gccfiles) { ;
    $_ =~ s/ -m32//g;
    unless (defined ($opts{'useInfo'}) or -e $_) {
      printErr ("File \"$_\" not found");
      $err++;
    }
  } # END _foreach_file_

  # END _argument_validation_

  printAndDie ("Try \"$0 -h\" for more information.") if ($err > 0);
  printDebug ("Arguments validated.");
  return (%opts);
} # END validate_args ()

sub set_defaults {
#*******************************************************************************
#* Check arguments for correctness and set default values if none are provided.
#*******************************************************************************
  my (%opts) = @_;
  my ($prod, $ver) = &guess_prod_name ();
  my ($smpver)     = &get_smp_ver ();
  my ($massver)    = &get_mass_ver ();
  printDebug ("Setting defaults..");

  unless (defined($opts{'targetPlatform'})) {
    $opts{'targetPlatform'} = &getDefaultTarget() if &isLinux;
  }

  unless (defined ($opts{'source'})) {
    if (defined ($opts{'default_base_cfg'})) {
      $opts{'source'} = $opts{'default_base_cfg'};
    } else {
      if ((&isCProd) or (&isCxxProd)) {
        $opts{'source'} = "/opt/ibmcmp/$cProdname" .
          &getCompilerVariation() . "/$ver/etc/$cProdname.base.cfg";
      } elsif (&isFortranProd) {
        $opts{'source'} = "/opt/ibmcmp/$fortranProdname" .
          &getCompilerVariation() . "/$ver/etc/$fortranProdname.base.cfg";
      } # END _case_prod_
    }
  } # END _unless_defined_source_
  if (!defined($opts{'xlf'}) and !defined($opts{'ibmcmp'})) {
    $opts{'xlf'} = "/opt/ibmcmp/$fortranProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'xlfrt'}) and !defined($opts{'ibmcmp'})) {
    $opts{'xlfrt'} = "/opt/ibmcmp/$fortranProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'xlflic'}) and !defined($opts{'ibmcmp'})) {
    $opts{'xlflic'} = "/opt/ibmcmp/$fortranProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'vac'}) and !defined($opts{'ibmcmp'})) {
    $opts{'vac'} = "/opt/ibmcmp/$cProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'vaclic'}) and !defined($opts{'ibmcmp'})) {
    $opts{'vaclic'} = "/opt/ibmcmp/$cProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'vacpp'}) and !defined($opts{'ibmcmp'})) {
    $opts{'vacpp'} = "/opt/ibmcmp/$cxxProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'vacpprt'}) and !defined($opts{'ibmcmp'})) {
    $opts{'vacpprt'} = "/opt/ibmcmp/$cxxProdname" . &getCompilerVariation() . "/$ver";
  }
  if (!defined($opts{'smprt'}) and !defined($opts{'ibmcmp'})) {
    $opts{'smprt'} = "/opt/ibmcmp/xlsmp" . &getCompilerVariation() . "/$smpver";
  }
  if (!defined($opts{'mass'}) and !defined($opts{'ibmcmp'})) {
    $opts{'mass'} = "/opt/ibmcmp/xlmass" . &getCompilerVariation() . "/$massver";
  }

  printDebug ("Defaults set.");
  return (%opts);
} # END set_defaults ()

sub optParse {
#*******************************************************************************
#* Parse arguments..
#*******************************************************************************
  my (%opts, %optval);
  my ($err) = 0;

  my ($prod, $ver) = guess_prod_name ();
  unless ( (defined ($prod)) and (defined ($ver)) ) {
    printAndDie ("Identity crisis.. behaviour is undefined for \"$0\"");
  }

  my (@args_no_val)   = ('-install','-force','-v','-vv','-quiet','-dfp');
  my (@args_with_val) = (
    '-o',
    '-default_base_cfg',
    '-gcc',
    '-targetgcc',
    '-targetgcc64',
    '-ppugcc32',
    '-spugcc32',
    '-ibmcmp',
    '-smprt',
    '-mass',
    '-useInfo',
    '-saveInfo',
  );

  push (@args_with_val, '-osrelease')   if (&isLinux);
  push (@args_with_val, '-target')      if (&isLinux);
  push (@args_with_val, '-gcc64', '-ppugcc64') if (&is64bitEnabled);

  if ((&isCProd) or (&isCxxProd)) {
    push (@args_with_val, "-${cProdname}");
    push (@args_with_val, "-${cProdname}lic") if (&useLicPackage);
  } # END _if_vac_vacpp_
  if (&isCxxProd) {
    push (@args_with_val, "-${cxxProdname}");
    push (@args_with_val, "-${cxxProdname}rt");
  } # END _if_vacpp_
  if (&isFortranProd) {
    push (@args_with_val, "-${fortranProdname}");
    push (@args_with_val, "-${fortranProdname}rt");
    push (@args_with_val, "-${fortranProdname}lic") if (&useLicPackage);
  } # END _if_xlf_

  for ($i=0; $i<@ARGV; $i++) {
    my ($key) = $ARGV[$i];
    if ($key eq '-h') {
      &usage ();
    } elsif (grep($key eq $_, @args_with_val)) {
      my ($val) = $ARGV[++$i];
      if ((!defined ($val)) or ($val =~ /^-/)) {
        printErr ("Invalid argument given for option \"$key\""); $err++; last;
      } elsif (defined ($opts{$key})) {
        printErr ("Duplicate values given for option \"$key\""); $err++; last;
      } else {
        $opts{$key} = $val;
      } # END _if_val_check_
    } elsif (grep($key eq $_, @args_no_val)) {
      if (defined ($opts{$key})) {
        printErr ("Duplicate usage of option \"$key\""); $err++; last;
      } else {
        $opts{$key} = 'true';
      } # END _if_dup_usage_check__
    } elsif ($key =~ /^-/) {
      printErr ("Option \"$key\" is not known"); $err++; last;
    } else {
      if (defined ($optval{'source'})) {
        printErr ("Only one template file can be specified."); $err++; last;
      } else {
        $optval{'source'} = $key;
      } # END _val_check_
    } # END _key_check_
  } # END _foreach_key_

  $optval{'force'}       = 1 if (defined ($opts{'-force'}));
  if (((defined ($opts{'-v'})) or (defined ($opts{'-vv'}))) and (defined ($opts{'-quiet'}))) {
    printErr ("Cannot specify \"-v\" and/or \"-vv\" when \"-quiet\" is used"); $err++;
  } else {
    $optval{'quiet'}       = 1 if (defined ($opts{'-quiet'}));
    $optval{'verbose'}     = 1 if (defined ($opts{'-v'}));
    $optval{'verbose'}     = 1 if (defined ($opts{'-vv'}));
    $optval{'veryverbose'} = 1 if (defined ($opts{'-vv'}));
    $optval{'dfp'}         = 1 if (defined ($opts{'-dfp'}));
  }
  if ((defined ($opts{'-o'})) and (defined ($opts{'-install'}))) {
    printErr ("Only one target file can be specified."); $err++;
  } elsif (defined ($opts{'-o'})) {
    $optval{'target'} = $opts{'-o'};
  } elsif (defined ($opts{'-install'})) {

    # must be set before call to getCompilerVariation()
    $opt{'targetPlatform'} = $opts{'-target'} if (defined($opts{'-target'}));

    if ((&isCProd) or (&isCxxProd)) {
      $optval{'target'} = "/opt/ibmcmp/$cProdname" . &getCompilerVariation() . "/$ver/etc/vac.cfg";
    } elsif (&isFortranProd) {
      $optval{'target'} = "/opt/ibmcmp/$fortranProdname" . &getCompilerVariation() . "/$ver/etc/xlf.cfg";
    }
  }
  $optval{'default_base_cfg'} = $opts{'-default_base_cfg'}      if (defined ($opts{'-default_base_cfg'}));
  $optval{'osrelease'}        = $opts{'-osrelease'}             if (defined ($opts{'-osrelease'}));
  $optval{'targetPlatform'}   = $opts{'-target'}                if (defined ($opts{'-target'}));
  $optval{'gcc32'}            = $opts{'-gcc'}                   if (defined ($opts{'-gcc'}));
  $optval{'gcc64'}            = $opts{'-gcc64'}                 if (defined ($opts{'-gcc64'}));
  $optval{'gcc32'}            = $opts{'-ppugcc32'}              if (defined ($opts{'-ppugcc32'}));
  $optval{'gcc64'}            = $opts{'-ppugcc64'}              if (defined ($opts{'-ppugcc64'}));
  $optval{'targetgcc32'}      = $opts{'-targetgcc'}             if (defined ($opts{'-targetgcc'}));
  $optval{'targetgcc64'}      = $opts{'-targetgcc64'}           if (defined ($opts{'-targetgcc64'}));
  $optval{'targetgcc64'}      = $opts{'-targetgcc'}             unless (defined ($optval{'targetgcc64'}));
  $optval{'targetgcc32'}      = $opts{'-spugcc32'}              if (defined ($opts{'-spugcc32'}));
  $optval{'ibmcmp'}           = $opts{'-ibmcmp'}                if (defined ($opts{'-ibmcmp'}));
  $optval{'xlf'}              = $opts{"-$fortranProdname"}      if (defined ($opts{"-$fortranProdname"}));
  $optval{'xlfrt'}            = $opts{"-${fortranProdname}rt"}  if (defined ($opts{"-${fortranProdname}rt"}));
  $optval{'xlflic'}           = $opts{"-${fortranProdname}lic"} if (defined ($opts{"-${fortranProdname}lic"}));
  $optval{'vac'}              = $opts{"-$cProdname"}            if (defined ($opts{"-$cProdname"}));
  $optval{'vaclic'}           = $opts{"-${cProdname}lic"}       if (defined ($opts{"-${cProdname}lic"}));
  $optval{'vacpp'}            = $opts{"-$cxxProdname"}          if (defined ($opts{"-$cxxProdname"}));
  $optval{'vacpprt'}          = $opts{"-${cxxProdname}rt"}      if (defined ($opts{"-${cxxProdname}rt"}));
  $optval{'smprt'}            = $opts{'-smprt'}                 if (defined ($opts{'-smprt'}));
  $optval{'mass'}             = $opts{'-mass'}                  if (defined ($opts{'-mass'}));
  $optval{'saveInfo'}         = $opts{'-saveInfo'}              if (defined ($opts{'-saveInfo'}));
  $optval{'useInfo'}          = $opts{'-useInfo'}               if (defined ($opts{'-useInfo'}));

  printAndDie ("Try \"$0 -h\" for more information.") if ($err > 0);

  return %optval;
} # END optParse ()

sub usage {
#*******************************************************************************
#* Display usage text.
#*******************************************************************************
  my ($prod, $ver) = &guess_prod_name ();
  my ($smpver)     = &get_smp_ver ();
  my ($massver)    = &get_mass_ver ();

  print "USAGE: $0";
  print " -gcc <path>";
  print " -gcc64 <path>"       if (&is64bitEnabled);
  print " -targetgcc <path>"   if (&isBG);
  print " [-o <name> | -install] [-force]";
  print " {[-ibmcmp <path>] | [-smprt <path>] | [-mass <path>]";
  if (&isCProd) {
    print " [-${cProdname}lic <path>]" if &useLicPackage;
    print " [-${cProdname} <path>]}";
  } elsif (&isCxxProd) {
    print " [-${cProdname}lic <path>]" if &useLicPackage;
    print " [-${cProdname} <path>] [-${cxxProdname}rt <path>] [-${cxxProdname} <path>]}";
  } elsif (&isFortranProd) {
    print " [-${fortranProdname}lic <path>]" if (&useLicPackage);
    print " [-${fortranProdname}rt <path>] [-${fortranProdname} <path>]}";
  } # END _case_prod_
  print " [<template_config_file>]\n";
  print "\n";
  print "-o         <name>      : name of the configuration file to generate\n";
  print "                         (eg. my.cfg)\n";
  print "-install               : generate default compiler configuration file\n";
  if (&isCProd || &isCxxProd) {
    print "                         (i.e. /opt/ibmcmp/${cProdname}" . &getCompilerVariation() . "/$ver/etc/vac.cfg)\n";
  } elsif ($isFortranProd) {
    print "                         (i.e. /opt/ibmcmp/${fortranProdname}" . &getCompilerVariation() . "/$ver/etc/xlf.cfg)\n";
  } # END _case_prod)

  print "-force                 : force overwrite of configuration file if it exists\n";

  print "-gcc       <path>      : path where gcc is installed\n";
  print "                         (eg. /usr if /usr/bin/gcc)\n";

  if (&is64bitEnabled) {
    print "-gcc64     <path>      : path where 64-bit gcc is installed\n";
    print "                         (eg. /usr if /usr/bin/gcc supports -m64 option)\n";
  } # END _if_is64bitEnable

  if (&isBG) {
    print "-targetgcc <path>      : path where Blue Gene tool chain is installed\n";
    if (&isBGP) {
      print "                         (eg. /bgsys/drivers/ppcfloor/gnu-linux/powerpc-bgp-linux)\n";
    } elsif (&isBGQ) {
      print "                         (eg. /bgsys/bgq/drivers/ppcfloor/gnu-linux/powerpc-bgq-linux)\n";
    }
  }

  if (&isLinux) {
    print "-osrelease <path>      : path where the linux release file is located \n";
    print "                         (default /etc)\n";
  }

  print "-ibmcmp    <path>      : common compiler path\n";
  print "                         (default: /opt/ibmcmp)\n";
  print "-smprt     <path>      : path where the SMP runtime is installed\n";
  print "                         (default: /opt/ibmcmp/xlsmp" . &getCompilerVariation() . "/$smpver)\n";
  print "-mass      <path>      : path where the MASS package is installed\n";
  print "                         (default: /opt/ibmcmp/xlmass" . &getCompilerVariation() . "/$massver)\n";

  if (&isCProd || &isCxxProd) {
    if (&useLicPackage) {
      print "-${cProdname}lic    <path>      : path where the C compiler license package is installed\n";
      print "                         (default: /opt/ibmcmp/${cProdname}" . &getCompilerVariation() . "/$ver)\n";
    } # END _if_useLicPackage_
    print "-${cProdname}       <path>      : path where the C compiler is installed\n";
    print "                         (default: /opt/ibmcmp/${cProdname}" . &getCompilerVariation() . "/$ver)\n";
  } # END _if_vac_

  if (&isCxxProd) {
    print "-${cxxProdname}rt     <path>      : path where the C++ runtime is installed\n";
    print "                           (default: /opt/ibmcmp/${cxxProdname}" . &getCompilerVariation() . "/$ver)\n";
    print "-${cxxProdname}       <path>      : path where the C++ compiler is installed\n";
    print "                           (default: /opt/ibmcmp/${cxxProdname}" . &getCompilerVariation() . "/$ver)\n";
  } # END _if_vacpp_
  if (&isFortranProd) {
    if (&useLicPackage) {
      print "-${fortranProdname}lic    <path>      : path where the XL Fortran license package is installed\n";
      print "                         (default: /opt/ibmcmp/$prod" . &getCompilerVariation() . "/$ver)\n";
    } # END _if_useLicPackage_
    print "-${fortranProdname}rt     <path>      : path where the XL Fortran runtime is installed\n";
    print "                         (default: /opt/ibmcmp/$prod" . &getCompilerVariation() . "/$ver)\n";
    print "-${fortranProdname}       <path>      : path where the XL Fortran compiler is installed\n";
    print "                         (default: /opt/ibmcmp/$prod" . &getCompilerVariation() . "/$ver)\n";
  } # END _if_xlf_
  print "<template_config_file> : name of the template configuration file\n";

  if (&isCProd || &isCxxProd) {
    print "                         (default: /opt/ibmcmp/${cProdname}" .
      &getCompilerVariation() . "/$ver/etc/${cProdname}.base.cfg)\n";
  } elsif (&isFortranProd) {
    print "                         (default: /opt/ibmcmp/${fortranProdname}" .
      &getCompilerVariation() . "/$ver/etc/${fortranProdname}.base.cfg)\n";
  } # END _case_prod)

  print "\n";

  programExit (2);
} # END usage ()

sub set_gcc_invocations {
#*******************************************************************************
#* Set the gcc compiler invocations for the various compilation modes (32/64-bit)
#* Allows the user to override the defaults through the use of environmet
#* variables.
#*******************************************************************************
  my (%invok);
  my ($prefix, $tgt_prefix) = ("", "");

  # complier invocation locations..
  my (%paths) = (
    'gcc32' => $opt{'gcc32'},
    'gcc64' => $opt{'gcc64'},
    'g++32' => $opt{'gcc32'},
    'g++64' => $opt{'gcc64'},

    'targetgcc32' => $opt{'targetgcc32'},
    'targetgcc64' => $opt{'targetgcc64'},
    'targetg++32' => $opt{'targetgcc32'},
    'targetg++64' => $opt{'targetgcc64'},
  );

  # default invocations..
  my (%def_invok) = (
    'gcc32' => "bin/${prefix}gcc",
    'g++32' => "bin/${prefix}g++",
    'gcc64' => "bin/${prefix}gcc",
    'g++64' => "bin/${prefix}g++",

    'targetgcc32' => "bin/${tgt_prefix}gcc",
    'targetg++32' => "bin/${tgt_prefix}g++",
    'targetgcc64' => "bin/${tgt_prefix}gcc",
    'targetg++64' => "bin/${tgt_prefix}g++",
  );

  # alternate invocations..
  my (%alt_invok) = (
    'gcc32' => '',
    'gcc64' => 'bin/powerpc64-linux-gcc',
    'g++32' => '',
    'g++64' => 'bin/powerpc64-linux-g++',

    'targetgcc32' => &getAltInvocation('gcc32'),
    'targetgcc64' => &getAltInvocation('gcc64'),
    'targetg++32' => &getAltInvocation('g++32'),
    'targetg++64' => &getAltInvocation('g++64'),
  );

  # user override invocations..
  my (%usr_invok) = (
    'gcc32' => $ENV{'CFG_GCC32_CCMD'},
    'g++32' => $ENV{'CFG_GCC32_CXXCMD'},
    'gcc64' => $ENV{'CFG_GCC64_CCMD'},
    'g++64' => $ENV{'CFG_GCC32_CXXCMD'},

    'targetgcc32' => $ENV{'CFG_TARGETGCC32_CCMD'},
    'targetg++32' => $ENV{'CFG_TARGETGCC32_CXXCMD'},
    'targetgcc64' => $ENV{'CFG_TARGETGCC64_CCMD'},
    'targetg++64' => $ENV{'CFG_TARGETGCC64_CXXCMD'},
  );

  foreach $cc ('gcc32','gcc64','g++32','g++64','targetgcc32','targetgcc64','targetg++32','targetg++64') {
    my (@alt_invok) = split (/:/, $alt_invok{$cc});
    foreach $alt (@alt_invok) {
      next unless (defined ($alt));
      if (-e "$paths{$cc}/$alt") {
        $invok{$cc} = $alt;
        printExtraDebug ("Setting alternate \"$cc\" to \"$invok{$cc}\".");
      } # END _set_alternates_
    } # END _foreach_each_alternate_invocation_

    if (defined ($usr_invok{$cc})) {
      $invok{$cc} = $usr_invok{$cc};
      printExtraDebug ("User overrides \"$cc\" to \"$invok{$cc}\".");
    } # END _set_usr_defines_

    unless (defined ($invok{$cc})) {
      $invok{$cc} = $def_invok{$cc};
      printExtraDebug ("Setting default \"$cc\" to \"$invok{$cc}\".");
    } # END _set_defaults_

    printDebug ("\"$cc\" set to \"$invok{$cc}\".");
  } # END _foreach_cc_

  foreach $cc ('gcc32', 'g++32') {
    if (&is64bitDefault) {$invok{$cc} = "$invok{$cc} -m32";}
    printDebug ("\"$cc\" re-set to \"$invok{$cc}\".");
  }

  return (%invok);
} # END set_gcc_invocations ()

sub getAltInvocation {
#*******************************************************************************
#* Return an alternate gcc/g++ invocation, depending on what product
#*******************************************************************************
  my ($invocation) = shift;

  my (%altInvocations) = (
    'bgp' => {
      'gcc32' => 'bin/powerpc-bgp-linux-gcc',
      'gcc64' => '',
      'g++32' => 'bin/powerpc-bgp-linux-g++',
      'g++64' => '',
    },
    'bgq' => {
      'gcc32' => 'bin/powerpc64-bgq-linux-gcc',
      'gcc64' => 'bin/powerpc64-bgq-linux-gcc',
      'g++32' => 'bin/powerpc64-bgq-linux-g++',
      'g++64' => 'bin/powerpc64-bgq-linux-g++',
    },
  );

  my ($architecture);

  if (&isBGP) {
    $architecture = 'bgp';
  } elsif (&isBGQ) {
    $architecture = 'bgq';
  }

  return '' unless defined($altInvocations{$architecture});

  return $altInvocations{$architecture}->{$invocation};

} # END getAltInvocations ()

sub set_os_macros {
#*******************************************************************************
#* Calls system commands or system file to obtain the values of the macros
#* about the OS. Sets the OS hash; returns 1 on success; undef otherwise.
#*******************************************************************************
  my ($macros)   = $_[0];
  my ($compiler) = $_[1];

  my ($os)    = "os_variant";
  my ($major) = "os_major";
  my ($minor) = "os_minor";
  my ($patch) = "os_patchlevel";
  printDebug ("Determining value of \"$os\" macro..");
  if (&isMacOSX) {
    $macros->{$compiler}->{$os}="macos";
  } elsif (&isRHEL) {
    if ($compiler =~ /^targetgcc/ && &isBGQ) {
      $macros->{$compiler}->{$os}="bgq";
    } else {
      $macros->{$compiler}->{$os}="rhel";
    }
  } elsif (&isSUSE) {
    if ($compiler =~ /^targetgcc/ && &isBGQ) {
      $macros->{$compiler}->{$os}="bgq";
    } elsif ($compiler =~ /^targetgcc/ && &isBGP) {
      $macros->{$compiler}->{$os}="bgp";
    } else {
      $macros->{$compiler}->{$os}="sles";
    }
  } elsif (&isFedora) {
    $macros->{$compiler}->{$os}="fedora";
  } elsif (&isYHPC) {
    $macros->{$compiler}->{$os}="yhpc";
  } else {
    $macros->{$compiler}->{$os}=undef;
  }
  printDebug ("Yielded == \"$macros->{$compiler}->{$os}\"");

  if (defined ($macros->{$compiler}->{$os})){
    ($macros->{$compiler}->{$major},$macros->{$compiler}->{$minor},$macros->{$compiler}->{$patch}) =
      &get_os_version($major,$minor,$patch);
    return undef unless (defined ($macros->{$compiler}->{$major}) &&
                         defined ($macros->{$compiler}->{$minor}) &&
                         defined ($macros->{$compiler}->{$patch}));
  } else {
    return undef;
  }
  return 1;
} # END set_os_macro ()

sub parse_version {
#*******************************************************************************
#* Parses a string to retrieve the OS version information.
#*******************************************************************************
  my $string = $_[0];
  printDebug ("Parsing version string \"$string\".");
  my ($v,$r,$m);
  if ($string =~ /(\d+)\.?(\d*)\.?([\d\.\w]*)/) { $v=$1; $r=$2; $m=$3; }
  $v = undef if ($v eq "");
  $r = "0"   if (!defined $r || $r eq "");
  $m = "0"   if (!defined $m || $m eq "");
  return ($v,$r,$m);
} # END parse_version ()

sub get_os_version {
#*******************************************************************************
#* Calls the system commands to return the OS version.
#*******************************************************************************
  my ($major) = $_[0];
  my ($minor) = $_[1];
  my ($patch) = $_[2];
  my ($v,$r,$m);
  printDebug ("Determining values of \"$major\", \"$minor\" and \"$patch\" macros..");
  if (&isMacOSX) {
    open (OSOUT, "sw_vers -productVersion 2>&1 |") or return undef;
    while (<OSOUT>) { chomp;
      printExtraDebug ("$_");
      ($v,$r,$m) = &parse_version($_);
        last if (defined $v && defined $r && defined $m);
    }
    close (OSOUT) or return undef;
  } elsif (&isLinux) {
    my ($osFilename) = &guess_os_filename();
    open (OSOUT, "< $osFilename") or return undef;
    while (<OSOUT>) { chomp;
      s/\//\./g;
      printExtraDebug ("$_");
      if (/(\d+).*Update ([\d\.\w]*)/) {
        $v=$1; ($r,$m)=&parse_version($2);
        printExtraDebug ("Parsing yielded \"$v\", \"$r\", and \"$m\".");
        last;
      } else {
        ($v,$r,$m) = &parse_version($_);
        last if (defined $v && defined $r && defined $m);
      }
    }
    close (OSOUT) or return undef;
  }
  printDebug ("Parsing yielded $major=\"$v\"");
  printDebug ("Parsing yielded $minor=\"$r\"");
  printDebug ("Parsing yielded $patch=\"$m\"");
  return ($v,$r,$m);
} # END get_os_version ()

sub get_gnu_macro {
#*******************************************************************************
#* Compiles a simple program to obtain the value of the given macro. Returns
#* the value of the macro on success; otherwise returns undef.
#*******************************************************************************
  my ($cc)    = $_[0];
  my ($macro) = $_[1];
  my ($file)  = $TEMP{'DUMMYC'};
  my ($value);
  my ($fname_ext, $macro_name)  = ($cc, $macro);
  foreach ($fname_ext, $macro_name) { $_ =~ s/\//-/g; $_ =~ s/\s+/_/g; }
  my ($tempout)  = $TEMP{'TEMPOUT'}.$fname_ext.'-'.$macro_name;

  printDebug ("Determining value of \"$macro\" macro.");
  if(openInfoFile (CCOUT, $tempout)) {
    while (<CCOUT>) { chomp;
      if (/\"$macro\"\s*=\s*(\S+)/) { $value = $1; }
    }
    close CCOUT or return undef;
    return $value;
  }

  unless (open (FILE, ">$file")) {
    printErr ("Error: Cannot create simple C program \"$file\""); return undef;
  }
  print FILE "\"$macro\"=$macro\n";
  close (FILE) or return undef;

  printDebug ("Running: \"$cc -E $file\"..");
  open (OUT, "$cc -E $file 2>&1 |") or return undef;
  open (TEMPOUT, "> $tempout") or return undef;
  while (<OUT>) {
    printInfoFile(TEMPOUT, $tempout, $_);
    printExtraDebug ("$_");
    if (/\"$macro\"\s*=\s*(\S+)/) { $value = $1; }
  }
  close (OUT) or return undef;
  close (TEMPOUT) or return undef;

  printDebug ("Yielded == \"$value\"");
  # If the macro still has the same name, macro has no value..
  if ($value eq $macro) {
    printDebug ("Macro \"$macro\" resolved to itself.. has no value.");
    $value = undef;
  }
  foreach ($file, $tempout) { unlink ($_); }
  return $value;
} # END get_gnu_macro ()

sub gen_c_program {
#*******************************************************************************
#* Create dummy C program with the given file name
#*******************************************************************************
  my ($file) = $_[0];
  unless (open (FILE, ">$file")) {
    printErr ("Error: Cannot create dummy C program \"$file\""); return 0;
  }
  print FILE "int main() { return 0; }\n";
  close (FILE) or return undef;
  printDebug ("Simple C program \"$file\" created.");
  return 1;
} # END gen_c_program ()

sub gen_cxx_program {
#*******************************************************************************
#* Create dummy C++ program with the given file name
#*******************************************************************************
  my ($file) = $_[0];
  unless (open (FILE, ">$file")) {
    printErr ("Error: Cannot create dummy C++ program \"$file\""); return 0;
  }
  # print FILE "#include <iostream>\n";
  # print FILE "int main() { std::cout << 1; return 0; }\n";
  print FILE "int main() { return 0; }\n";
  close (FILE) or return undef;
  printDebug ("Simple C++ program \"$file\" created.");
  return 1;
} # END gen_cxx_program ()

sub gen_c_tls_program {
#*******************************************************************************
#* Create dummy C program that uses __thread keyword with the given file name
#*******************************************************************************
  my ($file) = $_[0];
  unless (open (FILE, ">$file")) {
    printErr ("Error: Cannot create dummy __thread C program \"$file\"");
    return 0;
  }
  print FILE "__thread int i=0;\n";
  print FILE "int main() { i=1; return 0; } \n";
  close (FILE) or return undef;
  printDebug ("Simple __thread C program \"$file\" created.");
  return $file;
} # END gen_c_tls_program ()

sub gen_c_output {
#*******************************************************************************
#* Generate gcc '-v' output.
#*******************************************************************************
  my ($cc)   = $_[0];
  my ($exec) = $TEMP{'TEMPEXEC'};
  my ($dummy, $out);
  my ($fname_ext)  = ($cc);
  foreach ($fname_ext) { $_ =~ s/\//-/g; $_ =~ s/\s+/_/g; }

  $dummy = $TEMP{'DUMMYC'};
  $out   = $TEMP{'OUTPUTC'}.$fname_ext;

  # skip the real generation if using Info files
  return $out if (defined ($opt{'useInfo'}));

  gen_c_program ($dummy)   or return undef;
  open (OUT, ">$out") or return undef;
  printDebug ("Running: \"$cc -v $dummy -o $exec\"..");
  open (CCOUT, "$cc -v $dummy -o $exec 2>&1 |") or return undef;
  while (<CCOUT>) { chomp;
    printExtraDebug ("$_");
    printInfoFile(OUT,$out,"$_\n");
  }
  close (CCOUT) or return undef; close (OUT) or return undef;
  foreach ($dummy,$exec) { unlink ($_); }
  printDebug ("Output written to \"$out\".");
  return $out;
} # END gen_c_output ()

sub gen_cxx_output {
#*******************************************************************************
#* Generate g++ '-v' output.
#*******************************************************************************
  my ($cc)   = $_[0];
  my ($exec) = $TEMP{'TEMPEXEC'};
  my ($dummy, $out);
  my ($fname_ext)  = ($cc);
  foreach ($fname_ext) { $_ =~ s/\//-/g; $_ =~ s/\s+/_/g; }

  $dummy = $TEMP{'DUMMYCXX'};
  $out   = $TEMP{'OUTPUTCXX'}.$fname_ext;

  # skip the real generation if using Info files
  return $out if (defined ($opt{'useInfo'}));

  gen_cxx_program ($dummy) or return undef;
  open (OUT, ">$out") or return undef;
  printDebug ("Running: \"$cc -v $dummy -o $exec\"..");
  open (CCOUT, "$cc -v $dummy -o $exec 2>&1 |") or return undef;
  while (<CCOUT>) { chomp;
    printExtraDebug ("$_");
    printInfoFile(OUT,$out,"$_\n");
  }
  close (CCOUT) or return undef; close (OUT) or return undef;
  foreach ($dummy,$exec) { unlink ($_); }
  printDebug ("Output written to \"$out\".");
  return $out;
} # END gen_cxx_output ()

sub testCompilerOption {
#*******************************************************************************
#* Run the command "$compiler $option $dummy -o $exec".
#* $dummy is the input file provided when the function is invoked.
#* $out   is contains the compilation output if defined
#* $exec  is the executable after $dummy is compiled
#* $saveExec=1, $exec will not be deleted upon completion of the function
#* Returns compilation return code (1 if compiled successfully)
#*******************************************************************************
  my ($compiler) = $_[0];
  my ($option)   = $_[1];
  my ($dummy)    = $_[2];
  my ($out)      = $_[3];
  my ($saveExec) = $_[4];
  my ($exec)     = $_[5];
  my ($rc, );
  my @file_exts  = ($compiler, $option, $out, $saveExec, $exec);
  foreach (@file_exts) { $_ =~ s/\//-/g; $_ =~ s/\s+/_/g; }
  my ($tempout)  = $TEMP{'TEMPOUT'}.(join ('-', @file_exts));

  if(openInfoFile (TEMP, $tempout)) {
    while (<TEMP>) { chomp;
      if (/\"rc\"\s*=\s*(\S+)/) { $rc = $1; }
    }
    close (TEMP) or return undef;
    return $rc;
  }

  unless (defined ($exec)) {$exec = $TEMP{'TEMPEXEC'};}

  if (defined $out) { open (OUT, ">$out") or return undef; }
  printDebug ("Running: \"$compiler $option $dummy -o $exec\"..\n");
  open (CCOUT, "$compiler $option $dummy -o $exec 2>&1 |") or return undef;
  while (<CCOUT>) { chomp;
    printExtraDebug ("$_");
    if (defined $out) { print OUT "$_\n"; }
  }
  $rc = close (CCOUT);
  open (RESULT, ">$tempout");
  printInfoFile(\*RESULT, $tempout, "\"rc\" = $rc\n");
  close (RESULT);

  if (defined ($out)) {
    close (OUT) or return undef;
    printDebug ("Output written to \"$out\".");
  }

  foreach ($dummy) {unlink $_;}
  unlink ("$exec") unless ($saveExec);

  return $rc;
} # END testCompilerOption ()

sub valueExist {
#*******************************************************************************
#* Return the number of values found in array
#******************************************************************************
  my ($array) = splice (@_, -1, 1);
  my (@values) = splice (@_, 0);
  my ($found) = 0;

  foreach $v (@values) {
    if (grep($v eq $_, @$array)) {
      $found += 1;
    }
  }

  return $found;
} # END valueExist ()

sub gen_tempfile {
#******************************************************************************
#* Takes in a string and returns a process unique temporary file name.
#******************************************************************************
  my ($string) = $_[0];
  my ($unique) = "/tmp/__${$}_${string}";
  return $unique;
} # END gen_tempfile ()

sub get_dynlib_path {
#******************************************************************************
#* Obtain a dynlib path
#******************************************************************************
  my ($listing)  = $_[0];
  my ($bin_mode) = $_[1];
  my ($path);
  printDebug ("Looking for dynlib paths in \"$listing\"..");
  openInfoFile (LISTING, "$listing") or return undef;
  while (<LISTING>) { chomp;
    if (/dynamic-linker\s+(\S+)\s+/) {
      printExtraDebug ("Found the dynamic-linker search path: \"$1\"");
      $path = $1;
      last;
    }
  }
  if ($path eq "") {
     if ($bin_mode eq "32") {
       $path = "-dynamic-linker," . "/lib/ld.so.1";
     } elsif ($bin_mode eq "64") {
       $path = "-dynamic-linker," . "/lib64/ld64.so.1";
     } else {
       printErr ("Compiler mode is undefined or equal:\"$bin_mode\"");
     }
  } else {
     $path = "-dynamic-linker," . $path;
  }
  close (LISTING) or return undef;

  return $path;

} # END get_dynlib_path ()

sub get_search_path {
#******************************************************************************
#* Obtain a list of standard search paths separated by colons
#******************************************************************************
  my ($listing) = $_[0];
  my ($paths);
  my ($include_found);
  my @foundpaths = ();
  printDebug ("Looking for SEARCH paths in \"$listing\"..");
  openInfoFile (LISTING, "$listing") or return undef;
  while (<LISTING>) { chomp;
    if ( ( /\#include <\.\.\.>/i) || (/include.*search starts here/i) ) {
      $include_found=1;
    } elsif ( (/^\S+/) || (/End of search list/) ) {
      $include_found=0;
    } elsif ($include_found) {
      printExtraDebug ("Found this search path: \"$_\"");
      my $path=$_;
      if (grep /^\Q$path\E$/, @foundpaths) { printExtraDebug ("path already existed"); }
      elsif (defined($paths)) { $paths  = "$paths:$path"; push @foundpaths,$path; }
      else                    { $paths  = "$path"; push @foundpaths,$path; }
    }
  } # END _while_listing_
  close (LISTING) or return undef;
  # default fallback value..
  $paths = '/usr/include' unless (defined ($paths));
  $paths =~ s/\s//g; # strip out any spaces..
  printDebug ("Yielded == \"$paths\"");
  return $paths;
} # END get_search_path ()

sub get_exe_path {
#*******************************************************************************
#* Search for the given executable with the given GCC information.
#*******************************************************************************
  my ($listing)    = $_[0];
  my ($baseloc)    = $_[1];
  my ($file)       = $_[2];
  my ($fname_ext)  = $baseloc;
  foreach ($fname_ext) { $_ =~ s/\//-/g; $_ =~ s/\s+/_/g; }
  my ($result)  = $listing.$fname_ext."_result";
  my ($path);

  my $filePattern = $file;
  $filePattern =~ s/\+/\\+/g;
  $filePattern =~ s/\./\\./g;

  printDebug ("Looking for \"$file\" path..");

  # If the result is already generated then use the existing result
  openInfoFile (RESULT, $result);
  while(<RESULT>) {chomp;
    if ($_ =~ m/^$file\s*=\s*\"(\S+)\"/) { $path = $1; last; }
    else                                 { $path = undef; }
  }
  close (RESULT);
  if (defined $path) { printDebug ("Yielded == \"$path\""); return $path; }

  # First, look in the listing file to see if GCC tells us..
  printDebug ("Searching compiler output file \"$listing\"..");
  openInfoFile (LISTING, "$listing") or return undef;
  while (<LISTING>) { chomp;
    printExtraDebug ("Parsing line \"$_\"..");
    foreach $tok (split(' ',$_)) {
      if ($tok =~ /^(\/\S+)\/$filePattern/) {
        printExtraDebug ("Found this executable path: \"$tok\"");
        $path = "$1/$file" if (-e "$1/$file");
        printDebug ("Found \"$file\" in \"$1\"..");
        last;
      } # END _if_exepath_tok_
    }   # END _foreach_token_
  }     # END _while_listing_
  close (LISTING) or return undef;

  # Secondly, try the $gcc/bin directory..
  if (!defined($path)) {
    my ($try) = "$baseloc/bin";
    printDebug ("Searching compiler \'bin\' directory \"$try\"..");
    $path = "$try/$file" if (-e "$try/$file");
  }

  # Last resort is to try a mass find on the $gcc directory..
  if (!defined($path)) {
    printDebug ("Searching compiler directory \"$baseloc\"..");
    $path = &find_file ($baseloc, $file);
  }
  # Save the result to a hard-copy file
  open (RESULT, ">>$result") or return undef;
  printInfoFile (\*RESULT, "$result", "$file = \"$path\"\n");
  close (RESULT);
  printDebug ("Yielded == \"$path\"");

  return $path;
} # END get_exe_path ()

sub get_lib_path {
#*******************************************************************************
#* Obtain a list of C/C++ library paths by searching the given starting
#* directory.  If a file is given, then the path in which the given file is
#* found in is returned. Otherwise a list of the library paths are returned.
#*******************************************************************************
  my ($listing) = $_[0];
  my ($file)    = $_[1];
  my ($result)  = $listing."_result";
  my ($paths, $rpath, @rpaths);
  my ($found_rpath) = 0;
  my ($filepath);
  if (defined ($file)) {
    printDebug ("Looking for \"$file\" in LIBRARY paths in \"$listing\"..");
  } else {
    printDebug ("Looking for LIBRARY paths in \"$listing\"..")
  }
  openInfoFile (LISTING, "$listing") or return undef;
  while (<LISTING>) { chomp;
    printExtraDebug ("Parsing line \"$_\"..");
    foreach $tok (split(' ',$_)) {
      if ($found_rpath) {
        printExtraDebug ("Added rpath: \"$tok\"");
         push (@rpaths, $tok);
         $found_rpath = 0;
         next;
      }
      if ($tok =~ /^-L(\S+)$/) {
        printExtraDebug ("Found this library path: \"$tok\"");
        $paths = join (',',$paths,$tok);
        if (defined ($file) and (-e "$1/$file")) {
          open (RESULT, ">>$result") or return undef;
          $filepath = "$1/$file";
          printInfoFile (\*RESULT, "$result", "$file = \"$filepath\"\n");
          printDebug ("Found \"$file\" in \"$1\"..");
          close (RESULT);
          last;
        }
      } # END _if_libpath_tok_
      if ($tok =~ /rpath/) {
         printExtraDebug ("Found the rpath path: \"$tok\"");
         $found_rpath= 1;
      } # END _if_rpath_tok
    }   # END _foreach_token_
  }     # END _while_listing_
  close (LISTING) or return undef;
  # default fallback value..
  if (scalar(@rpaths)) {
    $paths .= ",-R" . (join (",-R", @rpaths));
  }
  $paths = '/usr/lib' unless (defined ($paths));
  $paths =~ s/\s//g; # strip out any spaces..
  $paths =~ s/(^,)|(,$)//;  # strip out leading/trailing commas..
  if (defined ($file)) {
    # default fallback value..
    if (! (defined ($filepath)) and (-e "/usr/lib/$file")) {
      $filepath = "/usr/lib/$file";
    }
    openInfoFile (RESULT, $result);
    while(<RESULT>) {chomp;
      if ($_ =~ m/^$file\s*=\s*\"(\S+)\"/) { $filepath = $1; last; }
      else                                 { $filepath = 'NULL'; }
    }
    close (RESULT);
    printDebug ("Yielded == \"$filepath\"");
    return $filepath;
  } else {
    printDebug ("Yielded == \"$paths\"");
    return $paths;
  }
} # END get_lib_path ()

sub chop_path {
#*******************************************************************************
#* Returns a path that has removed $depth directory(ies) from the end of the
#* path; default $depth is 1; returns 'undef' otherwise.
#* For example:
#*   rm_end_of_path ("/opt/ibmcmp/smprt/1.7", 2) will return  "/opt/ibmcmp"
#*******************************************************************************
  my($path, $depth) = splice (@_, 0, 2);
  $depth = 1 unless defined($depth);
  printExtraDebug ("Chopping \"$depth\" directory(ies) from end of \"$path\"..");
  if (($depth =~ /\D/) || ($depth < 0)) {
    printDebug ("Cannot chop \"$depth\" directory(ies) from end of \"$path\".");
    return undef;
  }
  for ($i = 0; $i < $depth; $i++) {
    $path = dirname($path);
  }
  printExtraDebug ("Yielded == \"$path\".");
  return $path;
} # END chop_path ()

sub read_templ_attr {
#*******************************************************************************
#* Searches for the given attribute in the given configuration file. Returns
#* the base file name value associated with the given attribute if found;
#* returns 'undef' otherwise.
#*******************************************************************************
  my ($templ)     = $_[0];
  my ($fullAttr)  = $_[1];
  my ($value, $file);

  $value=&read_templ_attr_value($templ, $fullAttr);
  if (defined ($value)) {
    $file = basename($value); chomp ($file);
    return undef if (!defined $file || $file eq "");
  } # END _if_value_found_
  printDebug ("Yielded == \"$file\"");
  return $file;
}

sub read_templ_attr_value {
#*******************************************************************************
#* Searches for the given attribute in the given configuration file. Returns
#* the value associated with the given attribute if found;
#* returns 'undef' otherwise.
#*******************************************************************************
  my ($templ)     = $_[0];
  my ($fullAttr)  = $_[1];

  my ($tempValue, $value, $attr, $stanza);
  my ($prefix) = '';

  if ($fullAttr =~ /,/) {
    ($prefix, $attr) = split(/,/, $fullAttr);
    $prefix = &getStanzaPrefix($prefix);
  }
  if ($fullAttr =~ /:/) {
    ($prefix, $attr) = split(/:/, $fullAttr);
    $prefix = &getStanzaPrefix($prefix);
  }
  else {
    $attr = $fullAttr;
  }

  # replacing the regexp with escape characters
  $attr=~s/\+/\\\+/;

  printDebug ("Reading attribute \"$attr\" value from \"$templ\"..");
  printDebug ("Stanza prefix is \"$prefix\"..") if length($prefix) > 0;

  open (TEMPL, "$templ") or return undef;

  while ($line = <TEMPL>) { chomp ($line);
    if (($line =~ /^(\S+):/)) { $stanza = $1; }

    if (!&isBG && $stanza =~ /^bg/) {
      printAndDie ("$stanza found in template file.  $stanza stanza is not recognized for the compiler you are trying to configure");
    }

    if ($line =~ /(.*\s+)($attr)(\s*[:\+-]?=\s*)(\S+)/) {
      $tempValue = $4;

      next if (length($prefix) > 0 && $stanza !~ /^$prefix/);

      unless ($line =~ /^\s*\*/) { # skip over comments..
        printExtraDebug ("Found \"$line\".");
        $value = $tempValue;
        # terminate search either
        # 1. finds the one under DEFLT if it exists there, or
        # 2. use whatever the one it lastly finds
        last if ($stanza =~ /^DEFLT/);
      } # END _skip_comments_
    }   # END _if_attr_
  } # END _while_template_
  close (TEMPL) or return undef;
  if ($value =~ /^-l(\S+)/) {
    printExtraDebug ("Found \"-l\" in \"$value\".. cropping..");
    $value = $1;
  } # END _if_-llib_syntax_
  return $value;
} # END read_templ_attr_value ()

#*******************************************************************************
#* Replacing the gcc include search paths where given headers are found
#*******************************************************************************
sub replace_gcc_incdir {
  my ($paths1)  = $_[0];
  my ($paths2)  = $_[1];
  my ($excld)   = $_[2];
  my ($paths3)  = "";
  my (@paths)      = split(/:/, $paths1);
  my (@excld_list) = split(/\|/, $excld);
  my ($p, $h);
  my ($replace_path) = 0;
  my ($infoFile) = "$TEMP{'TEMPOUT'}-replace_header";

  if (openInfoFile (INFO, "<$infoFile")) {
    my $paths1String=quotemeta $paths1;
    while(<INFO>){
      $line = $_;
      chomp $line;
      if ($line =~ m/^$paths1String\|(.*)\|(.*)$/) {
        my $oldpaths2String=quotemeta $1;
        $paths3 = $2;
        $paths3 =~ s/$oldpaths2String/$paths2/g;
        last;
      }
    }
    close (INFO);
  } else {
    foreach $p (@paths) {
      foreach $list (@excld_list) {
	$replace_path = 1;
	my @hdr_list = split(/\,/, $list);
	foreach $h (@hdr_list) {
	  # don't replace the path unless all excluded files are found
	  unless ( -e "$p/$h" ) { $replace_path = 0; }
	}
	last if ($replace_path);
      }
      if ( $replace_path ) {
      # replace this path with the give path(s) if all headers are found
	$paths3 .= $paths2 . ":";
      } else {
	$paths3 .= "$p" . ":";
      }
    }

    $paths3 =~ s/(:$)//;  # strip out trailing colon ..
    open (INFO, ">>$infoFile") or return undef;
    printInfoFile (\*INFO, "$infoFile", "$paths1|$paths2|$paths3\n");
    close (INFO);
  }

  foreach ($infoFile) { unlink ($_); }
  return $paths3;
}

sub find_file {
#*******************************************************************************
#* Searches for the given file from the given starting directory..
#*******************************************************************************
  my ($dir)     = $_[0];
  my ($file)    = $_[1];
  my ($location);

  printDebug ("Searching for \"$file\" in \"$dir\"..");

  open (FIND, "find $dir -name $file 2>/dev/null |") or return undef;
  while (<FIND>) { chomp;
    printExtraDebug ("Found \"$_\".");
    $location = $_; last;
  } # END _while_find_
  close (FIND) or return undef;
  printDebug ("Yielded == \"$location\"");
  return $location;
} # END find_file ()

sub isCProd {
#******************************************************************************
#* Returns true if configuration for C only product.
#******************************************************************************
  my ($prod, $ver) = guess_prod_name ();
  if ($prod eq $cProdname || &isOpenCL) { return 1; }
  else                     { return 0; }
} # END isCProd ()

sub isUpcProd {
#******************************************************************************
#* Returns true if configuration for UPC product.
#******************************************************************************
  my ($prod, $ver) = guess_prod_name ();
  if ($prod eq $upcProdname) { return 1; }
  else                       { return 0; }
} # END isUpcProd ()

sub isCxxProd {
#******************************************************************************
#* Returns true if configuration for C/C++ product.
#******************************************************************************
  my ($prod, $ver) = guess_prod_name ();
  if ($prod eq $cxxProdname && !&isOpenCL) { return 1; }
  else                       { return 0; }
} # END isCxxProd ()

sub isFortranProd {
#******************************************************************************
#* Returns true if configuration for Fortran product.
#******************************************************************************
  my ($prod, $ver) = guess_prod_name ();
  if ($prod eq $fortranProdname) { return 1; }
  else                           { return 0; }
} # END isFortranProd ()

sub isCxxBgProd {
#******************************************************************************
#* Returns true if configuration for C/C++ Blue Gene product.
#******************************************************************************
  if (&isCxxProd && &isBG)  { return 1; }
  else                      { return 0; }
} # END isCxxBgProd ()

sub isFortranBgProd {
#******************************************************************************
#* Returns true if configuration for Fortran Blue Gene product.
#******************************************************************************
  if (&isFortranProd && &isBG)  { return 1; }
  else                          { return 0; }
} # END isFortranBgProd ()

sub isFedora {
#******************************************************************************
#* Returns true if operating system is Fedora
#******************************************************************************
  my ($osFilename) = &getReleaseFileLocation()."/fedora-release";
  if (-e $osFilename && &isLinux) { return 1; }
  else                            { return 0; }
} # END isFedora ()

sub isMacOSX {
#******************************************************************************
#* Returns true if operating system is Red Hat Linux
#******************************************************************************
  my ($hostOS) = guess_os_name ();
  if (lc($hostOS) eq 'darwin') { return 1; }
  else                         { return 0; }
} # END isMacOSX ()

sub isLinux {
#******************************************************************************
#* Returns true if operating system is Linux
#******************************************************************************
  my ($hostOS) = guess_os_name ();
  if ($hostOS eq 'linux') { return 1; }
  else                    { return 0; }
} # END isLinux ()

sub isRHEL {
#******************************************************************************
#* Returns true if operating system is Red Hat
#******************************************************************************
  my ($osFilename) = &getReleaseFileLocation()."/redhat-release";
  my ($fedoraOSFilename) = &getReleaseFileLocation()."/fedora-release";
  if (-e $osFilename && &isLinux && !(-e $fedoraOSFilename)) { return 1; }
  else                                                       { return 0; }
} # END isRHEL ()

sub isSUSE {
#******************************************************************************
#* Returns true if operating system is SUSE
#******************************************************************************
  my ($osFilename) = &getReleaseFileLocation()."/SuSE-release";
  if (-e $osFilename && &isLinux) { return 1; }
  else                            { return 0; }
} # END isSUSE ()

sub isYHPC {
#******************************************************************************
#* Returns true if operating system is YHPC
#******************************************************************************
  my ($osFilename) = &getReleaseFileLocation()."/yhpc-release";
  if (-e $osFilename && &isLinux) { return 1; }
  else                            { return 0; }
} # END isYHPC ()

sub isBG {
#******************************************************************************
#* Returns true if operating system is SUSE and targetPlatform is bluegene
#******************************************************************************
  if (&isSUSE || &isRHEL) {
    if (defined($opt{'targetPlatform'})) {
      return ($opt{'targetPlatform'} eq 'bluegene');
    }
    else {
      return defined(&getBlueGeneVersion());
    }
  }

  return 0;
} # END isBG ()

sub isBGQ {
#******************************************************************************
#* Returns true if target system is bluegene and version is L
#******************************************************************************
  return (&isBG && &getBlueGeneVersion() eq 'Q');
} # END isBGQ ()

sub isBGP {
#******************************************************************************
#* Returns true if target system is bluegene and version is P
#******************************************************************************
  return (&isBG && &getBlueGeneVersion() eq 'P');
} # END isBGP ()

sub getBlueGeneVersion {
#******************************************************************************
#* Returns the Blue Gene version if it's defined, otherwise returns undef
#******************************************************************************
  return $__BG_VERSION__;
} # END getBlueGeneVersion ()

sub getOpenCLMode {
#******************************************************************************
#* Returns the Cell source mode if it's defined, otherwise returns undef
#******************************************************************************
  return $__OPENCL_MODE__;
} # END getOpenCLMode ()

sub getDefaultTarget {
#******************************************************************************
#* Returns either sles, rhel, or yhpc depending on the OS
#* Only valid if &isLinux() is true, otherwise return undef
#******************************************************************************
  if    (&isBG)	    { return 'bluegene'; }
  elsif (&isSUSE)   { return 'sles'; }
  elsif (&isRHEL)   { return 'rhel'; }
  elsif (&isYHPC)   { return 'yhpc'; }
  elsif (&isFedora) { return 'fedora'; }
  else            { return undef;  }
} # END getDefaultTarget ()

sub isOpenCL {
#******************************************************************************
#* Returns true if targetting operating system is cell
#******************************************************************************
  return &getOpenCLMode();

  return 0;
} # END isOpenCL ()

sub isValidProductPath {
#******************************************************************************
#* Returns true if the path specified is valid for the product
#******************************************************************************
  my ($path) = shift;

  my ($prod, $ver) = &guess_prod_name();
  my (@patterns)   = ();

  if (&isCProd || &isCxxProd) {
    push(@patterns, "$cProdname"   . &getCompilerVariation() . "/$ver");
  }

  if (&isCxxProd) {
    push(@patterns, "$cxxProdname" . &getCompilerVariation() . "/$ver");
  }

  if (&isFortranProd) {
    push(@patterns, "$fortranProdname" . &getCompilerVariation() . "/$ver");
  }

  unless (&isOpenCL) {
    push(@patterns, "xlsmp"   . &getCompilerVariation() . "/" . &get_smp_ver());
    push(@patterns, "xlmass"  . &getCompilerVariation() . "/" . &get_mass_ver());
  }

  unless ($#patterns < 0 || grep($path =~ /$_(\/)?$/, @patterns)) {
    printErr ("\"$path\" does not appear to be a valid installation path for the compiler you are trying to configure");
    return 0;
  }

  return 1;

} # END isValidProductPath ()

sub getCompilerVariation {
#******************************************************************************
#* returns the compiler variation used in the install path
#******************************************************************************
  if (&isBG)    { return '/bg'; }
  if (&isOpenCL)  { return '/opencl'; }
  else        { return ''; }
} # END getCompilerVariation ()

sub getReleaseFileLocation {
#******************************************************************************
#* Returns the location of the release file for the current Linux system
#******************************************************************************
  if (&isLinux) {
    return ((defined $opt{'osrelease'})?$opt{'osrelease'}:'/etc');
  } else {
    printAndDie ("The current system is not Linux");
  }
} # END getReleaseFileLocation ()

sub getStanzaPrefix {
#******************************************************************************
#* Returns a prefix of targetgcc32/targetgcc64 stanzas
#******************************************************************************
  my ($prefix) = shift; # unused for now

  if    (&isBG)       { return 'bg'; }
  elsif (&isOpenCL)   { return $prefix; }
  else             { return 'NULL_'; }

} # END getStanzaPrefix ()

sub useLicPackage {
#******************************************************************************
#* Returns true if platform supports the use of the -$prodlic package
#******************************************************************************
  return 1 if (&isLinux);
  return 1 if (&isMacOSX);
  return 0;
} # END useLicPackage ()

sub useOSMacro {
#******************************************************************************
#* Returns true if os macros are enabled for the specific platforms
#******************************************************************************
  return 1;
} # END useLicPackage ()

sub allowNullAttr {
#******************************************************************************
#* Returns true if the config file allow null attributes
#******************************************************************************
  return 1;
} # END useLicPackage ()

sub is64bitEnabled {
#******************************************************************************
#* Returns true if 64-bit configuration is enabled.
#******************************************************************************
  return 1 if (&isLinux);
  return 0 if (&isMacOSX);
  return 0;
} # END is64bitEnabled ()

sub is64bitDefault {
#******************************************************************************
#* Returns true if 64-bit configuration is default.
#******************************************************************************
  return 0;
} # END is64bitEnabled ()

sub isAltDEFLTStanza {
#******************************************************************************
#* Returns true if the given stanza stanza is alternative default stanza
#******************************************************************************
  my ($prefix) = $_[0];
  my ($stanza) = $_[1];
  my ($prefix_uc) = uc $prefix;
  if (&isBG && ($stanza=~m/${prefix}DEFLT/)) {
    return 1;
  } else {
    return 0;
  }
} # END isAltDEFLTStanza ()

sub isCrtsavresRemove {
#******************************************************************************
#* Returns true if we don't need crtsavres in config file
#******************************************************************************
  my ($gnu_major) = $_[0];
  my ($gnu_minor) = $_[1];
  return ($gnu_major >= 4 && $gnu_minor >=4);
} # #END isCrtsavresRemove ()

sub guess_os_name {
#******************************************************************************
#* Attempts to determine the operating system.
#******************************************************************************
  my ($hostOS) = `uname`;
  chomp ($hostOS);
  $hostOS=~tr/[A-Z]/[a-z]/;
  if (defined ($hostOS)) { return "$hostOS"; }
  else                   { return undef;     }
} # END guess_os_name ()

sub guess_os_filename {
#******************************************************************************
#* Attempts to determine the operating system's information file.
#******************************************************************************
  if    (&isRHEL)   { return &getReleaseFileLocation()."/redhat-release"; }
  elsif (&isFedora) { return &getReleaseFileLocation()."/fedora-release"; }
  elsif (&isSUSE)   { return &getReleaseFileLocation()."/SuSE-release"; }
  elsif (&isYHPC)   { return &getReleaseFileLocation()."/yhpc-release"; }
  else              { return undef; }
} # END guess_os_filename ()

sub guess_RHEL_ver {
#******************************************************************************
#* Attempts to determine the RHEL version
#******************************************************************************
  my ($osFilename) = &getReleaseFileLocation()."/redhat-release";
  my ($RHEL_ver) = undef;
  if (&isRHEL()) {
    $RHEL_ver = `cat $osFilename | grep -i release`; chop ($RHEL_ver);
    $RHEL_ver =~ m/.*release\s*(\d\.?\d?\d?)/i;
    $RHEL_ver = $1;
  }
  return $RHEL_ver;
} # END guess_RHEL_ver ()

sub guess_prod_name {
#******************************************************************************
#* Attempts to determine the product we are configuring for. If successful,
#* returns the product name and version number; undef otherwise.
#******************************************************************************
  my ($prod, $ver);
  if    ($0 =~ /($cProdname)_configure/)       { $prod = $1; $ver = $__XLCPP_VERSION__; }
  elsif ($0 =~ /($cxxProdname)_configure/)     { $prod = $1; $ver = $__XLCPP_VERSION__; }
  elsif ($0 =~ /($upcProdname)_configure/)     { $prod = $1; $ver = $__XLUPC_VERSION__; }
  elsif ($0 =~ /($fortranProdname)_configure/) { $prod = $1; $ver = $__XLF_VERSION__; }
  else                                         { return undef; }

  # Linux vac=vacpp..
  $prod = $cxxProdname if (($prod eq $cProdname) and (&isLinux));

  return ($prod, $ver);
} # END guess_prod_name ()

sub get_smp_ver {
#******************************************************************************
#* Attempts to determine the SMP version on the system..
#******************************************************************************
  my ($ver);
  if (&isLinux) { $ver = $__SMP_VERSION__; }
  return ($ver);
} # END get_smp_ver ()

sub get_mass_ver {
#******************************************************************************
#* Attempts to determine the SMP version on the system..
#******************************************************************************
  my ($ver);
  if (&isLinux) { $ver = $__MASS_VERSION__; }
  else          { $ver = ''; }
  return ($ver);
} # END get_mass_ver ()

sub get_shr_lib_ext {
#******************************************************************************
#* Returns the shared library extension convention for the platform.
#******************************************************************************
  my ($ext);
  if    (&isLinux)  { $ext = '.so';    }
  elsif (&isMacOSX) { $ext = '.dylib'; }
  else              { $ext = '.a';     }
  return ($ext);
} # END get_shr_lib_ext ()

sub printDebug {
#******************************************************************************
#* Prints only if in verbose mode..
#******************************************************************************
  if ($opt{'verbose'}) {
    my ($str) = $_[0]; print "DEBUG: $str\n"; return 1;
  } else {
    $indCounter = 0 unless (defined $indCounter);
    if ($indCounter % 60 == 0) {
      print ($indCounter == 0?"":"\n");
      print "    ";
    }
    $indCounter++; print "#";
  }
} # END printDebug ()

sub printExtraDebug {
#******************************************************************************
#* Prints only if in very verbose mode..
#******************************************************************************
  return 1 unless ($opt{'veryverbose'});
  my ($str) = $_[0]; print "DEBUG: -- $str\n"; return 1;
} # END printExtraDebug ()

sub printAndDie {
#******************************************************************************
#* Prints only if in very verbose mode..
#******************************************************************************
  my ($str) = $_[0]; print STDERR "ERROR: $str\n";
  programExit (1);
} # END printAndDie ()

sub printErr {
#******************************************************************************
#* Prints given string prefixed with "ERROR:" to standard error.
#******************************************************************************
  my ($str) = $_[0]; print STDERR "ERROR: $str\n"; return 1;
} # END printErr ()

sub printWarn {
#******************************************************************************
#* Prints given string prefixed with "WARNING:" to standard error.
#******************************************************************************
  my ($str) = $_[0]; print STDERR "WARNING: $str\n"; return 1;
} # END printWarn ()

sub printInfo {
#******************************************************************************
#* Prints given string prefixed with "INFORMATIONAL:" to standard error.
#******************************************************************************
  return 1 if ($opt{'quiet'});
  my ($str) = $_[0]; print STDERR "INFORMATIONAL: $str\n"; return 1;
} # END printInfo ()

sub programExit {
#******************************************************************************
#* Cleans up all temporary files and exits with given return code.
#******************************************************************************
  my ($exit_code) = $_[0];
  printDebug ("Program clean up..");
  if ($opt{'veryverbose'}) {
    printExtraDebug ("Very verbose mode: Clean up of temp files skipped.");
    exit $exit_code;
  }
  foreach $f (keys (%TEMP)) {
    if (-e "$TEMP{$f}") {
      printDebug ("Clean up - \"$TEMP{$f}\"..");
      unlink ("$TEMP{$f}") or printErr ("Can not clean up \"$TEMP{$f}\" - $!");
    }
  } # END
  exit $exit_code;
} # END programExit ()

sub openInfoFile {
#******************************************************************************
#* Open a file for reading information
#******************************************************************************
  my ($fd, $fname) = @_;
  my $infoName = (basename $fname)."_info";
  if (defined $opt{'useInfo'}) {
    # get rid of the PID exact match
    foreach ($infoName) { $_=~s/\+/\\\+/g; $_=~ s/^__[0-9]+_/^__\[0-9\]\+_/; }
    opendir (DIR,$opt{'useInfo'}) or return undef;
    @infoFiles = grep { /^$infoName$/ && -f "$opt{'useInfo'}/$_" } readdir(DIR);
    printDebug ("-useInfo is used, Using file $opt{'useInfo'}/$infoFiles[0]");
    open ($fd, "$opt{'useInfo'}/$infoFiles[0]") or return undef;
  } else {
    printExtraDebug ("-useInfo is not used, use file $fname");
    open ($fd, $fname) or return undef;
  }
  return 1;
}

sub printInfoFile {
#******************************************************************************
#* Print information to a file
#******************************************************************************
  my ($fd, $fname, $string) = @_;
  my $infoName = (basename $fname)."_info";
  print $fd $string or return undef;
  if (defined $opt{'saveInfo'}) {
    printDebug ("-saveInfo is used, writing to file $infoName under $opt{'saveInfo'}");
    open (TMPFILE, ">> $opt{'saveInfo'}/$infoName") or
      printErr ("Can not open file $opt{'saveInfo'}/$infoName for writing");
    print TMPFILE $string;
    close (TMPFILE) or printErr ("Can not close file $infoName");
  } else {
    printExtraDebug ("-saveInfo is not used, nothing is done");
  }
}

# END _vac/xlf_configure_

