#! /usr/bin/perl
# -*- Mode: perl; -*-
#
# Set some defaults
$includedir = ".";
$makefilebase = "Makefile.base";
$ranliblib    = 1;
$useinclude = 0;
$include_list = "";
$vpath_config = 0;   # set to 1 for @VPATH@
$nocomments = 0;     # set to 1 to exclude comments from the source file
$commonmake = "";    # Common entries for each generated Makefile
$maint_targets = 1;  # set to 0 for distribution versions
$verbose = 0;        # set to 1 to get more information
$am_a = "";          # set to _a for automake style input
$do_dependencies = "dynamic"; # set to no, static, or dynamic to attempt
                              # to generate dependency information 
			      # use "ignore" to produce a target (for
			      # recursive ops) but no actions
$makeInclude = "include";     # set to the include command to use.
                              # This is more robust if it ignores missing files
# Set the names for the autoconf and autoheader program, along with 
# the optional args and the argument used to specify the include dir for
# autoconf/autoheader (autoconf 2.57 changed the command-line interface
# without maintaining backward compatibility)
if (defined($ENV{"AUTOCONF"})) { 
    $autoconf_prog = $ENV{"AUTOCONF"};
}
else {
    $autoconf_prog = "autoconf";
}
if (defined($ENV{"AUTOHEADER"})) { 
    $autoheader_prog = $ENV{"AUTOHEADER"};
}
else {
    $autoheader_prog = "autoheader";
}

$autoconf_args = ""; # Extra arguments for autoconf
$acincdir_arg = "-l";

$do_sharedlibs  = 1; # set to 1 the generate targets for shared libraries
$found_sharedlib = 0;# set to 1 if a specific shared library target is found

$root_tags = 1;      # set to 1 to create a tags file in the root dir
$local_tags = 0;     # set to 1 to create a tags file in the local dir
$do_libmember = 0;   # set to 1 to generate library member rules in makefiles
$do_docs = 1;        # set to 1 to generate documentation

$convert_Ldir_to_relative = 1; # set to 1 to convert -Ldir to ../../lib 
                     # relative to the rootdir
#
# The following two symbols are defined for future use in generating
# the dependency information for programs that are created.  This
# allows us to ensure that test programs are rebuilt if we rebuild the 
# libraries
$project_libs = "";  # name of the libraries that are created by
                     # this project
$project_libdir = "";# name of the directory (may contain ROOTDIR) in which
                     # the libraries are created                    
#
# Perhaps a better approach is to provide
# <program>_DEPS = other program dependencies
# DEPSALL = dependencies for *all* programs

$make_depend = "gcc -MM";  # Set to command to create dependency list
$fixup_autoconf_cd = 0; # set to 1 to (partially) fixup configure for
                        # pathnames that contain blanks
$autoconf = "autoconf"; # Name of autoconf program to use
$autoconf_version = ""; # Require a specific version
$configure_has_config_headers = "no";
#
$quietmake = "@";       # set to "" for echo commands, @ to suppress them
#
# Defaults for building MPICH
$doc_heading = "MPI";
%doc_extra   = ();  # for kinds html, man, latex
#
$fixup_for_timestamps = 1; # make is broken
$SleepSlow = "sleep 1";
$SleepFast = "perl -e \'\$\$now=time;\$\$now-=10;utime \$\$now, \$\$now, \"LIB\";\'";
$Sleep = $SleepFast;
#
# Output File end-of-line character
$newline = "\n";

$create_configure_input = 1;  # Changes file.sm to file.in .  Set to 0
                              # for file.sm to file .
$smdir=$0;         # directory containing simplemake
if ($smdir =~/^[^\/]/) {
    $curpwd = $ENV{'PWD'};
    #chomp($curpwd = `pwd`);
    #print "curdir = $curpwd\n";
    #print "\$0 = $0\n";
    $smdir = $curpwd . "/$0";
}
$smdir =~ s/\/?simplemake$//;
#print "smdir = $smdir\n";

$debug = 0;                 # General debugging
$debug_confdir = 0;         # Track the directory containing the controlling
                            # configure.in
$quiet = 0;

%libdir = ();
#
# While simplemake doesn't support ext->other (e.g., .c to .s), 
# the rules have been added.
%extrules = ( 'c:o' => '$(C_COMPILE) -c $<', 
	      'f:o' => '$(F77_COMPILE) -c $<',
	      'cxx:o' => '$(CXX_COMPILE) -c $<',
	      'cpp:o' => '$(CXX_COMPILE) -c $<',
	      's:o' => '$(AS_COMPILE) $<',
	      'f90:o' => '$(F90_COMPILE) -c $<',
# Assembler *output* definitions
	      'c:s' => '$(C_COMPILE) -S $<',
	      'f:s' => '$(F77_COMPILE) -S $<',
# Program from source rules
	      'c:' => '$(C_COMPILE) -o $* $< $(LDFLAGS) $(LIBS)',
	      'f:' => '$(F77_COMPILE) -o $* $< $(LDFLAGS) $(LIBS)',
	      'f90:' => '$(F90_COMPILE) -o $* $< $(LDFLAGS) $(LIBS)',
              'cxx:' => '(CXX_COMPILE) -o $< $(LDFLAGS) $(LIBS)',
# LaTeX definitions
	      'tex:dvi' => 'latex $<',
	      'dvi:ps' => 'dvips $<',
	      'dvi:pdf' => 'dvipdfm $<',
# Shared object definitions	      
	      'c:lo' => '$(C_COMPILE_SHL) -c $<
	@mv -f $*.o $*.lo', 
	      'f:lo' => '$(F77_COMPILE_SHL) -c $<
	@mv -f $*.o $*.lo',
	      'cxx:lo' => '$(CXX_COMPILE_SHL) -c $<
	@mv -f $*.o $*.lo',
	      'cpp:lo' => '$(CXX_COMPILE_SHL) -c $<
	@mv -f $*.o $*.lo',
	      'f90:lo' => '$(F90_COMPILE_SHL) -c $<
	@mv -f $*.o $*.lo',
# This has an MPICH-specific definition that we should eventually generalize
              'c:pf' => '${C_COMPILE} -c -DMPICH_PROFILE_PMPI $< 
	@mv -f $*.o $*.pf'
	     );

# When we are building profiled versions, we use a separate ext rule
%extrules_with_profile = %extrules;
# PROFILE_DEF_MPI is set when needed to create the profiling libraries.
$extrules_with_profile{'c:o'} =~ s/-c/-c \@PROFILE_DEF_MPI\@/;
print "rule = $extrules_with_profile{'c:o'}\n" if $debug;

# Definitions for each extension (these are the defs needed for each ext->o
# extension)
%extdef = ( 'c:o'   => 'CC          = @CC@
CFLAGS      = @CFLAGS@
C_COMPILE   = $(CC) $(DEFS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS)',
	    'f:o'   => 'FC          = @FC@
FFLAGS      = @FFLAGS@
F77_COMPILE = $(FC) $(FFLAGS)',
	    'cxx:o' => 'CXX         = @CXX@
CXXFLAGS    = @CXXFLAGS@
CXX_COMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CXXFLAGS) $(CPPFLAGS)',
	    'cpp:o' => 'CXX         = @CXX@
CXXFLAGS    = @CXXFLAGS@
CXX_COMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CXXFLAGS) $(CPPFLAGS)',
	    's:o'   => 'AS          = @AS@
AS_COMPILE  = $(AS)',
	    'f90:o'   => 'F90          = @F90@
F90FLAGS    = @F90FLAGS@
F90_COMPILE = $(F90) $(F90FLAGS)',
# Similarly, but for shared-library versions
	    'c:lo'   => 'CC_SHL      = @CC_SHL@
C_COMPILE_SHL   = $(CC_SHL) $(DEFS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS)',
	    'f:lo'   => 'FC_SHL      = @FC_SHL@
F77_COMPILE_SHL = $(FC_SHL) $(FFLAGS)',
	    'cxx:lo' => 'CXX_SHL     = @CXX_SHL@
CXX_COMPILE_SHL = $(CXX_SHL) $(DEFS) $(INCLUDES) $(CXXFLAGS) $(CPPFLAGS)',
	    'cpp:lo' => 'CXX_SHL     = @CXX_SHL@
CXX_COMPILE_SHL = $(CXX_SHL) $(DEFS) $(INCLUDES) $(CXXFLAGS) $(CPPFLAGS)',
	   );
#
# Rules to build programs (.o:)
%progrules = ( 'c' => '$(C_LINK) $(LDFLAGS)',
	       'cxx' => '$(CXX_LINK) $(LDFLAGS)',
	       'cpp' => '$(CXX_LINK) $(LDFLAGS)',
	       'f'   => '$(F77_LINK) $(LDFLAGS)',
	      );
%progdefs = ( 'c' =>   'C_LINK      = $(CC)',
	      'cxx' => 'CXX_LINK    = $(CXX)',
	      'cpp' => 'CXX_LINK    = $(CXX)',
	      'f'   => 'F77_LINK    = $(FC)',
	     );

# Rules to build shared libraries (these are like programs
# Question: Do we want a common rule or separate rules for each language?
# These are out-of-date.
%shlibdefs = ( 'c' =>   'C_LINK_SHL      = @C_LINK_SHL@',
	       'cxx' => 'CXX_LINK_SHL    = @CXX_LINK_SHL@',
	       'cpp' => 'CXX_LINK_SHL    = @CXX_LINK_SHL@',
	       'f'   => 'F77_LINK_SHL    = @F77_LINK_SHL@',
	     );
%shlibrules = ( 'c' => '$(C_LINK_SHL) $(LDFLAGS)',
	       'cxx' => '$(CXX_LINK_SHL) $(LDFLAGS)',
	       'cpp' => '$(CXX_LINK_SHL) $(LDFLAGS)',
	       'f'   => '$(F77_LINK_SHL) $(LDFLAGS)',
	      );
#
# Directories needed.  These are the prefix etc.  Many are needed only
# at the top level, particularly for installation.  srcdir is needed only for
# VPATH builds
# We must build the srcdir and top_srcdir specially because autoconf
# insists on replacing this text.  The rest we had to do to allow the
# maint/configure to work under Cygwin
$srcdir_name =               'srcdir          = @' . "srcdir"      . '@';
$master_topsrcdir_name =     
               'master_top_srcdir  = @' . "master_top_srcdir"  . '@';
$topsrcdir_name =            'top_srcdir      = @' . "top_srcdir"  . '@';
$prefix_name =               'prefix          = @' . "prefix"      . '@'; 
$exec_prefix_name =          'exec_prefix     = @' . "exec_prefix" . '@';
$bindir_name =               'bindir          = @' . "bindir"      . '@';
$sbindir_name =              'sbindir         = @' . "sbindir"     . '@';
$libdir_name =               'libdir          = @' . "libdir"      . '@';
$includedir_name =           'includedir      = @' . "includedir"  . '@';
$mandir_name =               'mandir          = @' . "mandir"      . '@';
$htmldir_name =              'htmldir         = @' . "htmldir"     . '@';
$docdir_name =               'docdir          = @' . "docdir"      . '@';
$sysconfdir_name =           'sysconfdir      = @' . "sysconfdir"  . '@';

%dirdefs = ( 'srcdir'     => $srcdir_name,
	     'top_srcdir' => $topsrcdir_name,
	     'prefix'     => $prefix_name,
	     'exec_prefix'=> $exec_prefix_name,
	     'bindir'     => $bindir_name,
	     'sbindir'    => $sbindir_name,
	     'libdir'     => $libdir_name,
	     'includedir' => $includedir_name,
	     'master_top_srcdir' => $master_topsrcdir_name,
	     'mandir'     => $mandir_name,
	     'htmldir'    => $htmldir_name,
	     'docdir'     => $docdir_name,
	     'sysconfdir' => $sysconfdir_name,
	    );

#install_dir maps XXX from install_XXX into the GNU name
%install_dir = ( 'LIB' => 'libdir', 
		 'SHLIB' => 'libdir',     # SHLIB also signals library to build
		 'BIN' => 'bindir',
		 'INCLUDE' => 'includedir', 
		 'MAN' => 'mandir',
		 'HTML' => 'htmldir',
		 'DOC' => 'docdir',
		 'ETC' => 'sysconfdir',
		);
%install_methods = ( 'LIB'     => '$(INSTALL_DATA)',
		     'BIN'     => '$(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG)',
		     'SHLIB'   => '$(INSTALL_PROGRAM)',
		     'INCLUDE' => '$(INSTALL_DATA)',
		     'MAN'     => '$(INSTALL_DATA)',
		     'HTML'    => '$(INSTALL_DATA)',
		     'DOC'     => '$(INSTALL_DATA)',
		     'ETC'     => '$(INSTALL_DATA)',
		    );
# These give the directories that autoconf will require for the 
%required_dirs = ( 'libdir'      => 'exec_prefix prefix',
		   'bindir'      => 'exec_prefix prefix',
		   'mandir'      => 'prefix',
		   'htmldir'     => 'prefix',
		   'docdir'      => 'prefix',
		   'includedir'  => 'prefix',
 		   'exec_prefix' => 'prefix',
		   'sysconfdir'  => 'prefix',
		  );
# etc.
#
# Remember which document types we've seen
%globaldockind = ( "html" => 0, "man" => 0, "latex" => 0 );
# Set globaldocdir to the location to use if no specific directory is
# chosen.  It may contain ROOTDIR.
$globaldocdir  = 'ROOTDIR/$dockinddirval';
# Directories for documentation 
# These may be overridden how by setting docthiskinddir
%dockinddir = ( "html" => "www/www3", 
	        "man" => "man/man3", 
	        "latex" => "doc/refman" );
%docthiskinddir = ();
# man targets for documentation
%docTargetName = ( "html" => "htmldoc",
		   "man" => "mandoc",
		  "latex" => "latexdoc" );
# doctext name to produce documentation
%doctextOptionName = ( "html" => "-html",
		       "man" => "",
		      "latex" => "-latex" );
$docnamedefs   = "";
$doc_attop = 1;
#
# Rules
# (need a way to quote the rule here and unquote it when used)
#
# Need a way to substitute for additional or replacement default rules
# Other global data
$do_profilelibs   = 1; # Set to one if a profiling version of the library 
                       # should be created (required for MPI)
$found_profilelib = 0;

# Default values
$distcleanfiles = "";

@subdirs = ();
@doc_subdirs = ();
@keepargs = ();    # Used to recreate simplemake invocation for make target
foreach $_ (@ARGV) {
    $keepargs[$#keepargs+1] = $_;    # Add all args by default
    if (/-nocomments/) { $nocomments = 1; }
    elsif (/-v/) { $verbose = 1; }
    elsif (/-am/) { $am_a = "_a"; }
    elsif (/-libdir=([^=]*)=(.*)$/) {
	print "libdir{$1} = $2$newline" if (!$quiet);
	$libdir{$1}  = "$2/";
    }
    elsif (/-common=(.*)$/) {
	$filename = $1;
	open( CD,"<$filename" ) || die "Could not open $filename\n";
	while (<CD>) {
	    s/\r//g; # Strip \r for DOS
	    $commonmake .= $_;
	}
	close(CD);
	# Replace this argument with an updated version
	if ($filename =~ /^[^\/]/) {
  	    $keepargs[$#keepargs] = "-common=$curpwd/$filename";
	}
    }
    elsif (/-autoconf=(.*)$/) {
	$autoconf_args = $1;
    }
    elsif (/-include=(.*)$/) {
	$include_list = $1;
    }
    elsif (/-distrib/) {
	# Turn off the maintenance targets in the distribution version
	$maint_targets = 0;
	$do_doc = 0;
	# Use the robust sleep, not the fast perl version
	$Sleep = $SleepSlow;
    }
    elsif (/-dos/) {
	$newline = "\r\n";
    }
    elsif (/-shared/) {
	$do_sharedlibs = 1;
    }
    elsif (/-noshared/) {
	$do_sharedlibs = 0;
    }
    elsif (/-docs/) {
	$do_docs = 1;
    }
    elsif (/-nodocs/) {
	$do_docs = 0;
    }
    elsif (/-vpath=?(.*)/) {
	$val = $1;
	if ($val eq "no") { $vpath_config = 0; } 
	else { $vpath_config = 1; }
    }
    elsif (/-depend=static/) {
	$do_dependencies = "static";
    }
    elsif (/-depend/) {
	$do_dependencies = "dynamic";
    }
    elsif (/-nodepend/) {
	$do_dependencies = "no";
    }
    elsif (/-rootdir=(.*)$/) {
        $rootdirpath = $1;
	$#keepargs--;  # remove this entry (it is explicitly recreated)
    }
    elsif (/-distcleanfiles=(.*)/) {
	# extra files to remove in this directory
	$distcleanfiles = $1;
    }
    elsif (/-debug/) {
	$debug = 1;
    }
    elsif (/-quietmake/) { $quietmake = "@"; }
    elsif (/-noquietmake/) { $quietmake = ""; }
    elsif (/-quiet/) { $quiet = 1; }
    elsif (/-docheading=(.$)/) { $doc_heading = $1; }
    elsif (/-docdestdir=(.*)/) { $globaldocdir = $1; }	   
    elsif (/-docnamedefs=(.*)/) { $doc_namedefs = $1; }	   
    elsif (/-help/) {
	&printHelp;
	exit 0;
    }
    else {
	$#keepargs--;  # Remove filename from list
	&ProcessFile ( $_ );
    }
}


# Check that gcc is available if we need it
if ($do_dependencies eq "static") {
    if ($make_depend eq "gcc -MM") { 
	# This was | 2>&1 but the redirect should go before the pipe.
	if (open (TFD, "gcc --version 2>&1 |" )) {
	    close TFD;
	}
	else {
	    $do_dependencies = "no";
	}
    }
    # insert check here.  Perhaps we should try #include <stdio.h>?
}

# Routines
# Strip \n or \r\n from the end of a string
#sub strip (\@@);
sub strip {
#    my $aref = @_;
#    foreach (@$aref) { s/[\r,\n]*$//; }
    for(@_)
    {
        s/\W*$//;
    }
}

# Try this one soon:
# sub strip_newline {
#   my $line = $_[0];
#   $line =~ s/\r\n$//;
#   return $line;
#}

# =========================================================================
# Read Makefile.sm
sub ReadMfile {
    $Mfile = $_[0];
    open (MFILE,"<$Mfile" ) || die "Could not open $Mfile\n";
    &ClearVars;
    while (<MFILE>) {
	s/\r//g;              # Remove \r for DOS
	$origline = $_;
	# Remove trailing newline (we had trouble with chomp on DOS)
        #chomp;
        s/[\r\n]*$//;

        # Handle continuation lines
        while (s/\\$//) {  # Match and remove a trailing \
	    $nextline = <MFILE>;
	    $nextline =~ s/\r//g; # Remove \r for DOS
	    $origline .= $nextline;
	    #chomp $nextline;
	    $nextline =~ s/[\r\n]*$//; 
            $_ .= $nextline;
        }

        # Look for reserved forms:
        #lib([\w-]*)_SOURCES = names
        #lib([\w-]*)_DIR = name
        #SUBDIRS = names
        #DOC_SUBDIRS = names
	#DOCDESTDIRS = kind:dir [, kind:dir ]*
	# Also keep track of Makefile usages:
	#target: ...
	#variable = value
	#.SUFFIXES:value
	# Using the _a_ in the library lines is necessary to distinguish
	# between libraries and programs that start with lib...
        if (/^lib([@\${}\(\)\w-]*)_a_SOURCES\s*=\s*(.*)$/) {
            $libname = "$1";
            $libsource = $2;
            $libraries{ $libname } = $libsource;
	    # Add to targets
	    $libloc = &GetLibLoc( $libname );
	    $alltargets[$#alltargets+1] = "${libloc}lib$libname.a";
	    # Shared libraries should not be built unconditionally.  
	    # Instead of adding them to the alltargets, add them
	    # to a allshlibtargets
	    if ($do_sharedlibs) {
	    	$allshlibtargets[$#allshlibtargets+1] = 
		    "${libloc}lib$libname.la";
	    }
	    # Keep track of source types
	    &FindSrcTypes( $libsource );
	    # Keep track of source files
	    &SaveSrcNames( $libsource );
        }
	# Using the _so_ in the library lines is necessary to distinguish
	# between libraries and programs that start with lib...
        # This target is used for libraries that are *always* needed
	# as shared libraries (e.g., they are used only in a dynamic
	# link context).  No _so_DIR for these yet because stand-alone
	# shared libraries are usually contained within a single
	# directory.
        elsif (/^lib([@\${}\(\)\w-]*)_so_SOURCES\s*=\s*(.*)$/) {
	    $found_sharedlib = 1;
            $libname = "$1";
            $libsource = $2;
            $shared_libraries{ $libname } = $libsource;
	    # Add to targets
	    $libloc = &GetLibLoc( $libname );
	    $allshlibtargets[$#allshlibtargets+1] = "${libloc}lib$libname.so";
	    # Keep track of source types
	    &FindSrcTypes( $libsource );
	    # Keep track of source files
	    &SaveSrcNames( $libsource );
	    # We need to include .lo as a necessary suffix.
        }
        elsif (/^lib([@\${}\(\)\w-]*)_a_DIR\s*=\s*(.*)\s*$/) {
	    # This is an extension over automake.  It makes it easy
	    # to modify a library in a different directory
	    # Add a trailing / because this way we can unconditionally
	    # specify the library directory
	    print "Setting libdir{$1} to $2/\n";
            $libdir{$1}  = "$2/";
        }
	elsif (/^doc_([\w-]*)_SOURCES\s*=\s*(.*)\s*$/) {
	    # Lowercase the type
	    $docsrc{lc($1)} = $2;
	    $globaldockind{lc($1)} = 1;
	    # Add any autoconf dir in $doc_namedefs
	    &LookForAutoconfDirs( $doc_namedefs );
	}
	elsif (/^doc_([\w-]*)_DIR\s*=\s*(.*)\s*$/) {
	    # Lowercase the type
	    $docdir{lc($1)} = $2;
	}
	elsif (/^profilelib_([@\${}\(\)\w-]*)\s*=\s*(.*)\s*$/) {
	    # proflib_<oldname> = <newname>
	    $profile_libraries{$1} = $2;
	    $found_profilelib = 1;
	}
	elsif (/^install_([\w-]*)\s*=\s*(.*)\s*$/) {
	    $install_files{$1} .= "$2 ";
	}
	elsif (/^optinstall_([\w-]*)\s*=\s*(.*)\s*$/) {
	    # This is for files that will be installed only if present
	    $optinstall_files{$1} .= "$2 ";
	}
        elsif (/^SUBDIRS\s*=\s*(.*)\s*\r?$/) {
	    # The \r is used to remove any \r in DOS-style files
            @subdirs = split(/\s+/,$1);
	    $subdirs_has_autoconf = 0;
        }
        elsif (/^DOC_SUBDIRS\s*=\s*(.*)\s*\r?$/) {
	    # The \r is used to remove any \r in DOS-style files
            @doc_subdirs = split(/\s+/,$1);
        }
	elsif (/^DOCDESTDIRS\s*=\s*(.*)\s*\r?$/) {
	# kind:dir [, kind:dir ]*
	    for $pair (split(/,\s*/,$1)) {
		$pair =~ /(.*):(.*)/;
		$docthiskinddir{$1} = $2;
	    }
        }
	elsif (/^INSTALL_SUBDIRS\s*=\s*(.*)\s*\r?$/) {
	    @install_subdirs = split(/\s+/,$1);
	}
        elsif (/^EXTRA_PROGRAMS\s*=\s*(.*)\s*$/) {
	    foreach $program (split(/\s+/,$1)) {
		$extra_programs{$program} = 1;
	    }
	}
	elsif (/^EXTRA_DIRS\s*=\s*(.*)\s*$/) {
	    @extra_dirs = split( /\s+/,$1);
	}
	elsif (/^OTHER_DIRS\s*=\s*(.*)\s*$/) {
	    @other_dirs = split( /\s+/,$1);
	}
	elsif (/^EXTERNAL_LIBS\s*=\s*(.*)\s*$/) {
	    foreach $lib (split(/\s+/,$1)) {
		$external_libraries{$lib} = 1;
	    }
	}
	elsif ($nocomments && /^\s*#/) {
	       ;
	   }
	elsif (/^smvar_([^\s]*)\s*=\s*(.*)/) {
	    # Allow the user to override any simplemake variable 
	    # E.g.,
	    # smvar_autoconf = /foo/bar/fixedac
	    # causes simplemake to replace "autoconf" with "/foo/bar/fixedac"
	    $varname = $1;
	    $value   = $2;
	    # Save old values
	    $simplemake_vars{$varname} = $$varname;
	    $$varname = $value;
	    print STDERR "setting $varname to $value\n" if $debug;
	}
	elsif (/^noinst/) {
	    # Automake target to identify some programs/libraries as
	    # not to be installed.
	    # Skip for now
	    ;
	}
	elsif (/^([\w-]*)_SOURCES\s*=\s*(.*)\s*$/) {
	    # programs
	    $pgm = $1;
	    $pgmsrc = $2;
	    $programs{$pgm} = $pgmsrc;
	    # Add to targets
	    $alltargets[$#alltargets+1] = $pgm;
	    # Keep track of source types
	    &FindSrcTypes( $pgmsrc );
	    # Keep track of source files
	    &SaveSrcNames( $pgmsrc );
	    # Find program source type
	    $pgmsrctype{$pgm} = &FindPgmSrcType( $pgm, $pgmsrc );
	}
	elsif (/^([\w-]*)_LDADD\s*=\s*(.*)\s*$/) {
	    $pgm_ldadd{$1} = $2;
	}
	elsif (/^LDADD\s*=\s*(.*)\s*$/) {
	    $ldadd_all = $1;
	}
	elsif (/^([\w-]*)_DEPADD\s*=\s*(.*)\s*$/) {
	    $pgm_depadd{$1} = $2;
	}
	elsif (/^DEPADD\s*=\s*(.*)\s*$/) {
	    $depadd_all = $1;
	}
	elsif (/^([\w-]*)\s*=\s*(.*)\s*$/) {
	    $other_vars .= "$origline";
	    # Save all variable names
	    $makevars{$1} = $2;
	    # Look for special autoconf directory names
	    &LookForAutoconfDirs( $_ );
	}
	elsif (/^([^:\s]*)\s*:(.*)$/) {
	    # Remember user-defined targets.
	    $usertargets{$1} = $_;
	    $other_text .= "$origline";
	    # We could copy lines until we saw a blank line
	    if ($1 eq ".SUFFIXES") { $ExplicitSuffixes .= $2; }
	    # Look for special autoconf directory names
	    &LookForAutoconfDirs( $_ );
	    &LookForSuffixes( $_ );
	}
	else {
	    $other_text .= "$origline";
	    # Look for special autoconf directory names
	    if (!/^\s*#/) {
	        &LookForAutoconfDirs( $_ );
	    }
	}
    $origline = "";
    }
}

sub WriteMfile {
    $maxline = 80;
    $output_filename = $_[0];
    # Write out the generated Makefile
    unlink $output_filename;
    open( FD, ">$output_filename" ) || die "Could not open $output_filename\n";

    print FD "# This $output_filename created by simplemake.  Do not edit$newline$newline";
    if ($output_filename =~ /Makefile\.in/) {
	print FD "# \@configure_input\@$newline";
    }
    # Ensure that the default target takes us to "all"
    print FD "all: all-redirect$newline$newline";
    if ($useinclude) {
        print FD "SHELL = \@SHELL\@$newline";
        print FD "include $includedir/$makefilebase$newline";
    }
    else {
	# We may want to break DefaultRules into a pre and post version
        &DefaultRules;
    }
    
    # Other variables
    &VariableDocs;

    # Print out variables before generated targets
    print FD $other_vars;
    print FD "$newline";

    # Generate the all-redirect: target (libraries, programs, and 
    # anything specified by all-local)
    &TargetAll;

    # Output the generated targets.  First, the libraries
    &TargetLibraries;
    if ($do_sharedlibs) {
	&TargetSharedLibraries( \%libraries );
	if (defined($optinstall_files{'SHLIB'})) {
	    foreach $libspec (split(/\s+/,$optinstall_files{'SHLIB'})) {
		$libspec =~ /(.*)\/([^\/]*)/;
		$libdir = $1;
		$libname = $2;
		$libsrc = $libname;
		$libsrc =~ s/\.so/\.la/;
		&TargetSharedLibraryFinal( $libsrc, $libname, $libdir );
	    }
	}
    }
    if (%shared_libraries) {
	# If any shared libraries were requested...
	&TargetSharedLibraries( \%shared_libraries );
	foreach $libname (keys(%shared_libraries)) {
	    &TargetSharedLibraryFinal( "lib$libname.la", "lib$libname.so", "." );
	}
    }
    if ($do_profilelibs && $found_profilelib) {
	&print_make_endline( FD );
	&print_make_line( FD, "@" . "NO_WEAK_SYM_TARGET\@:" );
	foreach $lib (keys(%profile_libraries)) {
	    $libloc = &GetLibLoc( $lib );
	    $proflib_name = $profile_libraries{$lib};
	    print_make_line( FD, " ${libloc}lib$proflib_name.a" );
	}
	print_make_endline( FD );
	&TargetProfileLibraries;
    }

    # Coverage analysis
    &TargetGcov;

    # Next, the programs
    &TargetPrograms;

    # Documentation
    if ($maint_targets) {
	&TargetDocs;
    }

    &TargetInstall;

    # This is ugly, but we need to tell the install target when we're at
    # the top for the documentation.  This should be promoted to 
    # a more general sense of "at the top" for all areas.
    $doc_attop = 0;

    if ($do_dependencies ne "no") {
	if ($do_dependencies eq "static") {
	    &TargetDependenciesStatic;
	}
	elsif ($do_dependencies eq "ignore") {
	    # Add a null target so that recursive targets work
	    print FD "dependencies:$newline";
	}
	else {
	    &TargetDependenciesDynamic;
	}
    }

    # Tags
    &TargetTags;

    # Unrecognized lines go here
    print FD $other_text;
    close FD;

    # Make the file read only
    # ($dev,$ino,$mode) = stat $output_filename
    # Modifiy $mode to remove write permissions
    # use chmod $mode $output_filename
    # to change permissions

    # If the user overrode any variables, restore them here
    foreach $varname (keys(%simplemake_vars)) {
	print STDERR "Restoring $varname to $simplemake_vars{$varname}\n" if $debug;
	$$varname = $simplemake_vars{$varname}
    }
}

#
# ===========================================================================
# Output files may contain either a set of default rules, written by this
# routine, or an include of a set of base rules.
#
sub DefaultRules {
    # SHELL must be in uppercase for Make to use it as the shell to
    # execute commands with.
    print FD "SHELL           = \@SHELL\@$newline";

    # Library definitions
    if (scalar(%libraries)) {
	# Add ar, ranlib definitions if there are any library targets.
        print FD "AR              = \@AR\@$newline";
	print FD "RANLIB          = \@RANLIB\@$newline";
# Replace this with a block to create the actual shared library (.so), 
# not just the archive of sharable objects (.la)	
# 	if ($do_sharedlibs) {
# 	    foreach $ext (keys(%ext_seen)) {
# 		if (defined($shlibdefs{$ext})) {
# 		    print FD "$shlibdefs{$ext}$newline";
# 		}
# 	    }
# 	}
    }
    $out_mkdir_p = 0;
    if ($do_sharedlibs) {
	if (defined($optinstall_files{'SHLIB'})) {
	    print FD "$shlibdefs{'c'}$newline";
	}
	elsif ($found_sharedlib) {
	    # No install target, but a shared library is begin built
	    print FD "$shlibdefs{'c'}$newline";
	    $out_mkdir_p = 1;
	    print FD "MKDIR_P         = \@MKDIR_P\@$newline";
	}
    }

    if (scalar(%install_files)) { 
	print FD "INSTALL         = \@INSTALL\@$newline";
	print FD "INSTALL_PROGRAM = \@INSTALL_PROGRAM\@$newline";
	print FD "INSTALL_DATA    = \@INSTALL_DATA\@$newline";
	if (! $out_mkdir_p) {
	    print FD "MKDIR_P         = \@MKDIR_P\@$newline";
	}
    }

    # Directory definitions
    %dir_added = ();
    foreach $dir (keys(%dirs_seen)) {
	if (!defined($dir_added{$rdir})) {
	    print FD "$dirdefs{$dir}$newline";
	    $dir_added{$dir} = 1;
	    foreach $rdir (split(/\s+/,$required_dirs{$dir})) {
		if (!defined($dir_added{$rdir})) {
		    print FD "$dirdefs{$rdir}$newline";
		    $dir_added{$rdir} = 1;
		}
	    }
	}
    }
    if (scalar(%install_files)) {
	$dir_added{'prefix'} = 1;
	print FD "$dirdefs{'prefix'}$newline";
    }
    foreach $dir (keys(%install_files)) {
	# Handle the derived dirs for the install directories
	$dir = $install_dir{$dir};
	foreach $rdir (split(/\s+/,$required_dirs{$dir})) {
	    if (!defined($dir_added{$rdir})) {
		print FD "$dirdefs{$rdir}$newline";
		$dir_added{$rdir} = 1;
	    }
	}
    }
    foreach $dir (keys(%install_files)) {
	$dir = $install_dir{$dir};
	$resultdir = $dirdefs{$dir};
	print FD "$dirdefs{$dir}$newline";
    }

    &InstallDocDirs;

    # Miscellaneous.  This needs to be improved.  This is really needed
    # only for some targets
    # The definition of DEFS is the same as for Automake
    if (defined($ext_seen{"c"}) || defined($ext_seen{"cxx"}) ||
	defined($ext_seen{"cpp"})) {
	print FD "DEFS        = \@DEFS\@ -I. -I\${srcdir}$newline";
	# What to do about includes?  If they were set explicitly,
	# don't use the default.
	if (!defined($makevars{"INCLUDES"})) {
	    print FD "INCLUDES        = $include_list$newline";
        }
	print FD "CPPFLAGS        = \@CPPFLAGS\@$newline";
    }
    # Add the LIBS if there are any programs to build
    if (scalar(%pgmlinktypes)) {
	print FD "LIBS            = \@LIBS\@$newline";
    }

    # If there are subdirs, we need make
    if (($#subdirs >= 0 || $#doc_subdirs >= 0) && 
	! defined($makevars{"MAKE"})) {
	print FD "MAKE            = \@MAKE\@$newline";
    }

    # Add any standard definitions
    if ($commonmake ne "") {
	print FD "$commonmake$newline";
    }

    # Definitions for each possible program type seen
    $any_prog_def = 0;
    foreach $ext (keys(%ext_seen)) {
	print "ext seen is :$ext:\n" if $debug;
	$extkey = "$ext:o";
	if (defined($extdef{$extkey})) {
	    print FD "$extdef{$extkey}$newline";
	}
	if (defined($pgmlinktypes{$ext})) {
	    print FD "$progdefs{$ext}$newline";
	    $any_prog_def = 1;
	}
	if ($do_sharedlibs || $found_sharedlib) {
	    $extkey = "$ext:lo";
	    print FD "$extdef{$extkey}$newline";
	}
    }
    if ($any_prog_def) {
	# These are special definitions that are shared by all 
	# pgmlink types
	print FD "LDFLAGS     = \@LDFLAGS\@ $ldadd_all$newline";
    }
    print FD "$newline";
#    foreach $ext (keys(%pgmlinktypes)) {
#    }

    if ($vpath_config) {
        print FD '@VPATH@'; print FD "$newline";
    }
    else {
        print FD 'VPATH = .:${srcdir}'; print FD "$newline";
    }

    # Add the compilation rules.  Include only those needed for the
    # given files.  Remove all default suffix rules
    if (scalar(%ext_seen)) {
	$suffixes = ".o";
	if ($do_sharedlibs || $found_sharedlib) { 
	    $suffixes .= " .lo";
	}
	if ($do_profilelibs && $found_profilelib) {
	    $suffixes .= " .pf";
	}
    }
    foreach $ext (keys(%ext_seen)) {
	$suffixes .= " .$ext";
    }
    
    # Finally, update suffixes from any other source.  Currently, this
    # handles the suffixes for document generation.
    &SuffixDocs;

    print FD ".SUFFIXES:$newline";
    # Grrr.
    # OSF1 make complains if there are no suffix items.  To make it happy,
    # *always* add .o .c
    if ("$suffixes $ExplicitSuffixes" ne " ") {
	print FD ".SUFFIXES: $suffixes $ExplicitSuffixes$newline";
    }
    else { 
	print FD "# Some make programs complain if no suffixes are set$newline";
	print FD ".SUFFIXES: .c .o$newline";
    }

    # To make it easier to build programs, conditionally add a 
    # default "build program" rule from the seen sourcecode extensions
    foreach $ext (keys(%ext_seen)) {
	print FD ".$ext.o:$newline";
	if ($found_profilelib) {
	    # Use a special rule when building the non-profile-lib version
	    $extkey = "$ext:o";
	    print FD "\t$extrules_with_profile{$extkey}$newline";
	}
	else {
	    $extkey = "$ext:o";
	    print FD "\t$extrules{$extkey}$newline";
	}
	if ($do_sharedlibs || $found_sharedlib) {
	    $extkey = "$ext:lo";
	    print FD ".$ext.lo:$newline";
	    print FD "\t$extrules{$extkey}$newline";
	}
	if ($found_profilelib && $ext eq "c" && $do_profilelibs) {
	    $extkey = "$ext:pf";
	    print FD ".c.pf:$newline";
	    print FD "\t$extrules{$extkey}$newline";
	}
	$extkey = "$ext:";
	# We may want to make this conditional, only generating it
	# when desired.
	if (defined($extrules{$extkey})) {
	    print FD ".$extkey$newline";
	    print FD "\t$extrules{$extkey}$newline";
	}
    }
    
    # Other generic rules.  Currently, only for documents
    &RuleDocs;

    # Configure update targets
    if ( -s "configure.in" && $maint_targets ) {
	# Convert ROOTDIR as necessary
	$aargs = $autoconf_args;
	if ($rootdirpath eq "") {
	    $aargs =~ s/ROOTDIR/\./;
	}
	else {
	    #chomp( $rootdir =  $rootdirpath );
	    ( $rootdir =  $rootdirpath ) =~ s/[\r\n]*$//; # David added
		#strip( $rootdir = $rootdirpath );
	    $aargs =~ s/ROOTDIR/$rootdir/;
	}
	$aargs =~ s/\/\//\//;
	$autoconf_deps="";
	print "macro loc arg is $aargs\n" if $debug_confdir;
	# If there is a -l dir in the autoconf_args, then add that to the
	# dependencies (We use $acincdir_arg incase autoconf 2.57 is used,
	# in which case the argument is -I or -B, or in case autoconf 2.58
	# or later is used, in which case the argument may be changed again.
	if ($aargs =~ /$acincdir_arg\s*([\.\/\w]*)/) {
	    $macroloc = $1;
	    # HACK.  If we've messed up the location, don't include it
	    if (-s "$macroloc/aclocal.m4") {
		$autoconf_deps .= "$macroloc/aclocal.m4";
		# Extract includes from aclocal.m4
		open (AFD, "<$macroloc/aclocal.m4" );
		while (<AFD>) {
		    if (/^\s*builtin\(include,([\w-]*\.m4)\)\s*$/) {
			$filename = "$macroloc/$1";
			$autoconf_deps .= " $filename";
		    }
		}
		close (AFD);
	    }
	}
	print FD "$newline";
	&print_make_longline( FD,  "\${srcdir}/configure: \${srcdir}/configure.in $autoconf_deps" );
	&print_make_setpos( 8 );
	&FindWorkingAutoconf ;
	# Use autoheader only if AC_CONFIG_HEADER is in the configure file
	# 
	# With Autoconf 2.57, there is a "cache" that like all automake
	# caches, isn't reliable and must be removed 
	&print_make_longline( FD, "\t\@if [ -d autom4te.cache ] ; then rm -rf autom4te.cache ; fi$newline" );
	if ($configure_has_config_headers ne "no") {
	    &print_make_longline( FD,  "\t(cd \${srcdir} && $autoheader_prog $aargs && \\$newline\t$autoconf $aargs )" );
	}
	else {
	    &print_make_longline( FD,  "\t(cd \${srcdir} && $autoconf $aargs )" );
	}
	if ($fixup_autoconf_cd) {
	    # This is needed for DOS in case the pwd contains blanks
	    print FD "\t( cd \${srcdir} && sed -e 's/cd *\$\$ac_popdir/cd \"\$\$ac_popdir\"/g' configure > c.tmp ; mv -f c.tmp configure ; chmod a+x configure)$newline";
	}
    }
    if ($maint_targets && "$smdir" ne "") {
	print FD "$newline";
	print FD "\${srcdir}/Makefile.in: \${srcdir}/Makefile.sm$newline";
	print FD "\t( cd \${srcdir} && $smdir/simplemake -rootdir=$rootdir \\$newline";
	foreach $curarg (@keepargs) {
	    # Must handle $ specially
	    $tmparg = $curarg;
	    $tmparg =~ s/\$/\\\$\$/;
	    if ($tmparg =~ /\s/) {
		print FD "\t\"$tmparg\" \\$newline";
	    }
	    else {
		print FD "\t$tmparg \\$newline";
	    }
	}
	if (defined($autoconf_files_by_dir{$lcurdir})) {
	    print FD "\t-distcleanfiles=\"$autoconf_files_by_dir{$lcurdir}\" \\$newline";
	}
	print FD "\t\tMakefile.sm )$newline";
	print FD "Makefile: \${srcdir}/Makefile.in$newline";

	# The following does not always work correctly.  There may be 
	# problem in handling jumps between directories
	my $topdir = &GetPathToParent( $curdir, $last_config_dir );
 	print "last config dir = $last_config_dir, topdir = $topdir\n" if $debug_confdir;
 	if ($topdir eq "") {	
 	    $topdir = ".";
 	}		

	# We need to use the enclosing configure, not always the top-level
	# configure.  Thus, we need to keep track of the directory of the
	# current configure, and the path to get to that configure.
	# We also allow this step to fail; for example, the 
	# config.status may already have been removed.
	# Further, to make the clean step cleaner, we test for the 
	# config.status file before trying to run it (using a simple
	# test -x config.status && ... works, but still generates noise
	# about ignoring a failing step.

	$ignore_step = "-";
	if ($topdir ne ".") {
	    print FD "\t-cd $topdir && \\$newline";
	    $ignore_step = "";
	}
	$relcurdir = $curdir;
	$relcurdir =~ s/^$last_config_dir//;
	print FD "\t${ignore_step}if [ -x config.status ] ; then CONFIG_FILES=${relcurdir}Makefile CONFIG_HEADERS= \${SHELL} ./config.status ; fi$newline";
    }
    # Clean targets
    &TargetClean;
}

#
# ===========================================================================
#
# Look at a list of source files and determine the source types
#
# Eventually, make this $ext_seen{$extension} = 1, 
# then generate code by using keys(%ext_seen).  Allows general
# extensions and simpler handling of rules (like adding .F and .f90 )
sub FindSrcTypes {
    $source = $_[0];
    $files = "";
    foreach $sym (split(/\s+/,$source)) {
	print STDERR "Is $sym a make variable?\n" if $debug;
	$vsym = $sym;
	if ($vsym =~ /\$[\{\(]?([A-Za-z0-9_]*)[\}\)]?/) {
	    $vsym = $1;
	}
	if (defined($makevars{$vsym})) {
	    print STDERR "yes, value is $makevars{$vsym}\n" if $debug;
	    $files .= " $makevars{$vsym}";
	}
	else {
	    $files .= " $sym";
	}
    }
    foreach $file (split(/\s+/,$files)) {
	($name,$ext) = split('\.',$file);
	if (defined($ext) && $ext ne "") {
	    $ext_seen{$ext} = 1;
	}
    }
}

# Save all conventional sources
# This is only approximate.
# We want to allow source files to be specified through other 
# variables (e.g., ${Foo_sources}).
sub SaveSrcNames {
    $source = $_[0];
    foreach $file (split(/\s+/,$source)) {
	($name,$ext) = split( '\.',$file);
	if (defined($ext)) {
	    if (defined($extrules{"$ext:o"})) {
		$regular_sources .= " $file";
		$sources{$file} = 1;
	    }
	    elsif ($ext eq "h") {
		$regular_headers .= " $file";
	    }
	}
    }
}

#
# Find the name of the source file that matches the program.
# If none found, use c as the type
sub FindPgmSrcType {
    $pgm = $_[0];
    $pgmsrc = $_[1];
    foreach $file (split(/\s+/,$pgmsrc)) {
	($name,$ext) = split('\.',$file);
	if ($name eq $pgm) {
	    $pgmlinktypes{$ext} = 1;
	    return $ext;
	}
    }
    return "c";
}

sub ClearVars {
    # Extensions seen is a property of the makefile
    %ext_seen = ();
    %dirs_seen = ( "srcdir" => 1 );
    $other_vars = "";
    $other_text = "";
    $regular_sources = "";
    $header_sources = "";
    $regular_headers = "";
    %sources = ();
    # Targets
    @alltargets = ();   # implicit targets 
    @allshlibtargets = (); # implicit shared library targets
    %usertargets = ();  # explicit, user-defined targets
    %extra_programs = ();
    %libraries = ();
    %shared_libraries = ();
    %profile_libraries = ();
    %install_files = ();
    @install_subdirs = ();
    %optinstall_files = ();
    %external_libraries = ();
    $found_profilelib = 0;
    $found_sharedlib  = 0;
    %programs = ();
    %pgm_ldadd = ();
    $ldadd_all = "";
    %pgm_depadd = ();
    $depadd_all = "";
    # Variables
    %makevars = ();
    # Information about program targets
    %pgmlinktypes = ();
    # Other directories
    @subdirs = ();
    @doc_subdirs = ();
    %docthiskinddir = ();
    @extra_dirs = ();
    @other_dirs = ();
    $subdirs_has_autoconf = 0;
    # Suffix definitions
    $ExplicitSuffixes = "";
    # Document sources and directories
    %docdir = ();
    %docsrc = ();
    # These may be overriden on a file by file basis
    $autoconf = $autoconf_prog; # Name of autoconf program to use
    $autoconf_version = ""; # Any version is allowed
    # We cannot clear config_headers here because we may still
    # need to know that the configure in the current directory
    # has a header file, and this routine to clear vars is called for
    # every file.
    #$configure_has_config_headers = "no";
    %simplemake_vars = ();
}	

#
# Expand all of the make variables in an expression.  This
# lets users use targets like
# libmpich_SOURCE = ${MPI_SOURCES}
sub ExpandMakeVars {
    # look for ${\w*} and replace with the value of $makevars{$1}
    $_ = $_[0];
    print "Looking at $_\n" if $debug;
    while (/\${(\w*)}/) {
	print "replacing $1\n" if $debug;
	$mvar = $1;
	s/\${$mvar}/$makevars{$mvar}/g;
    }
    print "expanded to $_\n" if $debug;
    $_;
}

#
# ===========================================================================
@config_dir = ();    # Stack of the location of the most recently seen
                     # configure script.  Used to create targets that
                     # need to run config.status from that directory.

$last_config_dir = "";

# These next two routines let us print out the file being processed only
# when we need to (e.g., before an error message).
$curFilename = "";
$curFilenamePrinted = 0;
sub ResetFileName { 
    $curFilename = $_[0];
    $curFilenamePrinted = 0;
}
sub ShowFileName {
    if ($curFilenamePrinted) { return; }
    print "Processing $curdir$file\n" if (!$quiet);
    $curFilenamePrinted = 1;
}

sub ProcessFile {
    $file = $_[0];

    &ResetFileName( "$curdir$file" );
    #print "Processing $curdir$file\n" if (!$quiet);
    $configure_has_config_headers = "no";
    if (-s "configure.in") {
	&ReadAutoconf;
	print "Found configure.in in $curdir\n" if $debug_confdir;
	$last_config_dir = $curdir;
    }
    &ReadMfile( $file );
    $output_name = $file;
    if ($create_configure_input) {
	$output_name =~ s/\.sm$/.in/;
    }
    &WriteMfile( $output_name );
    
    #&checkForTargets();

    my @dirs = (@subdirs,@other_dirs,@doc_subdirs);
    # First, check for names that are replaced by autoconf (e.g., @name@)
    my @actdirs = ();
    foreach my $dir (@dirs) {
	$sdir = $dir;
	#print "Checking $sdir\n";
	if ($sdir =~ /@([^@]*)@/) {
	    $subst_name = $1;
	    $subdirs_has_autoconf = 1;
	    #print "Found $subst_name\n";
	    # Look up the special name
	    $var_name = "SUBDIRS_$subst_name";
	    #print "varname is $var_name\n";
	    if (defined( $makevars{$var_name} )) {
		# Concatenate the value of the variable name to the list
		# of directories
		@actdirs = ( @actdirs, split( /\s+/, $makevars{$var_name} ) );
	    }
	}
	else {
            $actdirs[$#actdirs+1] = $dir;
        }
    }
    M: foreach my $dir (@actdirs) {
	if ($dir eq ".") { next M; }
	if ($dir =~ /\.\./ || $dir =~ /.\/./) {
	    # Skip directory changes that aren't simple
	    &ShowFileName;
	    print "$dir has .. in it (skipping)\n";
	    print "Current dir is $curdir\n" if $debug;
	    next M;
	    #exit(1);
	}
	if (! -d $dir) { 
	    my $ldir = `pwd`;
	    &ShowFileName;
	    print "Directory $curdir$dir does not exist\n"; 
	    print "(Current location is $ldir)\n";
	    next M; }
	if (! -s "$dir/$file") { print "File $curdir$dir/$file does not exist\n"; next M; }
	chdir $dir;
	$curdir .= "$dir/";
	$curdir = &CleanCurDir( $curdir );
	if ($dir =~ /\.\./) {
	    &ShowFileName;
	    print "changed to a non-obvious dir = $dir\n";
	    my $ldir = $dir;
	    while ($ldir =~ /^\.\.\//) {
		$rootdirpath =~ s/\.\.\/$//;
		$ldir =~ s/^\.\.\///;
	    }
	    while ($ldir =~ /^[^\/]+\//) {
		$rootdirpath .= "../";
		$ldir =~ s/^[^\/]+\///;
	    }
	    if ($ldir =~ /[^\s]+/) {
		$rootdirpath .= "../";
	    }		
	}
	else {
	    $rootdirpath .= "../";
	}
	print "rootdir = $rootdirpath\n" if $debug_confdir;
	print "curdir = $curdir\n" if $debug_confdir;
	$config_dir[$#config_dir+1] = $last_config_dir; 
	print "config stack has depth $#config_dir\n" if $debug_confdir;
	print "relative path to configure dir is " . &GetPathToParent( $curdir, $last_config_dir ) . "\n" if $debug_confdir;
	&ProcessFile( $file );
	$last_config_dir = $config_dir[$#config_dir-1]; $#config_dir--;
	print "after processing, last_config_dir = $last_config_dir\n" if $debug_confdir;
	print "config stack has depth $#config_dir\n" if $debug_confdir;
	$rootdirpath =~ s/\.\.\/$//;
	chdir "..";
	$curdir =~ s/[^\/]*\/$//;
	$curdir = &CleanCurDir( $curdir );
    }
}

sub ListTargets {
  T: foreach $target (@alltargets) {
      # Skip the extra programs
      if (defined($extra_programs{$target})) { next T; }
      print_make_line( FD,  " $target" );
  }
    if ($found_profilelib) { 
	# Add the special configure name that is used for building extra
	# code when weak symbols are not supported.
	print_make_line( FD,  " @" . "NO_WEAK_SYM@" );
    }
}			       

#
# Add to a target the designate operation in all subdirs (except for .)
#     &RecursiveOp( "target" [, optional array of directories ] );
sub RecursiveOp {
    $target = $_[0];
    $subdirname = $_[1];
    if ($subdirname ne "") {
	@dirs = @$subdirname;
    }
    else {
	@dirs = (@extra_dirs, @subdirs);
    }
    print "n dirs = $#dirs\n" if $debug;
    if ($#dirs == 0 && $dirs[0] eq ".") { return; }
    if ($#dirs >= 0) { 
        print FD "\tfor dir in";
        foreach $dir (@dirs) {
	    if ($dir ne ".") { print FD " $dir"; }
	    if ($dir =~ /@[^@]*@/) {
		$subdirs_has_autoconf = 1;
	    }	    
        }
	# We may also want to check if subdirs is *only* autoconf; 
	# if not, we don't need the -
	if ($subdirs_has_autoconf) {
	    # Add a - incase there is a problem
          print FD " - ; do \\$newline";
	  print FD "\t\tif [ \"\$\$dir\" = \"-\" ] ; then break ; fi ; \\$newline";
	  print FD "\t\t(cd \$\$dir && \${MAKE} $target ; ) ; done$newline";
        }	
	else {
          print FD " ; do \\$newline\t\t(cd \$\$dir && \${MAKE} $target ; ) ; " .
	    "done$newline";
        }
    }
}

#
# Return the directory in which the named library should be in
sub GetLibLoc {
    $libname = $_[0];
    
    $libloc = $libdir{$libname};
    #chomp( $rootdir =  $rootdirpath );
    ( $rootdir =  $rootdirpath ) =~ s/[\r\n]*$//; # David added
	#strip ( $rootdir =  $rootdirpath );
    $libloc =~ s/ROOTDIR/$rootdir/;
    # Remove duplicated //
    $libloc =~ s/\/\//\//;

    $libloc;
}


#
# Look for autoconf directory variables that are used 
sub LookForAutoconfDirs {
    $line = $_[0];
    print "Looking at $line\n" if $debug;
    # Look for \$\{\w*\} and \$\(\w*\) 
    while ($line =~ /^[^\$]*\$[\{\(](\w*)[\}\)](.*)$/) {
	$varname = $1;
	$line = $2;
	print "Found $varname in line\n" if $debug;
	# Look for varname in the known names; add to dirs_seen
	if (defined($dirdefs{$varname})) {
	    print "Adding $varname to dirs_seen\n" if $debug;
	    $dirs_seen{$varname} = $varname;
	}
    }
}

sub LookForSuffixes {
    $line = $_[0]; 
    while ($line =~ /^[^\.]*\.(\w*)\s*(.*)$/) {
	$suffix = $1;
	$line   = $2;
	# For now, only check for suffixes that lead to .o files.
	# Later we can check the keys of extdef to see if they
	# match /$ext:.*/
	if (defined($extdef{"$suffix:o"})) {  
	    $ext_seen{$suffix} = 1;
	}
#  	# Also check for .txt files, used for documentation
#  	if ($suffix eq "txt") {
#  	    $ext_seen{$suffix} = 1;
#  	}
    }
}

#
# ===========================================================================
# The "all" target.
#
# Output the target list.  If there are extra_programs, note that.
# FIXME: there needs to be way to specify other local targets
# beyond the implicitly determined ones.  This needs to allow
# for both pre and post implicit target values
#
sub TargetAll {
    print_make_line( FD,  "all-redirect:" );
    if ($#subdirs > -1) {
	# If there are subdirectories, we must descend into them.
	# This branch does that, after adding the dependencies for the
	# target (if any).
	&TargetPreamble( "all" );
	print_make_endline( FD );
	# Now add the steps for the subdirectories
	$has_dot = 0;
	foreach $dir (@extra_dirs, @subdirs) {
	    if ($dir eq ".") {
		if (scalar(@alltargets) || 
		    defined($usertargets{"all-local"})) {
		    $has_dot = 1;
		    print FD "\t\${MAKE} all-local$newline";
		}
	    }
	    elsif ($dir =~ /@([^@]*)@/) {
		# May be a replaced variable
		print FD "\t${quietmake}for dir in $dir - ; do \\$newline";
		print FD "\t\tif [ \"\$\$dir\" = \"-\" ] ; then break ; fi ; \\$newline";
		print FD "\t\tif ( cd \$\$dir && \${MAKE} all ) ; then : ; else exit 1; fi \\$newline";
		print FD "\tdone$newline";
	    }
	    else {
		print FD "\t${quietmake}(cd $dir && \${MAKE} all )$newline";
	    }
	}
	# If subdirs has no dot but there are local targets, add an 
	# implicit dot to the end.
	if (!$has_dot && $#alltargets > -1) {
	    $has_dot = 1;
	    print FD "\t\${MAKE} all-local$newline";
	}
	if ($has_dot && !defined($usertargets{"all-local"})) {
	    print_make_line( FD, "all-local:" );
	    &ListTargets;
	}
	if (defined($optinstall_files{'SHLIB'})) {
	    # Conditionally create the shared libraries.
	    print FD "\t\@if [ \"\@ENABLE_SHLIB\@\" != \"none\" ] ; then \\\n";
	    foreach $libspec (split(/\s+/,$optinstall_files{'SHLIB'})) {
		print FD "\t    echo \"make $libspec\" ;\\\n";
		print FD "\t    \${MAKE} $libspec ; \\\n";
	    }
	    print FD "\tfi\n";
	}
	&TargetPostamble( "all" );
    }
    else {
	# This is a leaf, so we can list the dependencies.  
	&TargetPreamble( "all" );
	if (defined($usertargets{"all-local"})) {
	    # Add all-local as a target
	    print_make_line( FD, " all-local " );
	}
	&ListTargets;
	&TargetPostamble( "all" );
	if ($do_sharedlibs && $#allshlibtargets >= 0) {
	    # Add a conditional step
	    print_make_endline( FD );
	    print FD "\tif [ \"\@ENABLE_SHLIB\@\" != \"none\" ] ; then \\\n";
	    foreach $shlib (@allshlibtargets) {
		print FD "\t    \${MAKE} $shlib ; \\\n";
	    }
	    print FD "\tfi\n";
	}
    }
    print_make_endline( FD );
}

sub TargetPreamble {
    my $name = $_[0];
    $name .= "-preamble";
    if (defined($usertargets{$name})) { 
	print FD " $name";
    }
}
sub TargetPostamble { 
    my $name = $_[0];
    $name .= "-postamble";
    if (defined($usertargets{$name})) { 
	print FD "\t\${MAKE} $name$newline";
    }
}
#
# ===========================================================================
# The "clean" target
# 
# Produces clean: and distclean: .
# If clean-local or distclean-local were defined, they are included in
# the dependency lists
sub TargetClean {
    $programnames = join( ' ', keys(%programs));
    print FD "clean:";
    if (defined($usertargets{"clean-local"})) { print FD " clean-local"; }
    print FD "$newline";
    print FD "\t-rm -f *.o \${srcdir}/*.o $programnames$newline";
    # Add Windows names of executables
    if ($programnames ne "") {
	print FD "\t-rm -f";
	foreach $name (split(/\s+/,$programnames)) {
	    print FD " $name.exe";
	}
	print FD "$newline";
    }

    #if ($do_sharedlibs) {
        # Output this in all cases to clear any old files.  
	print FD "\t-rm -f *.lo \${srcdir}/*.lo$newline";
    #}
    if ($do_profilelibs && $found_profilelib) {
	print FD "\t-rm -f *.pf \${srcdir}/*.pf$newline";
    }
    # Clean coverage analysis files
    &GcovClean;

    &RecursiveOp( "clean" );
    print FD "distclean: clean";
    if (defined($usertargets{"distclean-local"})) { 
	print FD " distclean-local";
    }
    print FD "$newline";
    &RecursiveOp( "distclean" );
    # Remove any local files last (in case this file is one of them)
    $rmfile = "";
    $lcurdir = "$curdir";
    $lcurdir =~ s/\/$//;
    if (defined($autoconf_files_by_dir{$lcurdir})) {
	$rmfile = $autoconf_files_by_dir{$lcurdir};
	print FD "\t-rm -f $rmfile$newline";
	# Remove the configure cache that autoconf 2.57 adds
	print FD "\t-rm -rf autom4te.cache$newline";
    }
    if ($configure_has_config_headers ne "no") {
	# Add the AC_CONFIG_HEADER file, if any.
	print FD "\t-rm -f $configure_has_config_headers$newline";
    }
    &DistCleanDependencies;

    if ($distcleanfiles ne "") {
	print FD "\t-rm -f $distcleanfiles$newline";
    }
    print FD "\t-rm -f TAGS$newline";

    if ($maint_targets) {
	# Should maintainerclean also perform a distclean?
	print FD "maintainerclean:";
	if (defined($usertargets{"maintainerclean-local"})) {
	    print FD " maintainerclean-local";
	}
	print FD "$newline";
	&RecursiveOp( "maintainerclean" );
	# Remove the file that simplemake creates
	print FD "\t-rm -f $output_name$newline";
	# eventually, this should also invoke distclean, but it must
	# do that only once (not recursively) and only after all other
	# uses of the Makefile, since distclean removes the Makefile
	# Directories containing autoconf should include an rm of configure

	# This should also remove any files that will be created with
	# autoheader.  We'll need to check for files that are created
	# by autoheader, not just rely on the AC_CONFIG_HEADER command,
	# since some headers may be created by hand.  We'll ignore
	# this for now, since we uniformly use autoheader (and
	# simplemake runs autoheader if it finds AC_CONFIG_HEADER)
	if ($configure_has_config_headers ne "no") {
	    print FD "\t-rm -f ";
	    foreach $file (split(/\s+/,$configure_has_config_headers)) {
		print FD "$file.in ";
	    }
	    print FD "$newline";
	}
	# We also need to remove configure and autom4ate/ if present
    }
}

#
# ===========================================================================
# Libraries
#
# We want to generate either a generic "update library from object files"
# or "update library member" for makes that support that feature (this 
# is normally used only for the maintenance target).

#
# LibraryBuild ( libname, libloc, libfiles, lib extension, member extension )
# Not quite right.  Need to include the update command as well as ways
# to handle the "special extensions", both for the library (e.g., .a vs. .la)
# and members (e.g., .o vs .pf)
sub LibraryBuild {
    $libname = $_[0];
    $libloc  = $_[1];
    $sourcefiles = $_[2];
    $libext = $_[3];
    $memext = $_[4];
    if (!$dolib_member) {
	&print_make_line( FD, "${libloc}lib$libname.$libext: " );
    }
    foreach $sourcefile (split(/\s+/,$sourcefiles)) {
	$sourcefile =~ /(.*)\.([^\.]*)/;
	$obj = "$1.$memext";
	$ext = $2;
	# The special case for an extension of h handles the case where the
	# .h files are derived, and hence have special rules for creating
	# them
	if ( (!defined($extrules{"$ext:o"}) && ($ext ne "h"))) { 
	    print STDERR "Unknown extension $ext for $sourcefile for library $libname\n";
	}
	
	if ($dolib_member) {
	    &print_make_line( FD, "${libloc}lib$libname.$libext($obj): $obj" );
	    &print_make_endline( FD );
	    print FD "\t\${AR} cr ${libloc}lib$libname.$libext \$?$newline";
	}
	else {
	    if ($ext ne "h") {
		&print_make_line( FD, "$obj " );
	    }
	}
    }
    if (!$dolib_member) {
        &print_make_endline( FD );
        print FD "\t\${AR} cr ${libloc}lib$libname.$libext \$?$newline";
    }
}

sub TargetLibraries {
    foreach $lib (keys(%libraries)) {
	$libloc = &GetLibLoc( $lib );
	$sourcefiles = &ExpandMakeVars($libraries{$lib});
	&LibraryBuild( $lib, $libloc, $sourcefiles, "a", "o" );
        if ($ranliblib) { 
	    print FD "\t\${RANLIB} ${libloc}lib$lib.a$newline"; 
	}
	# To handle timestamp problems with recursive makes, add a delay
	if ($libloc =~ /^\.\./ && $fixup_for_timestamps) {
 	    $SleepText = $Sleep;
	    $SleepText =~ s/LIB/${libloc}lib$lib.a/;
	    print FD "\t$SleepText$newline"; 
        }

    }
}


# This code is similar to TargetLibraries.
sub TargetProfileLibraries {
    $found_source_files = 0;
    foreach $lib (keys(%profile_libraries)) {
	$proflib_name = $profile_libraries{$lib};
	$libloc = &GetLibLoc( $lib );
	$sourcefiles = &ExpandMakeVars($libraries{$lib});
#	&LibraryBuild( $proflib_name, $libloc, $sourcefiles, "a", "pf" );
	&print_make_line( FD, "${libloc}lib$proflib_name.a: " );
        foreach $sourcefile (split(/\s+/,$sourcefiles)) {
	    $found_source_files = 1;
            $obj = $sourcefile;
            # Convert to object file
	    $ext = $sourcefile;
	    $ext =~ s/^.*\.//g;
	    if ($ext eq "f") { 
		# Ignore Fortran source files (setbotf.f in mpich2)
		next;
	    }
	    elsif (defined($extrules{"$ext:o"})) {
		$obj =~ s/\.$ext/\.pf/g;
	    }
	    else {
		# Be silent on .h files
		if ($ext ne "h") {
		    print STDERR "Unknown extension $ext for $sourcefile for profile library $proflib_name\n";
		}
	    }
	    &print_make_line( FD, "$obj " );
        }
	&print_make_endline( FD );
	if ($found_source_files) {
	    # Add these files as objects to the archive
	    print FD "\t-mkdir .tmp ; rm -f .tmp/* ; cp \$? .tmp $newline";
	    print FD "\t-(cd .tmp && for file in *.pf ; do \\$newline";
	    print FD "\tbname=`basename \$\$file .pf`; mv -f \$\$file \$\${bname}.o ; done;)$newline";
	    # We should try to use a single invocation of ar instead of
	    # a separate one for each file, since ar is usually O(length) 
	    # for a single file, so this approach is O(length*nfiles).
	    # The only reason not to do this is that a particularly long
	    # command line may exceed commandline length limits.
	    print FD "\tfor file in .tmp/*.o ; do \\$newline";
	    print FD "\t\${AR} cr ${libloc}lib$proflib_name.a \$\$file ; done;$newline";
	    if ($ranliblib) { 
		print FD "\t\${RANLIB} ${libloc}lib$proflib_name.a$newline"; 
		# To handle timestamp problems with recursive makes, 
		# add a delay
		if ($libloc =~ /^\.\./ && $fixup_for_timestamps) {
		    $SleepText = $Sleep;
		    $SleepText =~ s/LIB/${libloc}lib$proflib_name.a/;
		    print FD "\t$SleepText$newline"; 
		}
	    }
	    print FD "\t-rm -rf .tmp$newline";
	}
    }
}

# This routine creates the library of shared objects.  There is a separate
# step that builds the shared library (which is really a kind of partially
# linked executable).
# Pass in the name (by reference) of the list of libraries.  This allows
# us to use this routine for both the general list of libraries (for -shared, 
# which makes both static and dynamic libraries) and for the list of libraries
# that are only needed as shared libraries (e.g., Totalview and Java/SLOG
# interface libraries).
sub TargetSharedLibraries {
    # This provides a *reference* to the hash that is passed into the routine
    # See the perlsub and perlref manpages for this, and the %$libraries and
    # $$libraries used below.
    my $libraries = @_[0];

    foreach $lib (keys(%$libraries)) {
	$libloc = &GetLibLoc( $lib );
	$sourcefiles = &ExpandMakeVars($$libraries{$lib});
	&LibraryBuild( $lib, $libloc, $sourcefiles, "la", "lo" );
	# no ranlib step here because we can't "link" the shared library
	# until all members are added.
    }
}

#
# This is the routine that creates a shared library from a library of
# shared objects.  NOT TESTED
# This must be called from the directory containing the library.
# Still to do: provide a separate directory for the library, so 
# that a build library may be used instead
# 
# If we can't use .lo as an object extension, then after extracting,
# rename everything as .o and then build.
# TargetSharedLibraryFinal( "libmpich.la", "libmpich.so.1", dir )
sub TargetSharedLibraryFinal {
    my $libname = $_[0];
    my $newlibname = $_[1];
    my $libdir = $_[2];
    print FD "# Build the shared library from the shared object files\n";
    print FD "$libdir/$newlibname: $libdir/$libname\n";
    print FD "\tif [ -d $libdir/.tmp ] ; then rm -rf $libdir/.tmp ; fi\n";
    print FD "\t\$(MKDIR_P) $libdir/.tmp\n";
    print FD "\t(cd $libdir/.tmp && ar x ../$libname && \\\n";
    print FD "\tfor file in *.lo ; do bfile=\`basename \$\$file .lo\` ; \\\n";
    print FD "\t\tmv \$\$file \$\$bfile.o ; done; \\\n";
    print FD "\t\${C_LINK_SHL} -o ../$newlibname *.o)\n";
    print FD "\trm -rf $libdir/.tmp\n";
}
#
# ===========================================================================
sub TargetPrograms {
    foreach $pgm (keys(%programs)) {
	&print_make_line( FD,  "$pgm: " );
	$pgmobjs = "";
	foreach $sourcefile (split(/\s+/,$programs{$pgm})) {
            $obj = $sourcefile;
            # Convert to object file
	    $ext = $sourcefile;
	    $ext =~ s/^.*\.//g;
	    if (defined($extrules{"$ext:o"})) {
		$obj =~ s/\.$ext/\.o/g;
		&print_make_line( FD, "$obj " );
		$pgmobjs .= "$obj ";
	    }
	    else {
		if ($ext ne "h") {
		    print STDERR "Unknown extension $ext for $sourcefile for program $pgm\n";
		}
	    }
        }
	# Add dependencies on libraries if requested
	$debug_lib_dependencies = 0;
	if ($convert_Ldir_to_relative) {
	    print STDERR "Checking for relative dirs\n" if $debug_lib_dependencies;
	    # convert -L dir -lname into dir/libname.a
	    $libdep=$pgm_ldadd{$pgm};
	    $libdep =~ s/-L\s*([\w\.\/]*)\s*-l([\w-]*)//;
	    $libdir = $1;
	    $libname = $2;
	    print STDERR "Checking $libdir and $libname\n" if $debug_lib_dependencies;
	    if (defined($libdir) && defined($libname) && 
		$libdir ne "" && $libname ne "" && 
		!defined($external_libraries{$libname})) { 
	        &print_make_line( FD, " $libdir/lib$libname.a" );
            }
	}
	$otherdep = $pgm_depadd{$pgm};
	if (defined($otherdep)) {
	    &print_make_line( FD, " $otherdep" );
	}
	if (defined($depadd_all)) {
	    &print_make_line( FD, " $depadd_all" );
	}

	# Use the link rule appropriate for this program type
	$pgmtype = $pgmsrctype{$pgm};
	&print_make_endline( FD );
	&print_make_setpos( 8 );
	$ruleline = "\t$progrules{$pgmsrctype{$pgm}} -o $pgm $pgmobjs";
	# We really need an libs before LIBS and libs after libs.
	if (defined($pgmlibs{$pgm})) {
	    $ruleline .= " $pgmlibs{$pgm}";
	}
	if (defined($pgm_ldadd{$pgm})) {
	    $ruleline .= " $pgm_ldadd{$pgm}";
	}
	$ruleline .= " \${LIBS}";
	&print_make_longline( FD, $ruleline );
#	&print_make_longline( FD, "\t$progrules{$pgmsrctype{$pgm}} -o $pgm $pgmobjs $pgmlibs{$pgm} $pgm_ldadd{$pgm} \${LIBS}" );
    }

}

#
# ===========================================================================
sub TargetTags {
    if (!$local_tags && !$root_tags) { return; }
    
    # Generate a listing of header and source files
    $has_sources = 0;
    $has_headers = 0;
    if ($regular_sources ne "") {
	&print_make_longline( FD, "SOURCES = $regular_sources" );
	$has_sources = 1;
    }
    if ($regular_headers ne "") {
	&print_make_longline( FD, "HEADERS = $regular_headers" );
	$has_headers = 1;
    }
    # Add a synonym for tags.
    print FD "tags: TAGS$newline"; 
    print FD "TAGS:";
    # Only generate a local etags call if there are local sources
    # This target is designed for VPATH builds to build a TAGS file in
    # a vpath location.
    if ($has_headers || $has_sources) {
        if ($local_tags) {
	    print FD '${HEADERS} ${SOURCES}
	here=`pwd`;\
	(cd ${srcdir} && etags -o $$here/TAGS --append ${HEADERS} ${SOURCES};)
';
        }
        elsif ($root_tags) {
	    print FD "\${HEADERS} \${SOURCES}$newline";
	    $rpath = $rootdirpath;
	    $rpath =~ s/\/$//;
	    # For vpath builds, make the root path point to the
	    # VPATH root.
	    
	    print FD "\there=\`cd $rpath && pwd\` ; cd \${srcdir} && etags -o \$\$here/TAGS --append \${HEADERS} \${SOURCES}$newline";
        }
        else {
	    print FD "$newline";
        }
    }
    else {
	print FD "$newline";
    }
    &RecursiveOp( "TAGS" );
}
#
# The generation of documentation (e.g., manual pages) is handled 
# a little differently.  To make it easier to manage a VPATH build of
# everything, including the documentation, we:
#    Add the document output types as file extensions to SUFFIX
#    Add generic build rules (using variables for options) 
#    Create targets using variable substitution.
# For example, to add html output (this shows *only* the document rules)
#
# .SUFFIXES: .c .html 
# .c.html:
# \tdoctext -html $(DOCTEXT_OPTIONS) $<
# HTML: ${mpi_sources:.c=.html}
#
# In addition, we may need to generate a document target even if there are
# no files in this directory *if* there are subdirectories (the usual
# recursive target).
#
# Temporary repository:
# the doctext line from MPICH1
#	$doctext -ext 3 -mpath ../../man/man3 -I pubinc -heading MPI \
#		 -quotefmt /home/MPI/mansrc/fortnotes \
#		 -ignore EXPORT_MPI_API \
#	         /home/MPI/mansrc/errnotes *.c ; \
#
# SuffixDocs: Add any suffix rules for this directory
sub SuffixDocs { 
    # global: do_docs, suffixes, docsrc
    if (! $do_docs) { return; }
    foreach my $kind (keys(%docsrc)) {
	if ($docsrc{$kind} ne "") {
	    $suffixes .= " .$kind";
	}
    }
    # Add source file suffixes
    if (! ($suffixes =~ /\.txt/) ) {
	$suffixes .= " .txt";
    }
}
sub VariableDocs {
    # global: do_docs, suffixes, docsrc
    if (! $do_docs) { return; }
    foreach my $kind (keys(%docsrc)) {
	;
    }
}

#
# Generate the rule for generating documentation from the source files
# 
sub RuleDocs {
    # global: do_docs, docsrc, FD, newline
    if (! $do_docs) { return; }
    $rootdir = $rootdirpath;
    foreach my $kind (keys(%docsrc)) {
	# Set the default suffix
	$docsrcsuffix = ".c";
	if ($docsrc{$kind} ne "") {
	    $docdestdir = $globaldocdir;
	    if ($docdir{$kind} ne "") {
		$docdestdir = $docdir{$kind};
	    }
	    # Replace ROOTDIR, including handling any doubled //
	    $docdestdir =~ s/ROOTDIR/$rootdir/g;
	    $docdestdir =~ s/\/\//\//g;
	    # Replace any occurance of $dockinddirval is docdestdir
	    if (defined($docthiskinddir{$kind})) {
		$dockinddirval = $docthiskinddir{$kind};
	    }
	    else {
		$dockinddirval = $dockinddir{$kind};
	    }
	    $docdestdir =~ s/(\$\w+)/$1/eeg;     # see man perlfaq4
	    #
	    # Replace ROOTDIR etc in any doc_namedefs
	    $docargs = $doc_namedefs;
	    $docargs =~ s/ROOTDIR/$rootdir/g;
	    $docargs =~ s/\/\//\//g;
	    
	    # Check for an alternative suffix
	    $docfiles = &ExpandMakeVars( $docsrc{$kind} );
	    print "file list = $docfiles\n" if $debug;
	    for $file (split(/\s+/,$docfiles)) {
		$file =~ /.*(\..*)$/;
		$suffix = $1;
		if ($docsrcsuffix ne $suffix) {
		    $docsrcsuffix = $suffix;
		}
	    }
	    print FD "$docsrcsuffix.$kind:$newline";
	    $extarg = "";
	    if ($kind eq man && ($docdestdir =~ /man(\d)$/)) {
		$extarg = "-ext $1";
	    }
	    print FD "\tdoctext $doctextOptionName{$kind} -mpath $docdestdir $extarg -heading $doc_heading \\$newline";
	    print FD "\t\t-quotefmt $docargs \$<$newline";
	}
    }
}

#
# Given a list of sources, return an array containing the distinct suffixes
# (without the leading .)
sub GetSuffixList {
    my %suffixSeen = ();
    my $vars = $_[0];
    my @suffixes = ();

    # Check for an alternative suffix
    $vars = &ExpandMakeVars( $vars );
    print "file list = $vars\n" if $debug;
    for $file (split(/\s+/,$vars)) {
	$file =~ /.*\.(.*)$/;
	$suffix = $1;
	if (!defined($suffixSeen{$suffix})) {
	    $suffixSeen{$suffix} = 1;
	    $suffixes[$#suffixes+1] = $suffix
	}
    }
    return @suffixes;
}

sub SubForSuffixes {
    my $src = $_[0];
    my $suffixarrayName = $_[1];
    my $repSuffix = $_[2];
 
    for $suffix (@$suffixarrayName) {
	$src =~ s/\.$suffix/\.$kind/;
    }
    return $src;
}

#
# Generate the documentation targets.
#
sub TargetDocs {
    if (! $do_docs) { return; }
    my %didkind = ( "html" => 0, "man" => 0, "latex" => 0 );
    foreach my $kind (keys(%docsrc)) {
	$targetKind = $docTargetName{$kind};
	print FD "$targetKind: ";
	my $src = $docsrc{$kind};
	if ($src ne "") {
	    if ($src =~ /^\s*\$[\{\(][_\w]*[\}\)]\s*$/) {
		# a single variable: use make substitution if a single
		# suffix
		@suffixes = &GetSuffixList( $src );
		if ($#suffixes == 0) {
		    $src =~ s/\}/:.$suffixes[0]=.$kind\}/;
		}
		else {
		    # manually substitute
		    $src = &SubForSuffixes( $src, "suffixes", $kind );
		}
	    }
	    elsif ($src =~ /\$/) {
		# Perform variable expansion if possible
		$src = &ExpandMakeVars( $src );
		@suffixes = &GetSuffixList( $src );
		# Convert the extensions to the document type
		#$src =~ s/\.c/.$kind/;
		$src = &SubForSuffixes( $src, "suffixes", $kind );
	    }
	    else {
		$src =~ s/\.c/.$kind/;
	    }
	    print FD "$src$newline";
	}
	else {
	    # This is the recursive branch
	    print FD "$newline";
	}
	# If we're at the top; create any directories that are needed
	# This assumes a particular layout for the directories that
	# we'll eventually want to make adjustable.
	if ($doc_attop) {
	    if ($kind eq "html") {
		print FD "\tif [ ! -d www ] ; then mkdir www ; fi$newline";
		print FD "\tif [ ! -d www/www1 ] ; then mkdir www/www1 ; fi$newline";
		print FD "\tif [ ! -d www/www3 ] ; then mkdir www/www3 ; fi$newline";
	    }
	    elsif ($kind eq "man") {
		print FD "\tif [ ! -d man ] ; then mkdir man ; fi$newline";
		print FD "\tif [ ! -d man/man1 ] ; then mkdir man/man1 ; fi$newline";
		print FD "\tif [ ! -d man/man3 ] ; then mkdir man/man3 ; fi$newline";
	    }
	    elsif ($kind eq "latex") {
		print FD "\tif [ ! -d doc ] ; then mkdir doc ; fi$newline";
		print FD "\tif [ ! -d doc/refman ] ; then mkdir doc/refman ; fi$newline";
	    }
	    else {
		print STDERR "Unrecognized document type $kind\n";
	    }
	}
	&RecursiveOp( $targetKind );
	if ($#doc_subdirs >= 0) {
	    &RecursiveOp( $targetKind, "doc_subdirs" );
	}
	$didkind{$kind} = 1;
    }
    # 
    # For any directory that does not have any source files, we must still
    # generate a target *if* any directory set the source.
    foreach $kind ("html", "man", "latex") { 
	$targetKind = $docTargetName{$kind};
	if (! $didkind{$kind} && $globaldockind{$kind}) {
	    print FD "$targetKind:$newline";
	    &RecursiveOp( $targetKind );
	    if ($#doc_subdirs >= 0) {
		&RecursiveOp( $targetKind, "doc_subdirs" );
	    }
	}
    }
}

#
# Install target.  Question: does this need to list (or use a shell command
# to get) the filename for each individual file?
sub InstallDocs {
    # Add target only at the top
    if (!$doc_attop) { return; }
    
    print FD "install-docs:$newline";
    # Each document type is different.  In addition, we want the install
    # to work even if the documents have not been built.
    if ((!$didkind{"html"}) && $globaldockind{"html"}) {
        print FD "\tif [ ! -d \$(htmldir) ] ; then \$(MKDIR_P) \$(htmldir) ; fi\n";
	print FD "\tif [ -d www/www3 ] ; then \\$newline";
	print FD "\t\$(INSTALL_DATA) www/www3/* \$(htmldir)/www3/ ; fi$newline";
	print FD "\tif [ -d www/www1 ] ; then \\$newline";
	print FD "\t\$(INSTALL_DATA) www/www1/* \$(htmldir)/www1/ ; fi$newline";
    }
    if ((!$didkind{"man"}) && $globaldockind{"man"}) {
        print FD "\tif [ ! -d \$(mandir) ] ; then \$(MKDIR_P) \$(mandir) ; fi\n";
	print FD "\tif [ -d man/man3 ] ; then \\$newline";
	print FD "\t\$(INSTALL_DATA) man/man3/* \$(mandir)/man3/ ; fi $newline";
	print FD "\tif [ -d man/man1 ] ; then \\$newline";
	print FD "\t\$(INSTALL_DATA) man/man1/* \$(mandir)/man1/ ; fi $newline";
    }
    # LaTeX manual is different and requires a special case
}

# Add any dirs that are referred to by InstallDocs
sub InstallDocDirs {
    # Add target only at the top
    if (!$doc_attop) { return; }

    print FD "htmldir         = \@htmldir\@\nmandir          = \@mandir\@\n";
}

#
# Installation is complicated by VPATH builds; files that are derived and
# files that are not may be in different locations (one relative, the other
# absolute with respect to the source tree)
sub TargetInstall {
    %dirschecked = ();
    if (!scalar(%install_files)) { return ; }
    print FD "# Install target$newline";
    print FD "install:$newline";
    foreach $kind (keys(%install_files)) {
	$dir = $install_dir{$kind};
	if ($dir eq "") {
	    print STDERR "No known installation dir for install_$kind\n";
	    next;
	}
	if (!defined($dirschecked{$dir})) {
	    # Check on dependent directories
	    foreach $checkdir (split(/\s+/,$required_dirs{$dir})) {
		if ($checkdir ne "" && !defined($dirschecked{$checkdir})) {
		    $dirschecked{$checkdir} = 1;
		    print FD "\tif [ ! -d \${$checkdir} ] ; then \$(MKDIR_P) \${$checkdir} ; fi$newline";
		}
	    }
	    print FD "\tif [ ! -d \${$dir} ] ; then \$(MKDIR_P) \${$dir} ; fi$newline";
	    $dirschecked{$dir} = 1;
	}
	#
	# If there is an install-local target, invoke it here:
	if (defined($usertargets{"install-local"})) {
	    print FD "\t\${MAKE} install-local$newline";
	}
	foreach $file (split(/\s+/,$install_files{$kind})) {
	    $destfile = $file;
	    $destfile =~ s/.*\///;
	    $this_install_method = $install_methods{$kind};
	    if ($this_install_method eq "") {
		$this_install_method = '$(INSTALL)';
		}
	    print FD "\t$this_install_method $file \${$dir}/$destfile$newline";
	}
    }
    foreach $kind (keys(%optinstall_files)) {
	$dir = $install_dir{$kind};
	if (!defined($dirschecked{$dir})) {
	    print FD "\tif [ ! -d \${$dir} ] ; then \$(MKDIR_P) \${$dir} ; fi$newline";
	    $dirschecked{$dir} = 1;
	}
	foreach $filelist ($optinstall_files{$kind}) {
	    foreach $file (split( /\s+/, $filelist)) {
		$destfile = $file;
		$destfile =~ s/.*\///;
		print FD "\tif [ -s $file ] ; then \$(INSTALL_PROGRAM) $file \${$dir}/$destfile ; fi$newline";
	    }
	}
    }
    foreach $extradir (@install_subdirs) {
	# Check for configure substitutions in the list.  Make
	# these conditional, so that they can be empty.  Also note that
	# they could also contain *multiple* directories, so we have
	# to handle them in a general way
	$endline = "";
	if ($extradir =~ /^@/) {
	    print FD "\tfor dir in $extradir - ; do \\$newline";
	    print FD "\t\tif [ \"\$\$\dir\" = \"-\" ] ; then break ; fi ;\\$newline";
	    print FD "\t\t(cd \$\$dir && \$(MAKE) INSTALL_STRIP_FLAG=\$(INSTALL_STRIP_FLAG) install) ;\\$newline";
	    print FD "\tdone$newline";
	}
	else {
	    print FD "\t(cd $extradir && \$(MAKE) INSTALL_STRIP_FLAG=\$(INSTALL_STRIP_FLAG) install)$newline";
	}
    }
    print FD "$newline";

    # Install documentation
    &InstallDocs;
    #
    print FD "install-strip:$newline";
    print FD "\t\$(MAKE) INSTALL_STRIP_FLAG=-s install$newline";
    
    #
    # We should also create an uninstall target.  Rather than 
    # unilaterally uninstalling files, we may want an option to create
    # a file that will uninstall only the installed files (as MPICH-1
    # does).
    print FD "uninstall:$newline";
    foreach $kind (keys(%install_files)) {
	$dir = $install_dir{$kind};
	foreach $file ($install_files{$kind}) {
	    $destfile = $file;
	    $destfile =~ s/.*\///;
	    print FD "\t-rm -f \${$dir}/$destfile$newline";
	}
    }
    foreach $kind (keys(%optinstall_files)) {
	$dir = $install_dir{$kind};
	foreach $file (split(/\s+/,$optinstall_files{$kind})) {
	    $destfile = $file;
	    $destfile =~ s/.*\///;
	    print FD "\t-rm -f \${$dir}/$destfile$newline";
	}
    }
    # Still doesn't handle install files added by subdir installs
}
#
# ===========================================================================
# Other targets and stuff to be added:
#   CPP
#   Including common headers (e.g., all file.sm's get a common header of
#       variables defined by configure.  This is cleaner than the automake 
#       approach of including *every* AC_SUBST value).
#   Support for shared libraries.  Unlike automake, we will not require
#       separate rules (automake uses lib_LTLIBRARIES and la extensions)
#       for shared library support.
#   Handling files to be installed (e.g., automake's sbin_PROGRAMS = ...)
#      (automake understands <dir>_PROGRAMS and <dir>_LIBRARIES)
#   target_LDFLAGS and general LDFLAGS
#   INCLUDES (automake variable that we've adopted) needs better control.
#   Support for .F and .F90 extensions (Fortran with preprocessor)
#   FLIBS
#   Linker choice.  simplemake uses the file type of the *first* source file.
#       automake has a matrix that depends on the source files referred to.
#   SCRIPTS (as in bin_SCRIPTS) targets
#   HEADERS variables (as in prog_HEADERS).  In many cases, this should
#       be determined automatically.  Note that it is needed for correct TAGS
#       generation.

# Miscellaneous Routines
sub printHelp {
    print STDERR "\
simplemake [ -nocomments ] [ -am ] [ -libdir=NAME=DIR ] [ -include=LIST ]\
           files \
    -nocomments      - Exclude Makefile comments from generated file\
    -libdir=NAME=DIR - library NAME is located in directory DIR\
    -am              - Automake style target names\
    -include=LIST    - CPP style list of include directories (e.g., -Ia -Ib)\
                       These define INCLUDES unless a Makefile.sm defines\
                       that value\
    -v               - verbose output\
    -common=file     - Read text to include in every output file\
    -distrib         - Turn off all maintenance targets (make a distribution\
                       version)\
    -vpath=[yes|no]  - Create VPATH targets\
\
    -depend          - Generate dependency information as a make target\
    -depend=static   - Generate dependency information when simplemake runs\
    -nodepend        - Do not generate dependency information\
\
    -rootdir=PATH    - Set the root directory for all Makefiles\
    -debug           - Turn on debugging output\
    -dos             - Use DOS-style newlines on output files\
    -help            - This output\
    \n";
    print STDERR "\
    Recognized target forms\
    libname_a_SOURCES = source files for library \"name\"\
    libname_a_DIR     = location of directory into which lib \"name\" goes\
    SUBDIRS = blank separated list of subdirectories to process.  Use \".\"\
              to control the order in which the current directory is processed\
    DOC_SUBDIRS = blank separate list of subdirectories containing \
              documentation but no code source.  These directories may\
              contain files used as input to documentation generators.\
    EXTRA_PROGRAMS = names of programs to define rules for but not to build\
                     by default\
    name_SOURCES = source files for program \"name\"\
    name_LDADD   = extra linker flags for building program \"name\"\
\
    LDADD = extra linker flags to add to all programs\
    simplemake also allows all usual Makefile commands, including variable\
    assignment and targets.\n";
}

#
# Generate dependency information when possible.  This version simply 
# uses gcc -MM; if that doesn't work, does nothing.  
#
# Automake strives to generate the dependencies.  This is a better approach,
# but it is very difficult to implement in practice, particularly where the
# development environment is not GNU.  
#
# This is somewhat tricky because the current organization of MPICH2
# makes use of many -I<dir> switches, that are selected at configure time,
# so some files may not be where expected.
sub AddDependency {
    $target = $_[0];
    if (defined($makevars{"INCLUDES"})) {
	$include = $makevars{"INCLUDES"};
    }
    else {
	$include = $include_list;
    }
    print "Trying $make_depend $include $target\n" if $debug;
    $cmdline = "$make_depend $include $target";
    if (! $debug) {
	$cmdline .= " 2>/dev/null";
    }
    $cmdline .= " |";
    print "Depend commandline = $cmdline\n" if $debug;
    open( DEPFD, $cmdline ) || return;
    while (<DEPFD>) {
	# Remove files that are provided by the device
	s/[^\s]*mpidpre\.h//g;
	s/[^\s]*mpidpost\.h//g;

	# For derived object files like lo and pf, add these
	if ($do_profilelibs && $found_profilelib) {
	    s/^(.*)\.o:(.*)/\1.o \1.pf:\2/;
	}
	if ($do_sharedlibs || $found_sharedlib) {
	    s/^(.*)\.o(.*)/\1.o \1.lo\2/;
	}
	print FD $_ ;
    }
    close( DEPFD );
}

#
# 
sub TargetDependenciesStatic {
    print FD "# Dependencies$newline";
    # Libraries first
    foreach $lib (keys(%libraries)) {
        foreach $sourcefile (split(/\s+/,&ExpandMakeVars($libraries{$lib}))) {
            # Get extension
	    $ext = $sourcefile;
	    $ext =~ s/^.*\.//g;
	    # We only know about C for now.
	    if ($ext eq "c") {
		&AddDependency( $sourcefile );
	    }
        }
    }
    # Programs
    foreach $pgm (keys(%programs)) {
	foreach $sourcefile (split(/\s+/,$programs{$pgm})) {
	    $ext = $sourcefile;
	    $ext =~ s/^.*\.//g;
	    # We only know about C for now.
	    if ($ext eq "c") {
		&AddDependency( $sourcefile );
	    }
	}
    }
}

#
# Design:
# Each source file has an associated file containing dependencies, stored in 
# a subdirectory .deps
#    Each source file foo has .deps/foo.Po
#    The Makefile includes .deps/alldeps
#
# Because we want to support VPATH builds, we can't create these in the
# real source directory, so these directories and files must be created
# at configure time.
#
sub TargetDependenciesDynamic {
    my $has_sources = 0;

    # First, are there any sources?
    # a hash in a scalar context is 0 if empty and nonzero otherwise
    if (scalar(%libraries)) {
	$has_sources = 1;
    }
    
    # Some makes will accept sinclude instead of -include
    # -include is gnumake for "include if file exists, ignore otherwise"
    if ($makeInclude eq "") { $makeInclude = "-include"; }

    print FD "# Dependencies$newline";
    # This definition follows the cone for COMPILE_C
    if ($has_sources) {
	print FD "MAKE_DEPEND_C = \@MAKE_DEPEND_C\@ \$(INCLUDES) \$(CPPFLAGS)$newline";
	print FD "dependencies: .deps/timestamp$newline";
    }
    else {
	print FD "dependencies:$newline";
    }
    &RecursiveOp( "dependencies" );

    if ($has_sources) {
	print FD ".deps/timestamp: ";
	foreach $lib (keys(%libraries)) {
	    $sourcefiles = $libraries{$lib};
	    PrintMakeLongline( FD, "$sourcefiles ", "append" );
	}
	# Add Makefile as a dependency, since changes in the Makefile
	# can change the dependencies (particularly different configure 
	# choices)
	PrintMakeLongline( FD, "Makefile", "last" );

	# We always use a "newalldeps" incase there is a failure 
	# creating the new list of dependency files.
	print FD "\t-rm -f .deps/newalldeps$newline";
	foreach $lib (keys(%libraries)) {
	    foreach $sourcefile (split(/\s+/,&ExpandMakeVars($libraries{$lib}))) {
		$ext = $sourcefile;
		$ext =~ s/^.*\.//g;
		$sourcebasename = $sourcefile;
		$sourcebasename =~ s/\.\w*$//;
		if ($ext eq "c") {
		    print FD "\t\$(MAKE_DEPEND_C) \$(srcdir)/$sourcefile >.deps/$sourcebasename.Po$newline";
		    print FD "\techo \"$makeInclude .deps/$sourcebasename.Po\" >>.deps/newalldeps$newline";
		}
	    }
	}
	print FD "\tif [ -s .deps/newalldeps ] ; then mv -f .deps/newalldeps .deps/alldeps ; fi$newline";
	print FD "\tdate >.deps/timestamp$newline";

	print FD "$makeInclude .deps/alldeps$newline";
    }
    print FD "# End of Dependencies$newline";
}

sub DistCleanDependencies {
    # Eventually, this should output only in Makefiles that have the 
    # dependencies directory
    print FD "\trm -rf .deps$newline";
}


# Extract derived files from autoconf
# Also record whether there is an AC_CONFIG_HEADER
sub ReadAutoconf {
    $configure_has_config_headers = "no";
    open FDCONF, "configure.in" || die "Could not open configure.in file";
    while (<FDCONF>) {
	#if (/^\s*#/) { next; }
	if (/^\s*AC_CONFIG_HEADER\((.*)\)/) {
	    # Record file name of header in result variable
	    # We also need to add this to the list of files to remove
	    # in the distclean target
	    $configure_has_config_headers = $1;
	}
	if (/^\s*AC_OUTPUT\(/) {
	    # First, read past all continued lines
	    $line = "";
	    # Remove any M4 dnl line
	    s/\sdnl\s.*//;
	    while (/\\\s*$/) {
		#chomp;    # remove trailing EOL (\n on Unix, \r\n on DOS)
		s/[\r\n]*$//; # David added
		#strip;
		chop($_); # remove the backslash
		$line .= $_;
		$_ = <FDCONF>;
		# Remove any M4 dnl line
		s/\sdnl\s.*//;
	    }
	    $line .= $_; 
	    #chomp( $line );
	    $line =~ s/[\r\n]*$//; # David added
		#strip ( $line );
	    #print $line;
	    $line =~ /^\s*AC_OUTPUT\((.*)\)\s*$/;
	    $files = $1;
	    @autoconf_files = split(/\s+/,$files);
	    # Create a hash by directory
	    $lcurdir = $curdir;
	    $lcurdir =~ s/\/$//;
	    foreach $file (@autoconf_files) {
		if ($file =~ /^(.*)\/([^\/]*)$/) {
		    # File contains a directory path, so update the
		    # appropriate directory entry
		    $autoconf_files_by_dir{"$curdir$1"} .= " $2";
		    #print "{$curdir$1} .= $2\n";
		    # Also add files that are in directories with no simplemake
		    # input (e.g., in include directories with no makefile)
		    if (! -s "$curdir$1/Makefile.sm") {
			$autoconf_files_by_dir{$lcurdir} .= " $file";
		    }
		}
		elsif ($file =~ /^\$(\w*)/) {
		    # Another special case.  The name is actually
		    # a shell variable.  This is too hard for us right now,
		    # so generate a warning and do NOT add it to the list
		    print STDERR "Shell variable $1 will not be added to the list\n";
		    print STDERR "of known autoconf file files for ";
		    if ($lcurdir ne "") {
			print STDERR "$lcurdir\n";
		    }
		    else {
			print STDERR "top directory\n";
		    }
		}
		elsif ($file =~ /^.*$/) {
		    $autoconf_files_by_dir{"$lcurdir"} .= " $file";
		    #print "{$lcurdir} .= $file\n";
		}
	    }
	    # Add files that configure generates in the current directory
	    $autoconf_files_by_dir{$lcurdir} .= " config.status config.log config.cache config.system";
	    #print "$files\n";
	    last;
	}
    }
    close FDCONF;
}
#
# Find how to get from path_child to path_parent.  Return as
# ../.. etc, suitable for using cd to get to the parent
sub GetPathToParent {
    my ($path_child, $path_parent) = @_;
    # Remove parent path from child path
    $path_child =~ s/^$path_parent//;
    # convert all of the non directory separators into ..
    $path_child =~ s/[^\/\.]*\//..\//g;
    return $path_child;
}

#
# Remove any trailing .. from the directory as well as that many directories
sub CleanCurDir {
    my $dir = $_[0];
    my $depth = 0;

    # Handle any /.. at the end
    $dir =~ s/\/$//;
    while ($dir =~ /\/\.\.$/) {
	$depth++;
	$dir =~ s/\/\.\.$//;
    }
    while ($depth > 0) {
	$dir =~ s/\/[^\/]*//;
	$depth--;
    }

    # We sometimes get ../ in the middle
    while ($dir =~ /(.*)\/[^\/\.]+\/\.\.(.*)/) {
	print "Changing $dir to $1$2\n" if $debug_confdir;
	$dir = "$1$2";
    }
    return "$dir/";
}    
#
# ===========================================================================
# Pretty print output lines.  These routines insert line breaks and tabs
# to keep the generated makefile from being too ugly.  These also use
# tabs after a continuation line.
$linelen = 0;
sub print_make_line {
    my $FD = $_[0];
    my $line = "$_[1]";
    my $len = length($line);
    if ($linelen + $len + 2 > $maxline) {
	print $FD "\\$newline\t";
	$linelen = 8;
    }
    print $FD $line;
    $linelen += $len;
    }
sub print_make_endline {
    my $FD = $_[0];
    print $FD $newline;
    $linelen = 0;
}
sub print_make_setpos {
    $linelen = $_[0];
}
# print_make_longline is intended for printing long lines that contains blanks
# This adds the newline at the end
sub print_make_longline {
    my $FD = $_[0];
    my $line = $_[1];
    my $len = length( $line );
    &PrintMakeLongline( $FD, $line, "last" );
}

# New print routines
# PrintMakeLongline( FD, line, flag ) - line may have spaces, will break
# as spaces in line.  Flag may be "append" or "last".  line may be empty
# (to use flag = "last" to terminate.
sub PrintMakeLongline {
    my $FD = $_[0];
    my $line = $_[1];
    my $flag = $_[2];

    my $len = length( $line );
    if ($linelen + $len + 2 < $maxline) {
	print $FD $line;
    }
    else {
	# Use space, not \s, because we want tabs to remain tabs
	foreach my $token (split(/ /,$line)) {
	    # We must be careful not to add a blank if the token is
	    # a \ used at the end of a line to continue to the 
	    # next line
	    if ($token eq "\\") {
		&print_make_line( $FD, "$token" );
	    }
	    else {
		&print_make_line( $FD, "$token " );
	    }
	}
    }
    if ($flag eq "last") {
	&print_make_endline( $FD );
    }
}

# Eventually we will use this to generate the profiling targets.
#### THIS IS DEAD CODE!! DO NOT USE!!!
sub ProfileTargets {
    print FD "\
# Instead, we define the PMPI_OBJECTS as having suffix pf:\
PMPI_OBJECTS = \${OBJECTS:.o=.pf}\
# Convert foo.pf to _foo.o, then archive all at once\
${libbuild_dir}/lib\@PMPILIBNAME\@.a: \${PMPI_OBJECTS}\
        \@echo \"Rename xxx.pf to _xxx.o for profiling interface.\"\
        \@if [ ! -d .tmp ] ; then mkdir .tmp ; else rm -f .tmp/*.o ; fi\
        \@for file in $? ; do \\\
            bname=`basename $$file .pf`; \\\
            cp $$file .tmp/_$${bname}.o ; \\\
        done\
        \@cd .tmp && ${AR} cr $\@ *.o && rm -f *.o\
        -\@rmdir .tmp\
# Note that the Solaris SunPro cc (4.0 98/12/15) does not allow the file\
# named with -o to have any suffix other than .o !\
.c.pf:\
        \${C_COMPILE} -c -DMPICH_MPI_FROM_PMPI \$< -o \$*.o\
        \@mv -f \$*.o \$*.pf\
.f.pf:\
        \${F77_COMPILE} -c \$<\
        \@mv -f \$*.o \$*.pf\
";
}
#
# Find a working autoconf.
# If the variables autoconf and autoconf_version are set, try to
# find one that works in the user's path.  The format for these
# variables is
#   autoconf = name:name:...:lasthope
#   autoconf_version = number
#   Check each autoconf name for handling version.  If all else fails,
#   unconditionally accept lasthope
sub FindWorkingAutoconf {
    if ($autoconf_version ne "") {
	foreach $file (split(/:/,$autoconf)) {
	    $lastfile = $file;
	    # Grumble.  I need to redirect stderr to stdout before this
	    # open.  We use open with a pipe and then exec so that we
	    # can get stderr redirection to work correctly.
	    #
	    # Additional grumble.  Perl doesn't flush output the
	    # way you'd like.  Of course, if you turn on -debug,
	    # things do get flushed.
	    $pid = open( ACFD, "-|");
	    if ($pid == 0) {
		close FD;  # without flushing
		open STDIN, "/dev/null";
		open STDERR, ">>&STDOUT";
		exec split(/\s+/,"$file --version");
	    }
	    else {
		$found_version = "";
		while (<ACFD>) {
		    print STDERR "$_" if $debug;
		    if (/[Aa]utoconf\s.*([12]\.[0-9]+)/) {
			$found_version = $1;
			last;
		    }
		}
		close( ACFD );
		print STDERR "Autoconf $file is version $found_version\n" if $debug;
		if ($found_version >= $autoconf_version) {
		    $autoconf = $file;
		    print STDERR "Using autoconf $file\n" if $debug;
		    return;
		}
	    }
	}
	# If we got here, use the lastchance
	$autoconf = $lastfile;
    }
}
#
# ----------------------------------------------------------------------------
# Coverage analysis
# One useful target for package maintainers is coverage analysis.  
# The following code creates the targets for the gcc coverage analyzer, 
# gcov.  In tests, this analyzer worked with programs built from libraries
# and with sources in multiple directories.
#
# To use the gcc coverage analyzer, the following steps must be taken
# 1.  All file must be compiled with -fprofile-arcs -ftest-coverage, and
#     without optimization
# 2.  Programs are run as usual
# 3.  To create coverage data, run
#         gcov -f -b sourcefile
#     over all source files.  The result is (for each sourcefile) a
#     new file, "sourcefile.gcov", which annotates the source file with
#     the number of times each statement was executed
#
# To add support for these, simplemake adds the following targets in
# maintenance target mode (e.g., not in the distributed version):
#     Add to clean (all with ${srcdir}) *.bb, *.bbg, *.da, *.c.gcov .  
#         These are all created by either gcc or by running programs
#         built with -ftest-coverage.
#     Add a recursive coverage target that does:
#         Run gcov on each source file (if any), where a .da file is present
#     We may be able to use a target like:
#         $*.c.gcov depends on $*.da (.da.gcov)
#     We let the configure step add the compiler options (so that a 
#     separate simplemake build is not required to add or remove 
#     coverage analysis.
#
# ToDo: 
# In the install step, mkdir isn't right, since it will make only one
# directory level, and mkdir -p isn't universally available.  We probably
# need either a MKDIR_P command, determined byu configure, or an
# mkinstalldirs script.  I'd prefer a mkdirp script, used only if mkdir -p
# did not work, and chosen by configure in that case.
# This is partially done (MKDIR_P and that is set to mkdir -p)
# ----------------------------------------------------------------------------
# Add the clean target for the coverage analyzer
sub GcovClean {
    if ($maint_targets) {
	print FD "\t-rm -f \${srcdir}/*.bb \${srcdir}/*.bbg \${srcdir}/*.da$newline";
    }
}

# coverage target
sub TargetGcov {
    if (!$maint_targets) { return; }
    print FD "coverage:$newline";
    foreach $lib (keys(%libraries)) {
	$sourcefiles = $libraries{$lib};
	PrintMakeLongline( FD, 
	   "\t-${quietmake}for file in $sourcefiles ; do \\", "last" );
	print FD "\t\tgcov -b -f \$\$file ; done$newline";
    }
    &RecursiveOp( "coverage" );
}
# 
# ----------------------------------------------------------------------------
#
# ToDo
# Should we add a target to strip debugging information from the object files?
# For example, strip -S *.o .  Ths usually isn't necessary if -g is not
# selected when building the object files.
#
# David Ashton suggests an option to print a warning message for 
# each source file (e.g., *.c, *.cxx, *.f, *.f90) that has no corresponding
# entry in the Makefile.sm 
#
# Here is a start on that.
# What is still needed is a way to check for defined sources when the source 
# files are named in a variable (e.g., xxx_SOURCE = ${foobar}, then we
# need to expand foobar.  This is not done systematically yet, in part
# because we want to preserve the use of variables in the Makefile.
sub checkForTargets {
    opendir DIR, ".";
    while ($filename = readdir DIR) {
	if ($filename =~ /.*\.[cf]$/) {
	    # Found a source file.  Did we see this file in the source lists?
	    if (! defined($sources{$filename})) {
		print STDERR "File $filename did not appear in Makefile.sm\n";
	    }
	}
    }
    closedir DIR;
}
