#!/opt/local/bin/perl
#!/usr/local/bin/perl
#
# Get list of fortran source and header files:
#
system("/bin/ls -1 *.f *.F > Srcfiles");
open(SRCFILES,"< Srcfiles") || die "$0: Could not open Srcfiles\n";
while (<SRCFILES>) {
  chop;
  push(@srcfiles,$_);
}
#
# Get list of modules contained in each source file:
# (modules is assoc array w/ each source file as the
#  key, and a list of module(s) defined in that source 
#  as the values)
#
%modules = &find_modules(@srcfiles);
#
# Open output file:
open(DEPENDS,"> Depends") || die "$0: Can't open output file Depends\n";
open(OBJECTS,"> Objects") || die "$0: Can't open output file Objects\n";
print OBJECTS "OBJS = ";
#
# Loop through each source file, find modules used by each
#   source, and build file dependencies.
# module_deps: list of modules used by current source file
# file_deps: list of file dependencies of current source
#   (i.e., objects (.o) of files containing modules used)
#
foreach $srcfile (@srcfiles) {
  open(SRCFILE,"< $srcfile") || die "$0: Error opening file $srcfile.\n";
  undef(@module_deps);	# module dependencies for each source file
  undef(@include_deps);	# include dependencies for each source file
  undef(@file_deps);	# file dependencies for each source file
#
# Add dot-o file name to OBJECTS file:
  $doto = $srcfile; $doto =~ s/\.[fF]$/\.o/; 
  print OBJECTS "$doto\t";
#
# Build list of modules used:
  while (<SRCFILE>) {
#
# Fixed source style use statement:
    if (/^      use (\w*)/) {
      $module = $1;
#
# Check for "use module,only: xyz": 
      if ($module =~ /(\w*[^,])[,]/) { $module = $1; } 
      if (&findmember($module,@module_deps) < 0) {
        push(@module_deps,$module);
      }
    }
#
# Check for include statements:
#
# Fortran style include statement:
    if ( /^\s+include\s+[<"'](.*)[>"']/ ) {
      $hdrfile = $1;
      if (&findmember($hdrfile,@include_deps) < 0) {
        push(@include_deps,$hdrfile);
      }
    }
#
# cpp style include statement:
    if ( /^#include\s+[<"'](.*)[>"']/ ) {
      $hdrfile = $1;
      if (&findmember($hdrfile,@include_deps) < 0) {
        push(@include_deps,$hdrfile);
      }
    }
  }   # end reading srcfile
#
# Find file dependencies (i.e., files containing the module(s)
#   used by the source file):
#
  if (@module_deps) {
    foreach $module (@module_deps) {
#
# Find source file that defines $module:
      undef($filedep);
      foreach $src (@srcfiles) {
        @modules_in_src = split(' ',$modules{$src});
        if (&findmember($module,@modules_in_src) >= 0) {
          $filedep = $src; $filedep =~ s/\.[fF]$/\.o/; 
          push(@file_deps,$filedep);
        }
      }
      if (! $filedep) {
        print "WARNING: could not find module $module (used by source file $srcfile)\n";  
      }
    }
  }
#
# Add included header files to list of dependencies:
#
  if (@include_deps) {
    foreach $hdrfile (@include_deps) {
      if (-e $hdrfile) { 
        push(@file_deps,$hdrfile); 
      } else {
#       print "WARNING: could not find header file $hdrfile (included by source file $srcfile)\n";
      }
    }
  }
  close($srcfile);
#
# Write file dependencies to output file:
#
  $srcobj = $srcfile; $srcobj =~ s/\.[fF]$/\.o/; 
  print DEPENDS "$srcobj: @file_deps\n";
}	# each srcfile
print OBJECTS "\n";
close(OBJECTS);
close(DEPEND);
#-------------------------------------------------------------------------
sub find_modules {
#
# Given list of source files, return associative array with
# each source file as the key and the module(s) it contains the
# as the values.
#
  local (@srcfiles) = @_;
  local ($srcfile,*SRCFILE,$modules);
#
  foreach $srcfile (@srcfiles) {
    open(SRCFILE,"< $srcfile") || 
      die "sub module_files: Error opening file $srcfile.\n";
    while (<SRCFILE>) {
      if (/^      module (.*)/) {
        $modules{$srcfile} .= $1 . ' ';
      }
    }
  }
  return %modules;
}
#-------------------------------------------------------------------------
sub findmember {
#
# Given a string $member, and a list @list, search for $member in @list
# and if found return index of $member in @list, otherwise return -1:
#
# (Note this routine also in $TGCMROOT/bin/util.pl)
#
  local ($member,@list) = @_;
  local ($offset);
  $offset = 0;
  foreach $ele (@list) {
    if ($ele eq $member) {
      return $offset
    }
    $offset++;
  }
  $offset = -1;
  return $offset;
}
