#!/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 "F_O := \$(F_O) -I../../../lib\n";
print MAKEFILE "P_O := \$(P_O) -traditional\n";
print MAKEFILE "#---------------------------------------------------------------------\n";
print MAKEFILE "#- Create libioserver and libxmlio\n";
print MAKEFILE "#---------------------------------------------------------------------\n\n";

print MAKEFILE ".PRECIOUS : \$(MODEL_LIB1) \$(MODEL_LIB2)\n";
print MAKEFILE "SXMODEL_LIB1 = \$(MODEL_LIB1)\n";
print MAKEFILE "SXMODEL_LIB2 = \$(MODEL_LIB2)\n";
print MAKEFILE "ifeq (\$(L_X),1)\n";
print MAKEFILE "SXMODEL_LIB1 = \$(LIBDIR)/libsxioserver.a\n";
print MAKEFILE "SXMODEL_LIB2 = \$(LIBDIR)/libsxxmlio.a\n";
print MAKEFILE ".PRECIOUS : \$(SXMODEL_LIB1) \$(SXMODEL_LIB2)\n";
print MAKEFILE "endif\n\n";

# Source listing
#IOSERVER
print MAKEFILE "MODS1 =\t";
@srcs = < ../src/IOSERVER/*.F90 ../src/IOSERVER/*.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] ;
         if( "$objs" eq 'server.o' ){
         $objs = ''};
         };
         
&PrintWords(8, 0, @objs);
print MAKEFILE "\n\n";

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

&PrintWords(8, 0, @objs);
print MAKEFILE "\n\n";

#
# make
#
print MAKEFILE ".SUFFIXES: .f90 .F90\n\n";

print MAKEFILE "all: libioipsl libxmlf90 dirxml \$(MODEL_LIB2)(\$(OBJSMODS2)) \$(MODEL_LIB1)(\$(OBJSMODS1)) server.o EXEC_BIN\n";
print MAKEFILE "\t\@echo IOSERVER is OK\n\n";

# Main program
print MAKEFILE "ifeq (\$(P_P),-DNO_MPI)\n";
print MAKEFILE "EXEC_BIN :\n";
print MAKEFILE "server.o :\n";
print MAKEFILE "else\n";
print MAKEFILE "EXEC_BIN : server.o\n";
print MAKEFILE "\t\$(F_L) \$(L_O) -o ../../../bin/server.exe server.o \$(MODEL_LIB1) \$(MODEL_LIB2) ../../../lib/libioipsl.a \$(NCDF_LIB) ../../../lib/libxmlio_server/libxmlf90.a\n";
print MAKEFILE "server.o :       ../src/IOSERVER/server.f90\n";
print MAKEFILE "\t\@\$(F_C) \$(F_O) -c ../src/IOSERVER/server.f90\n";
print MAKEFILE "endif\n\n";


# .f90 -> .o
#

print MAKEFILE "#Rules for ioserver\n";
print MAKEFILE "\$(MODEL_LIB1)(%.o): ../src/IOSERVER/%.f90\n";
print MAKEFILE "\t\$(F_C) \$(F_O) -I\$(NCDF_INC) \$<\n";
print MAKEFILE "\t\$(A_C) \$(MODEL_LIB1) \$*.o\n";
print MAKEFILE "ifeq (\$(L_X),1)\n";
print MAKEFILE "\t\$(A_X) \$(SXMODEL_LIB1) \$*.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 "#Rules for ioserver\n";
#print MAKEFILE "\$src/IOSERVER/%.f90: ../src/IOSERVER/%.F90\n";
#print MAKEFILE "\t@\$(P_C) \$(P_O) \$(P_P) src/IOSERVER/\$(*F).F90 > src/IOSERVER/\$(*F).f90\n\n";
print MAKEFILE "\$(MODEL_LIB1)(%.o): ../src/IOSERVER/%.F90\n";
print MAKEFILE "\t\$(F_C) \$(F_O) \$(P_P) -I\$(NCDF_INC) -I../src/IOSERVER \$<\n";
print MAKEFILE "\t\$(A_C) \$(MODEL_LIB1) \$*.o\n";
print MAKEFILE "ifeq (\$(L_X),1)\n";
print MAKEFILE "\t\$(A_X) \$(SXMODEL_LIB1) \$*.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 "#Rules for xmlio\n";
print MAKEFILE "\$(MODEL_LIB2)(%.o): ../src/XMLIO/%.f90\n";
print MAKEFILE "\t\$(F_C) \$(F_O) -I\$(NCDF_INC) -I../src/XMLIO \$<\n";
print MAKEFILE "\t\$(A_C) \$(MODEL_LIB2) \$*.o\n";
print MAKEFILE "ifeq (\$(L_X),1)\n";
print MAKEFILE "\t\$(A_X) \$(SXMODEL_LIB2) \$*.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";

print MAKEFILE "# IOIPSL library\n";
print MAKEFILE "libioipsl :\n";
print MAKEFILE "\t(cd ../../IOIPSL/src ; \$(M_K) -f Makefile )\n\n";

print MAKEFILE "# XMLF90 library\n";
print MAKEFILE "libxmlf90 :\n";
print MAKEFILE "\t(cd ../../XMLF90/external ; \$(M_K) -f Makefile )\n\n";

#
# make clean
#
print MAKEFILE "clean:\n";
print MAKEFILE "\t\$(RM) *.*~ Makefile~ core *.o *.mod i.*.L *.L\n";
print MAKEFILE "\t\$(RM) server.o \$(MODEL_LIB1) \$(MODEL_LIB2)\n\n";
#
#
# Dependency listings
#
&MakeDependsf90($ARGV[1],IOSERVER,MODEL_LIB1);
&MakeDependsf90($ARGV[1],XMLIO,MODEL_LIB2);
&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);
   local($DIR) = @_[1];
   local($MODEL_LIB) = @_[2];
   #
   # 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/;
         }
      }
   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 (<../src/$DIR/*.f90 ../src/$DIR/*.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/;
         ($objfile = $file) =~ s/\.[fF]90$/.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] . ')';

             if( "$DIR" eq 'IOSERVER'  && "$dependencies" eq '$(MODEL_LIB1)(xmlio.o)' ) {
             	$dependencies = '$(MODEL_LIB2)'
#                $dependencies = ''

             }          
         }

         foreach $incs (@incs) {
         @tab = split('/', $incs);
         @incs = '../src' . '/' . $DIR. '/' . $tab[$#tab] ;
         }
        foreach $incs (@incs) {
             if( "$incs" eq '../src/IOSERVER/mpif.h' ||  "$incs" eq '../src/IOSERVER/VT.inc' ||  "$incs" eq  '../src/IOSERVER/ios_mpif.h' ) {
                $incs = '';
       }
       }

 

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