#!/usr/bin/perl
#
# Usage: makemake {<program name> {<F90 compiler or fc or f77 or cc or c>}}
#
# Generate a Makefile from the sources in the current directory.  The source
# files may be in either C, FORTRAN 77, Fortran 90 or some combination of
# these languages.  If the F90 compiler specified is cray or parasoft, then
# the Makefile generated will conform to the conventions of these compilers.
# To run makemake, it will be necessary to modify the first line of this script
# to point to the actual location of Perl on your system.
#
# Written by Michael Wester <wester@math.unm.edu> February 16, 1995
# Cotopaxi (Consulting), Albuquerque, New Mexico
#
open(MAKEFILE, "> AA_make");
#
#print MAKEFILE "PROG =\t$ARGV[0]\n\n";
#
# Misc

print MAKEFILE "MAKE_NAM = \$(MAKE)\n";
print MAKEFILE "ifneq (\$(MAKE_NAM),\$(M_K))\n";
print MAKEFILE " \@\$(error You must invoke this Makefile with the \$(M_K) command)\n";
print MAKEFILE "endif\n";
print MAKEFILE "USER_DIR = \$(shell /bin/pwd)\n";
print MAKEFILE "MAKE_DIR = '??'\n";
print MAKEFILE "ifneq (\$(USER_DIR),\$(MAKE_DIR))\n";
print MAKEFILE " \@\$(error You must invoke this Makefile from its directory)\n";
print MAKEFILE "endif\n";
print MAKEFILE "#-\n";
print MAKEFILE "#-Q- sxdkrz F_O = \$(F_D) \$(F_P) -C vsafe -size_t64 -I \$(MODDIR)\n";
print MAKEFILE "#-Q- eshpux F_O = \$(F_D) \$(F_P) -C vsafe -I \$(MODDIR)\n";
print MAKEFILE "#-Q- sx8brodie F_O = \$(F_D) \$(F_P) -I \$(MODDIR)\n";
print MAKEFILE "#-Q- sx6nec F_O = \$(F_D) \$(F_P) -size_t64 -Wf\,\"-pvctl loopcnt=999999\" -I \$(MODDIR)\n";
print MAKEFILE "#-Q- sx8mercure F_O = \$(F_D) \$(F_P) -size_t64 -Wf\,\"-pvctl loopcnt=999999\" -I \$(MODDIR)\n";
print MAKEFILE "#---------------------------------------------------------------------\n";
print MAKEFILE "#- Create libxmlf90\n";
print MAKEFILE "#---------------------------------------------------------------------\n\n";

print MAKEFILE ".PRECIOUS : \$(MODEL_LIB)\n";
print MAKEFILE "SXMODEL_LIB = \$(MODEL_LIB)\n";
print MAKEFILE "ifeq (\$(L_X),1)\n";
print MAKEFILE "SXMODEL_LIB = \$(LIBDIR)/libsxxmlf90.a\n";
print MAKEFILE ".PRECIOUS : \$(SXMODEL_LIB)\n";
print MAKEFILE "endif\n\n";

# Source listing
#
print MAKEFILE "MODS1 =\t";
@srcs = < ../*/*/*.f90 >;
&PrintWords(8, 0, @srcs);
print MAKEFILE "\n\n";
#
# Object listing
#
print MAKEFILE "OBJSMODS1 =\t";
@objs =  @srcs;
foreach (@objs) { s/\.[^.]+$/.o/ };
         foreach $objs (@objs) {
         @tab = split('/', $objs);
         $objs = $tab[$#tab] ;
         };

&PrintWords(8, 0, @objs);
print MAKEFILE "\n\n";
#
# Define common macros
#
#print MAKEFILE "LIBS =\t\n\n";
#print MAKEFILE "CC = cc\n";
#print MAKEFILE "CFLAGS = -O\n";
#print MAKEFILE "FC = f77\n";
#print MAKEFILE "FFLAGS = -O\n";
#print MAKEFILE "F90 = f90\n";
#print MAKEFILE "F90FLAGS = -O\n";
#print MAKEFILE "LDFLAGS = -s\n\n";
#
# make
#
print MAKEFILE "all: dirxml \$(MODEL_LIB)(\$(OBJSMODS1))\n";
print MAKEFILE "\t\@echo XMLF90 is OK\n\n";

# .f90 -> .o
#

print MAKEFILE "\$(MODEL_LIB)(%.o): ../*/*/%.f90\n";
print MAKEFILE "\t\$(F_C) \$(F_O) -I\$(NCDF_INC) \$<\n";
print MAKEFILE "\t\$(A_C) \$(MODEL_LIB) \$*.o\n";
print MAKEFILE "ifeq (\$(L_X),1)\n";
print MAKEFILE "\t\$(A_X) \$(SXMODEL_LIB) \$*.o\n";
print MAKEFILE "endif\n";
print MAKEFILE "#-Q- sgi6       mv \$(shell echo \$* | tr '[:lower:]' '[:upper:]').mod \$(MODDIR)\n";
print MAKEFILE "ifeq (\$(M_M),1)\n";
print MAKEFILE "\t\@mv -f *.mod \$(MODDIR)  2> /dev/null || true\n";
print MAKEFILE "endif\n";
print MAKEFILE "\t\$(RM) \$*.o\n\n";;


print MAKEFILE "dirxml: \n";
print MAKEFILE "\t\@if [ ! -d ../../../lib/libxmlio_server ] ; then mkdir ../../../lib/libxmlio_server ; fi\n\n";
#
# make clean
#
print MAKEFILE "clean:\n";
print MAKEFILE "\t\$(RM) *.*~ Makefile~ core *.o *.mod i.*.L *.L\n";
print MAKEFILE "\t\$(RM)  \$(MODEL_LIB) \n\n";
#
#
# Dependency listings
#
&MakeDependsf90($ARGV[1]);
&MakeDepends("*.f *.F", '^\s*include\s+["\']([^"\']+)["\']');
&MakeDepends("*.c",     '^\s*#\s*include\s+["\']([^"\']+)["\']');

#
# &PrintWords(current output column, extra tab?, word list); --- print words
#    nicely
#
sub PrintWords {
   local($columns) = 78 - shift(@_);
   local($extratab) = shift(@_);
   local($wordlength);
   #
   print MAKEFILE @_[0];
   $columns -= length(shift(@_));
   foreach $word (@_) {
      $wordlength = length($word);
      if ($wordlength + 1 < $columns) {
         print MAKEFILE " $word";
         $columns -= $wordlength + 1;
         }
      else {
         #
         # Continue onto a new line
         #
         if ($extratab) {
            print MAKEFILE " \\\n\t\t$word";
            $columns = 62 - $wordlength;
            }
         else {
            print MAKEFILE " \\\n\t$word";
            $columns = 70 - $wordlength;
            }
         }
      }
   }

#
# &LanguageCompiler(compiler, sources); --- determine the correct language
#    compiler
#
sub LanguageCompiler {
   local($compiler) = &toLower(shift(@_));
   local(@srcs) = @_;
   #
   if (length($compiler) > 0) {
      CASE: {
         grep(/^$compiler$/, ("fc", "f77")) &&
            do { $compiler = "FC"; last CASE; };
         grep(/^$compiler$/, ("cc", "c"))   &&
            do { $compiler = "CC"; last CASE; };
         $compiler = "F90";
         }
      }
   else {
      CASE: {
         grep(/\.f90$/, @srcs)   && do { $compiler = "F90"; last CASE; };
         grep(/\.(f|F)$/, @srcs) && do { $compiler = "FC";  last CASE; };
         grep(/\.c$/, @srcs)     && do { $compiler = "CC";  last CASE; };
         $compiler = "???";
         }
      }
   $compiler;
   }

#
# &toLower(string); --- convert string into lower case
#
sub toLower {
   local($string) = @_[0];
   $string =~ tr/A-Z/a-z/;
   $string;
   }

#
# &uniq(sorted word list); --- remove adjacent duplicate words
#
sub uniq {
   local(@words);
   foreach $word (@_) {
      if ($word ne $words[$#words]) {
         push(@words, $word);
         }
      }
   @words;
   }

#
# &MakeDepends(language pattern, include file sed pattern); --- dependency
#    maker
#
sub MakeDepends {
   local(@incs);
   local($lang) = @_[0];
   local($pattern) = @_[1];
   #
   foreach $file (<${lang}>) {
      open(FILE, $file) || warn "Cannot open $file: $!\n";
      while (<FILE>) {
         /$pattern/i && push(@incs, $1);
         }
      if (defined @incs) {
         $file =~ s/\.[^.]+$/.o/;
         @tab = split('/', $file);
         $file = '$(MODEL_LIB)(' . $tab[$#tab] . ')' ;
         print MAKEFILE "$file: ";
         &PrintWords(length($file) + 2, 0, @incs);
         print MAKEFILE "\n";
         undef @incs;
         }
      }
   }

#
# &MakeDependsf90(f90 compiler); --- FORTRAN 90 dependency maker
#
sub MakeDependsf90 {
   local($compiler) = &toLower(@_[0]);
   local(@dependencies);
   local(%filename);
   local(@incs);
   local(@modules);
   local($objfile);
   #
   # Associate each module with the name of the file that contains it
   #
   foreach $file (<../*/*/*.f90>) {
      open(FILE, $file) || warn "Cannot open $file: $!\n";
      while (<FILE>) {
         /^\s*module\s+([^\s!]+)/i &&
            ($filename{&toLower($1)} = $file) =~ s/\.f90$/.o/;
         }
      }
   #
   # Print the dependencies of each file that has one or more include's or
   # references one or more modules
   #
   foreach $file (<../*/*/*.f90>) {
      open(FILE, $file);
      while (<FILE>) {
         /^\s*include\s+["\']([^"\']+)["\']/i && push(@incs, $1);
         /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1));
         }
      if (defined @incs || defined @modules) {
         ($objfile = $file) =~ s/\.f90$/.o/;
         @tab = split('/', $objfile);
         $objfile = '$(MODEL_LIB)(' . $tab[$#tab] . ')' ;

         print MAKEFILE "$objfile: ";
         undef @dependencies;
         foreach $module (@modules) {
            push(@dependencies, $filename{$module});
            }
         @dependencies = &uniq(sort(@dependencies));

         foreach $dependencies (@dependencies) {
         @tab = split('/', $dependencies);
         $dependencies = '$(MODEL_LIB)(' . $tab[$#tab] . ')';
         }

         &PrintWords(length($objfile) + 2, 0,
                     @dependencies, &uniq(sort(@incs)));
         print MAKEFILE "\n";
         undef @incs;
         undef @modules;
         #
         #
         }
      }
   }
