#!/usr/bin/perl -w # # Simple script for automatic dependency generation of (primarily) FORTRAN # and C programs. See usage() for more info. # # Notes # 1. Some files contain more than one module. When this occurs, the basename # of the .mod files will not necessarily match the basename of the source # file in which they are found. # 2. Because of #1, module dependencies must be made to the .mod file rather # than to the source or object file (since there may not be a source or # object file to match the module name). # 3. Because of #2, a line is added showing the dependency of the .mod file # to object file associated with the source file. # # REVISION HISTORY: # 25Feb2005 da Silva First crack. # 17Mar2006 da Silva Now it should work with more than 1 module per file # 28Nov2006 da Silva Fixed Include regular expression. # 03Mar2007 da Silva Fixed major bug with .mod dependencies; also revised # the include refular expression rule and added elsif's # for efficiency # 17Jul2008 Stassi Divided code into subs; use strict standards # 17May2011 Stassi Simplified .mod.o dependency #........................................................................ use strict; # global variables #----------------- my ($verbose, $outfile, $default); my ($script, $srcfn, $infile); my (%deps, $mstring); my ($base, $suffix); my ($ncase, $mcase); # main program #------------- { init(); read_input(); write_output(); } #======================================================================= # name - init # purpose - read input flags and parameters; determine file names; # set global variables #======================================================================= sub init { use File::Basename; use Getopt::Long; my ($writefile, $mncase, $ifilenm, $help); my ($name, $mod, $path); $script = basename($0); $writefile = 0; $outfile = ""; # command line options #--------------------- GetOptions("v" => \$verbose, "c" => \$writefile, "p=s" => \$mncase, "o=s" => \$outfile, "i=s" => \$ifilenm, "h" => \$help, "help" => \$help); usage() if $help; # determine name and mod case #---------------------------- # IMPORTANT: never change the line below as installation relies on it # for creating appropiate defaults for each compiler. default: $default = "fdp.mod"; #---------------------------- $ncase = "lower"; $mcase = "lower"; $mncase = $default unless $mncase; ($name, $mod) = split /\./, $mncase; $ncase = "upper" if ($name eq uc $name); $mcase = "upper" if ($mod eq uc $mod); # input file and input filename #------------------------------ $infile = shift @ARGV; die "$script: must supply input filename as input parameter." unless ($infile); # (NOTE: $ifilenm may differ from $infile) #----------------------------------------- $ifilenm = $infile unless $ifilenm; ($base,$path,$suffix) = fileparse($ifilenm,'\..*'); $srcfn = "$base$suffix"; # output dependency file #----------------------- if ($writefile) { $outfile = "$base.d" unless $outfile }; # initialize global variables #---------------------------- %deps = (); $mstring = ""; # string of space-delimited mod names } #======================================================================= # name - read_input # purpose - read the input file and extract list of dependencies # # key variables - # %deps : hash storing dependency names as keys # $mstring : string containing list of dependency names #======================================================================= sub read_input { my ($keyword, $name, @dummy); open INFILE, "< $infile" or die "$script: >>> Error <<< while opening input file: $infile: $!"; while () { chomp; s/^\s*//; # remove leading blanks s/\#\s*/\#/; # remove blanks between "#" and "include" ($keyword, $name, @dummy) = split /\s+/; if (/^\#include\s/ and $name) { $name =~ s/\"//g; $name =~ s/\'//g; $name =~ s///g; #--print $name; $deps{$name} = 1; } elsif (/^[Ii][Nn][Cc][Ll][Uu][Dd][Ee]\s/ and $name) { $name =~ s/\"//g; $name =~ s/\'//g; #--print $name; $deps{$name} = 1; } elsif (/^[Uu][Ss][Ee]\s/ and $name) { $name =~ s/;//g; $name =~ s/,.*//gi; $name = fix_mod("$name"); #--print $name; $deps{$name} = 1; } elsif (/^[Mm][Oo][Dd][Uu][Ll][Ee]\s/ and $name) { if (uc $name ne "PROCEDURE") { if ($mstring) { #-------------------------------------- # if not the first module found in file #-------------------------------------- print STDERR "fdp: extra module found in $srcfn: $name\n"; $mstring = $mstring . " "; } $mstring = $mstring . fix_mod("$name"); } } } close INFILE; } #======================================================================= # name - write_output # purpose - write the dependency file to disk or standard output #======================================================================= sub write_output { my $dep; # open output file #----------------- if ( $outfile ) { open(OUTFL, "> $outfile"); print STDERR "Building dependency file $outfile\n" if $verbose; } else { open(OUTFL, ">& STDOUT"); } # write to output file #--------------------- print OUTFL "$base.d : $srcfn\n"; if ($mstring) { print OUTFL "$mstring : $base.o\n" } print OUTFL "$base.o : $srcfn"; foreach $dep ( keys %deps ) { print OUTFL " $dep" unless ( $mstring =~ /\b$dep\b/ ); } print OUTFL "\n"; close OUTFL; } #======================================================================= # name - fix_mod # purpose - create modfile name with correct case for both root and # .mod extension #======================================================================= sub fix_mod { my ($name, $mod); $name = shift @_; if ($ncase eq "lower") { $name = lc $name; } else { $name = uc $name; } if ($mcase eq "lower") { $mod = "mod"; } else { $mod = "MOD"; } $name = "$name.$mod"; return $name; } #======================================================================= # name - usage # purpose - print usage message #======================================================================= sub usage { print <<"EOF"; NAME $script - a simple depency generator for C or FORTRAN SYNOPSIS $script OPTIONS file_name DESCRIPTION Finds #include, include, and use kind of dependencies and prints them to stdout. Use this script for automatic dependence generation within the ESMA building mechanism. OPTIONS -c Creates dependency file with extension .d instead of writing to stdout. -i filename Use filename for input file when creating rules; This is useful when the filename is different than the file_name input parameter, e.g. when the function goes through /bin/cpp -o filename Specifies name of output depency file name, default is same as source file with .d extension. -p case.case Because f90 does not specify the case of the compiled module files, the user may need to specify it with the -p option. For example, the simple f90 module module fdp end module fdp may compile to fdp.mod, FDP.mod, fdp.MOD or FDP.MOD. You specify -p fdp.mod for the compilers producing fdp.mod -p FDP.mod for the compilers producing FDP.mod etc. The default is fdp.mod -v verbose mode BUGS It does not yet handle nested include files. AUTHOR Arlindo da Silva, NASA/GSFC. EOF exit(1) }