#! /bin/ksh # # Usage : Create_dependencies.pl 'modelname' 'source code directory' # # Limits: the name of the file which contains a module # and the module name must be the same. # # Functionality: # # The script.. # # 1.) checks all files in 'source code directory' ('scd') for # inclusion of header files (#include or INCLUDE) # or usage of Fortran modules. # 2.) It outputs for each file in 'scd' a dependency record with prerequisites # ('header file name' or 'module name'.o) for use in the Makefile of 'scd' # if any dependency was found. # 3.) It checks for all prerequisites whether the file (for header files) or # a 'module name'.[f,F][90] resides in 'scd' # 4.) Those which do not reside in 'scd' are searched in all other # source code directories at the same directory tree level. # If directories with platform dependent code exist, only the relevant # directories are checked. # 5.) If not found in any of the other source code directories, # the file is listed (e.g. psmile routines, platform dependent # include (header) files # 6.) If found, a 2nd level dependency check is done: # 7.) The 2nd level dependency check includes steps # 2.) for the prerequisites already found # 3.) checks for all prerequisites whether there reside in the same dir # 4.) Those which do not reside in 'scd' are searched in all other # source code directories at the same directory tree level. # 5.) If not found in any of the other source code directories, # the file is listed # 6.) If found new prerequisites are added # 8.) For some model another iteration is added # 9.) Finally, # - directories other than 'scd' are listed for inclusion in the VPATH # parameter of Makefile_1 if needed # - a list with unresolved dependencies is given. # # Unresolved dependencies may be resolved manually # (e.g. prism_kind_proto in the component models) and # listed in Makefile_1. They will not be lost with the new # creation of 'Makefile' since the dependency are appended. # # # Two command line parameters are mandatory # if [ "$2" = "" ] ; then echo '***************************************************************' echo '* ' echo '* This script must be called with 2 parameters:' echo '* 1. model name (directory name of the model source code)' echo '* 2. source code subdirectory for which to create the Makefile ' echo '* One or both of the parameters is empty!' echo '* The script is stopped!' echo '* ' echo '* A 3rd parameter (nodename for a valid PRISM site) is optional.' echo '* ' echo '***************************************************************' exit 1 fi # # Set 3rd parameter (processor type) for MOZART # if [ "$1" = "mozart" ]; then node=`uname -n` if [ ! "$3" = "" ]; then node=$3 fi node12=`echo $node | cut -c1-2` node13=`echo $node | cut -c1-3` node14=`echo $node | cut -c1-4` if [ "$node12" = "ds" ]; then proctype=vector elif [ "$node" = "dcm13" ]; then proctype=cache elif [ "$node" = "dcm23" ]; then proctype=cache elif [ "$node" = "elnino" ]; then proctype=cache elif [ "$node14" = "hpca" ]; then proctype=cache elif [ "$node12" = "p1" ]; then proctype=cache elif [ "$node14" = "xbar" ]; then proctype=vector elif [ "$node" = "SFV800" ]; then proctype=vector else echo Unknown site! echo The script is stopped! fi fi scriptname=`basename $0` scriptdirec=`dirname $0` perlname=`which perl | grep /perl` export perlname cat > ${scriptname}.pl << EOF #!$perlname EOF cat >> ${scriptname}.pl << \EOF # # Based on createMakefiles.pl by # Uwe Schulzweida June, 1999 # Stephanie Legutke, MPI M&D Oct 2003 # - loop on all source code directories for prerequisites # at the 2nd level # Stephanie Legutke, MPI M&D June 2004 # - '# include' (with blanks allowed) # - 3rd level check added June 2004 # #################################################################### $PROG=`basename $0`; $scriptdir=@ARGV[0]; $modname=@ARGV[1]; $dir=@ARGV[2]; $proctype=@ARGV[3]; # # Print directories # $presdir=`pwd`; chdir $presdir; chdir $scriptdir; $scriptdir=`pwd`; chdir "../../src/mod/"; $srcdir=`pwd`; # # Check whether valid model # if ( ! -d $modname ) { print "******************************************************** \n"; print "*\n"; print "* This script must be called with 2 parameters:\n"; print "* 1. model name (directory name of the model source code \n"; print "* (all lower case))\n"; print "* 2. source code subdirectory (for which to create make \n"; print "* dependencies) \n"; print "* The first parameter is not a valid model name:\n"; print "* model name = $modname\n"; # Create list of models. opendir (MODDIR, "."); foreach $file (readdir(MODDIR)) { if ( -d $file ) { ($nfile = $file) =~ (s/^\.//) ; if ( ("$file" eq "$nfile") ) { push (@modlist, $file); } } } close (MODDIR); print "* Valid models are : @{modlist}\n"; print "*\n"; print "******************************************************** \n"; exit; } chop(${srcdir}); $moddir="${srcdir}/".${modname}; print "********************************************************\n"; print "* Source root directory : $srcdir\n"; print "* Model name : $modname\n"; chdir $modname; # # Processor type dependent strings for selection of directories # $string1=" "; $string2=" "; if ( "$modname" eq "mozart" ) { if ( "$proctype" eq "vector" ) { $string1="cache"; $string2="scalar"; print "* Makefile dependencies will be created for a vector processor \n"; print "* maschine from the vector-directories.\n"; } if ( "$proctype" eq "cache" ) { $string1="vector"; $string2="scalar"; print "* Makefile dependencies will be created for a cache processor \n"; print "* maschine from the cache-directories.\n"; } if ( "$proctype" eq "scalar" ) { $string1="cache"; $string2="scalar"; print "* Makefile dependencies will be created for a scalar processor \n"; print "* maschine from the scalar-directories.\n" } } # # List of source code directories # (For compilation of mozart exclude # the $string1 and $string2 directories.) # undef @dirlist; opendir (MODDIR, "."); foreach $file (readdir(MODDIR)) { if ( -d $file ) { ($nfile = $file) =~ (s/^\.//) ; ($n1file = $nfile ) =~ (s/$string1//) ; ($n2file = $n1file ) =~ (s/$string2//) ; if ( ( "$file" ne "doc" ) && ("$file" eq "$n2file") ) { push (@dirlist, $file); } } } close (MODDIR); # if ( "$modname" eq "mozart" ) { if ( ( $dir eq "" ) || ( ! -d $dir )) { print "******************************************************** \n"; print "*\n"; print "* This script must be called with 2 parameters:\n"; print "* 2. source code subdirectory \n"; print "* (for which to create Makefile dependencies) \n"; print "* The specified vakue is not a valid directory name.\n"; print "* Valid directories are : @{dirlist}\n"; print "*\n"; print "******************************************************** \n"; exit; } #} print "* Create dependencies for Makefile in source code directory : $dir\n"; # # Work on directory @ARGV[1]; can be changed in a loop on @dirlist later # chdir $dir; # # Check for Makefile_1 # $file="Makefile_1"; if ( ! (-f $file) ) { print "* No Makefile_1 in directory $dir !!\n"; exit; } # # Remove old Makefile # $file="Makefile"; if ( -f $file ) { unlink ($file); } # # Open new Makefile # open(DEPENDS, ">> Makefile"); print DEPENDS "\n"; print DEPENDS "# This file is generated automatically\n"; # # Copy body of Makefile # open(MAKEBODY, "Makefile_1"); while ( ( $line = ) && ( "$line" ne "# Dont add anything behind this line\n" ) ) { print DEPENDS "$line"; } print DEPENDS "\n"; close(MAKEBODY); # # Create dependency listings (dirlist=all directories) # &MakeDepends(@{dirlist}); chdir ".."; chdir @ARGV[2]; # # Add more iteration # $times=0; if ( @ARGV[1] eq "mozart" && @ARGV[2] eq "base" ) { $times=2; } if ( @ARGV[1] eq "mozart" && @ARGV[2] eq "base_vector") { $times=2; } if ( @ARGV[1] eq "mozart" && @ARGV[2] eq "chem" ) { $times=1; } if ( @ARGV[1] eq "mozart" && @ARGV[2] eq "chem_vector") { $times=1; } foreach $time ( 1 .. $times ) { print "* Add Second Iteration\n"; &AddDepends(@{Dirlist}); chdir ".."; chdir @ARGV[2]; rename(Makefile_new,Makefile); } exit; ############################################################################ # # Usage &MakeDepends(@dirlist); # @_ = @dirlist = $directories # @directories: list of all model directories (excl. 'doc') # $presdir: present directory # @dirs: list of all model directories (excl. 'doc' and present) # %Filename: key=module name of Fortran files in present directory # value= file name (no .h file) # %dotOname: key=module name of Fortran files in present directory # value= $Filename.o (no .h file) # for each $file in present directory: @modules list of modules used # @incs list of files included # for each $file in present directory: $objfile=$Filename.o (.h unchanged) # # sub MakeDepends { local(@dependencies); local(%dotOname); local(%Filename); local(@incs); local(@modules); local(@directories); local($objfile); @directories = @_ ; # # Eliminate present directory $presdir from directory list # $presdir=`pwd`; $presdir=`basename $presdir`; chop($presdir); foreach $dir (@directories) { if ( $dir ne $presdir ) { push(@dirs, $dir); } } # # Associate each module with the name of the file (%Filename) it is contained in. # foreach $file (<*.F90 *.f90 *.F *.f>) { open(FILE, $file) || warn "Cannot open $file: $!\n"; while () { /^\s*module\s+([^\s!]+)/i && ($Filename{&toLower($1)} = $file) ; } close (FILE); } # # Replace Fortran suffixes with '.o' in (%dotOname) # while (($key,$vari) = each(%Filename)) { ($dotOname{$key}=$Filename{$key}) =~ s/\.[f,F].*$/.o/i; } # # Note: according to PRISM coding rules filename must be module name # while (($key,$vari) = each(%Filename)) { ($testname=$Filename{$key}) =~ s/\.[f,F].*$//i; if (&toLower($testname) ne $key && $key ne "procedure") { print " File/Module name: ${Filename{$key}} , $key\n"; print " This is not allowed! \n"; } } # # Loop on files in present directory for dependency search # foreach $file (<*.F90 *.f90 *.F *.f *.c *.h>) { # # Get object file name (Fortran and c, .h file names remain unchanged) # references one or more modules # ($objfile = $file) =~ s/\.[f,F].*$/.o/i; ($objfile = $objfile) =~ s/\.c$/.o/; open(FILE, $file); while () { /^\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*#\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1)); } if (defined @incs && $#incs < 0) {undef @incs;} undef @redmodules; if (defined @modules) { foreach $mod (@modules) { if ("&toLower($objfile)" ne "&toLower($dotOname{$mod})") { push(@redmodules,$mod); } else { print "* => reflective use: $objfile: $mod\n"; } } } @modules=@redmodules; # # Add .o- name for modules not in present directories (needs refinement) # foreach $mod (@modules) { if ( ${dotOname{$mod}} eq "" ) { ${dotOname{$mod}}=$mod."\.o"; } } if (defined @modules && $#modules < 0) {undef @modules;} # # If dependecies or includes are present ... # if (defined @incs || defined @modules) { # # ...but not in present directory: list file name @otherincs/@othermods # foreach $inc (@incs) { open(INC, $inc) || push(@otherincs, $inc); } foreach $mod (@modules) { open(MOD, $Filename{$mod}) || push(@othermods, $mod); } # # ... add line do Makefile (present dir only) # # # Define dotOname (@modules)??? # print DEPENDS "$objfile: "; undef @dependencies; foreach $module (@modules) { push(@dependencies, $dotOname{$module}); } @dependencies = &uniq(sort(@dependencies)); &PrintWords(length($objfile) + 2, 0, @dependencies, &uniq(sort(@incs))); print DEPENDS "\n"; undef @incs; undef @modules; } } # # End of loop on files in present directory for dependency search # @remainincs = &uniq(sort(@otherincs)); @remainmods = &uniq(sort(@othermods)); if ( defined @otherincs ) { print "* \n"; $no_remincs=@remainincs; $ele_1=0; $ele_2=0; print "* Included files not in present directory:\n"; until ( $ele_2 > $no_remincs ) { $ele_2=$ele_1 + 3; print " @remainincs[$ele_1 .. $ele_2]\n"; $ele_1=$ele_2 + 1; } } if ( defined @othermods ) { print "* \n"; $no_remmods=@remainmods; $ele_1=0; $ele_2=0; print "* Used modules not in present directory: \n"; until ( $ele_2 > $no_remmods ) { $ele_2=$ele_1 + 3; print " @remainmods[$ele_1 .. $ele_2]\n"; $ele_1=$ele_2 + 1; } } if ( defined @othermods || defined @otherincs ) { print "* \n"; print "* They are searched in the other directories,\n"; print "* i.e. in \"@dirs\"\n"; print "* \n"; print "* Warning: In this 2nd iteration it will not be checked whether \n"; print "* the files included or the modules used in these files \n"; print "* exist in the present or in any of the model directories.\n"; print "* To do this another iteration (not a rerun) would be needed!\n"; } # # Loop on other directories for file search # # # Do the included files first... # foreach $dir (@dirs) { chdir ".." ; chdir $dir; undef @restincs; foreach $file (@remainincs) { open(FILE, $file) || push(@restincs, $file); undef @incs; undef @modules; while () { /^\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*#\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1)); push(@vpathdirs,$dir); } $objfile = $file; if (defined @incs && $#incs < 0) {undef @incs;} if (defined @modules && $#modules < 0) {undef @modules;} foreach $mod (@modules) { if ( ${Filename{$mod}} eq "" ) { ${dotOname{$mod}}=$mod."\.o"; } } if (defined @incs || defined @modules) { print DEPENDS "$objfile: "; undef @dependencies; foreach $mod (@modules) { push(@dependencies, $dotOname{$mod}); } @dependencies = &uniq(sort(@dependencies)); &PrintWords(length($objfile) + 2, 0, @dependencies, &uniq(sort(@incs))); print DEPENDS "\n"; undef @incs; undef @modules; } } @remainincs = &uniq(sort(@restincs)); } @vpathdirs = &uniq(sort(@vpathdirs)); if ( $#vpathdirs >= 0) { print "* Header file directories to be included in VPATH: \"@vpathdirs\"\n"; } # # Do the uses then ... # undef @vpathdirs; foreach $dir (@dirs) { undef @restmods; chdir ".." ; chdir $dir; $vpath="no"; foreach $Mod (@remainmods) { ${Filename{$Mod}}=""; foreach $file (<*.F90 *.f90 *.F *.f>) { ($File = $file) =~ s/\.[f,F].*$// ; if (&toLower($File) eq $Mod) { ${Filename{$Mod}}=$file; } } if (${Filename{$Mod}} eq "") { push(@restmods, $Mod); } else { $vpath="yes"; open(FILE, ${Filename{$Mod}}); undef @incs; undef @modules; while () { /^\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*#\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1)); } $objfile = $Mod."\.o"; if (defined @incs && $#incs < 0) {undef @incs;} if (defined @modules && $#modules < 0) {undef @modules;} if (defined @incs || defined @modules) { print DEPENDS "$objfile: "; undef @dependencies; foreach $mod (@modules) { push(@dependencies, $mod."\.o"); } @dependencies = &uniq(sort(@dependencies)); &PrintWords(length($objfile) + 2, 0, @dependencies, &uniq(sort(@incs))); print DEPENDS "\n"; undef @incs; undef @modules; } } } @remainmods = &uniq(sort(@restmods)); if ( $vpath eq "yes" ) { push(@vpathdirs,$dir); } } if ( $#vpathdirs >= 0) { print "*\n"; print "* Directories to be included in VPATH: \"@vpathdirs\"\n"; } if ( $#remainincs >= 0) { print "*\n"; print "* Included files not found at all: \"@remainincs\"\n"; } if ( $#remainmods >= 0) { print "*\n"; print "* Used modules not found at all: \"@remainmods\"\n"; } print "*\n"; print "* Note: The *prism*/*clim* modules reside in the libraries \n"; print "* \"psmile\"/\"clim\". They are always compiled before \n"; print "* the model and therefore must be included in the INCL\n"; print "* variable only.\n"; print "*************************************************************\n"; } ############################################################################ # # Usage &AddDepends(@dirlist); # @_ = @dirlist = $directories # @directories: list of all model directories (excl. 'doc') # $presdir: present directory # @dirs: list of all model directories (excl. 'doc' and present) # @modules: list of modules used # @incs: list of files included # # Scan the already existing dependency-lines of Makefile and check # each .o prerequisite whether it implies # - new prerequisites and/or # - new dependency lines # # # # sub AddDepends { local(@dependencies); local(%dotOname); local(%Filename); local(@incs); local(@modules); local(@directories); local($objfile); @directories = @_ ; # # Scan the existing dependencies (line by line) and add prerequisites # close (DEPENDS); open(DEPENDS, "> Makefile_new"); # # Copy body of Makefile # $line=""; open(MAKEBODY, "Makefile"); while ( ( $line = ) && ( "$line" ne "# Dont add anything behind this line\n" ) ) { print DEPENDS "$line"; } print DEPENDS "\n"; # # Loop over all dependency lines ... # undef $fullline; undef @alltargets; undef $allprereqs; while ( $line = ) { # # Read full continued line ... # ( $nline = $line ) =~ ( s/\\// ) ; if ( ! ($nline eq $line) ) { chop ($nline); $fullline="$fullline".$nline; } if ( $nline eq $line ) { chop ($nline); $fullline="$fullline".$nline; # # Work on full line ... ( $target = $fullline ) =~ ( s/:.*$// ); push (@alltargets,$target); ( $reqline = $fullline ) =~ ( s/.*:// ); ( $reqs = $reqline ) =~ (s/\.h//g); ( $reqs = $reqline ) =~ (s/\.o//g); @prereqs = split(' ',$reqs); undef $fullline; # # Loop over prerequisites and extend with new prerequisites undef @incs; undef @modules; # # Loop over other directories other than present ... $scalar=@prereqs.""; $remains=join(" ",@prereqs); until ( $scalar eq 0 ) { $new_name=shift(@prereqs); $scalar=@prereqs.""; foreach $dir (@directories) { chdir ".." ; chdir $dir; foreach $file (<*.F90 *.f90 *.F *.f *.c *.h>) { ( $file_basename = $file ) =~ s/\.[f,F,c,h].*$//i; if ( $new_name eq $file_basename ) { open(FILE, $file) || warn "Cannot open $file: $!\n"; while () { /^\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*#\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1)); } } } } } # # Append to prerequisites list @reqlist=split(" ",$reqline); foreach $newmod (@modules) { push(@reqlist, $newmod."\.o"); } foreach $newinc (@incs) { push(@reqlist, $newinc); } # # Sorting and elimination of doubly defined prerequisites @reqlist = &uniq(sort(@reqlist)); # # Write rule to Makefile_new $rule=join(" ",@reqlist); $allprereqs = $allprereqs.$rule." "; $rule=$target.": ".$rule; $target=$target.": "; print DEPENDS "$target"; undef @incs; &PrintWords(length($target) + 2, 0, @reqlist, @incs ); print DEPENDS "\n"; } } # # Check whether new targets popped up ... @alltargets = &uniq(sort(@alltargets)); @allprereqs = split (" ",$allprereqs); @allprereqs = &uniq(sort(@allprereqs)); # # Subtract targets from list of all prerequisites $count=@alltargets; until ( ( $count == 0 ) || ( $#allprereqs == 0 ) ){ if ($allprereqs[0] eq $alltargets[0] ) { $junk=shift (@alltargets); $junk=shift (@allprereqs); } if ($allprereqs[0] gt $alltargets[0] ) { $junk=shift (@alltargets); } if ($allprereqs[0] lt $alltargets[0] ) { push(@prereqs_left,$allprereqs[0]); $junk=shift (@allprereqs); } $count=@alltargets; } # # If new targets popped up ... $scalar=@prereqs_left.""; #26 $remains=join(" ",@prereqs_left); # print "* Having $scalar new targets : $remains \n"; until ( $scalar eq 0 ) { $target=shift(@prereqs_left); # print "* Target= $target\n"; $scalar=@prereqs_left.""; undef @modules; undef @incs; foreach $dir (@dirs) { chdir ".." ; chdir $dir; foreach $file (<*.F90 *.f90 *.F *.f *.c *.h>) { ( $file_basename = $file ) =~ s/\.[f,F,c,h].*$//; ( $new_name = $target ) =~ s/\.[o,h]$//; if ( $new_name eq $file_basename ) { open(FILE, $file) || warn "Cannot open $file: $!\n"; while () { /^\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1); /^\s*#\s*include\s*["\']([^"\']+)["\']/i && push(@incs, $1.".h"); /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1.".o")); } } } if ( defined @incs || defined @modules) { @modules=&uniq(sort(@modules)); @incs=&uniq(sort(@incs)); $target=$target.": "; print DEPENDS "$target"; &PrintWords(length($target) + 2, 0, @modules, @incs ); print DEPENDS "\n"; undef @modules; undef @incs; } } } close (DEPENDS); } ############################################################################ # # &PrintWords(current output column, extra tab?, word list); --- print words # nicely # sub PrintWords { local($columns) = 78 - shift(@_); local($extratab) = shift(@_); local($wordlength); # print DEPENDS @_[0]; $columns -= length(shift(@_)); foreach $word (@_) { $wordlength = length($word); if ($wordlength + 1 < $columns) { print DEPENDS " $word"; $columns -= $wordlength + 1; } else { # # Continue onto a new line # if ($extratab) { print DEPENDS " \\\n\t\t$word"; $columns = 62 - $wordlength; } else { print DEPENDS " \\\n\t$word"; $columns = 70 - $wordlength; } } } } ############################################################################ # # &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 #@others = &uniq(sort(@others) sub uniq { local(@words); foreach $word (@_) { if ($word ne $words[$#words]) { push(@words, $word); } } @words; } EOF chmod 755 ${scriptname}.pl ./${scriptname}.pl $scriptdirec "$1" "$2" $proctype rm ${scriptname}.pl exit