| 1 | #! /usr/bin/perl | 
| 2 | # | 
| 3 | # Usage: makemake {<program name> {<F90 compiler or fc or f77 or cc or c>}} | 
| 4 | # | 
| 5 | # Generate a Makefile from the sources in the current directory.  The source | 
| 6 | # files may be in either C, FORTRAN 77, Fortran 90 or some combination of | 
| 7 | # these languages.  If the F90 compiler specified is cray or parasoft, then | 
| 8 | # the Makefile generated will conform to the conventions of these compilers. | 
| 9 | # To run makemake, it will be necessary to modify the first line of this script | 
| 10 | # to point to the actual location of Perl on your system. | 
| 11 | # | 
| 12 | # Written by Michael Wester <wester@math.unm.edu> December 27, 1995 | 
| 13 | # Cotopaxi (Consulting), Albuquerque, New Mexico | 
| 14 | # | 
| 15 | open(MAKEFILE, "> Makefile"); | 
| 16 | # | 
| 17 | print MAKEFILE "include Makefile.local\n\n"; | 
| 18 | print MAKEFILE "PROG =\t$ARGV[0]\n\n"; | 
| 19 | # | 
| 20 | # Allow Fortran 90 module source files to have extensions other than .f90 | 
| 21 | # | 
| 22 | $mod_ext = F90; | 
| 23 | @f90 = uniq(f90, $mod_ext); | 
| 24 | foreach (@f90) { s/^/*./ }; | 
| 25 | # | 
| 26 | # Source listing | 
| 27 | # | 
| 28 | print MAKEFILE "SRCS =\t"; | 
| 29 | @srcs = <@f90 *.f *.F *.c>; | 
| 30 | &PrintWords(8, 0, @srcs); | 
| 31 | print MAKEFILE "\n\n"; | 
| 32 | # | 
| 33 | # Object listing | 
| 34 | # | 
| 35 | print MAKEFILE "OBJS =\t"; | 
| 36 | @objs = @srcs; | 
| 37 | foreach (@objs) { s/\.[^.]+$/.o/ }; | 
| 38 | &PrintWords(8, 0, @objs); | 
| 39 | print MAKEFILE "\n\n"; | 
| 40 | # | 
| 41 | # | 
| 42 | # Define common macros | 
| 43 | # These are defined in Makefile.local which provides custom settings | 
| 44 | # for a particular system. | 
| 45 | # | 
| 46 | # print MAKEFILE "# LIBS =\t\n\n"; | 
| 47 | # print MAKEFILE "# CC = cc\n"; | 
| 48 | # print MAKEFILE "# CFLAGS = -O\n"; | 
| 49 | # print MAKEFILE "# FC = f77\n"; | 
| 50 | # print MAKEFILE "# FFLAGS = -O\n"; | 
| 51 | # print MAKEFILE "# F90 = f90\n"; | 
| 52 | # print MAKEFILE "# F90FLAGS = -O\n"; | 
| 53 | # print MAKEFILE "# LDFLAGS = -s\n\n"; | 
| 54 | # | 
| 55 | # make | 
| 56 | # | 
| 57 | print MAKEFILE "all: lib\$(PROG).a\n\n"; | 
| 58 | print MAKEFILE "\$(PROG): \$(OBJS)\n"; | 
| 59 | print MAKEFILE "\t\$(", &LanguageCompiler($ARGV[1], @srcs); | 
| 60 | print MAKEFILE ") \$(LDFLAGS) -o \$@ \$(OBJS) \$(LIBS)\n\n"; | 
| 61 | print MAKEFILE "lib\$(PROG).a: \$(OBJS)\n"; | 
| 62 | print MAKEFILE "\t\$(AR)"; | 
| 63 | print MAKEFILE " \$(ARFLAGS) \$@ \$(OBJS)\n"; | 
| 64 | # | 
| 65 | # make clean | 
| 66 | # | 
| 67 | print MAKEFILE "clean:\n"; | 
| 68 | print MAKEFILE "\trm -f \$(PROG) \$(OBJS) *.mod lib\$(PROG).a install_mod install_lib\n\n"; | 
| 69 | # | 
| 70 | # make install | 
| 71 | # | 
| 72 | print MAKEFILE "install: install_lib install_mod\n\n"; | 
| 73 | print MAKEFILE "install_lib: lib\$(PROG).a\n"; | 
| 74 | print MAKEFILE "\tcp"; | 
| 75 | print MAKEFILE " \$< ../../lib\n"; | 
| 76 | print MAKEFILE "\ttouch"; | 
| 77 | print MAKEFILE " \install_lib\n\n"; | 
| 78 | print MAKEFILE "install_mod: \$(OBJS)\n"; | 
| 79 | print MAKEFILE "\tcp"; | 
| 80 | print MAKEFILE " \*.mod ../../mod\n"; | 
| 81 | print MAKEFILE "\ttouch"; | 
| 82 | print MAKEFILE " \install_mod\n\n"; | 
| 83 | # | 
| 84 | # Make .f90 a valid suffix | 
| 85 | # | 
| 86 | print MAKEFILE ".SUFFIXES: \$(SUFFIXES) .f90"; | 
| 87 | if ($mod_ext ne "f90") { print MAKEFILE " .$mod_ext"; }; | 
| 88 | print MAKEFILE "\n\n"; | 
| 89 | # | 
| 90 | # .f90 -> .o | 
| 91 | # | 
| 92 | print MAKEFILE ".f90.o:\n"; | 
| 93 | print MAKEFILE "\t\$(F90) \$(F90FLAGS) -c \$<\n\n"; | 
| 94 | # | 
| 95 | # .$mod_ext -> .o | 
| 96 | # | 
| 97 | if ($mod_ext ne "f90") { | 
| 98 | print MAKEFILE ".$mod_ext.o:\n"; | 
| 99 | print MAKEFILE "\t\$(F90) \$(F90FLAGS) -c \$<\n\n"; | 
| 100 | } | 
| 101 | # | 
| 102 | # Dependency listings | 
| 103 | # | 
| 104 | &MakeDependsf90($ARGV[1]); | 
| 105 | &MakeDepends("*.f *.F", '^\s*include\s+["\']([^"\']+)["\']'); | 
| 106 | &MakeDepends("*.c",     '^\s*#\s*include\s+["\']([^"\']+)["\']'); | 
| 107 |  | 
| 108 | # | 
| 109 | # &PrintWords(current output column, extra tab?, word list); --- print words | 
| 110 | #    nicely | 
| 111 | # | 
| 112 | sub PrintWords { | 
| 113 | local($columns) = 78 - shift(@_); | 
| 114 | local($extratab) = shift(@_); | 
| 115 | local($wordlength); | 
| 116 | # | 
| 117 | print MAKEFILE @_[0]; | 
| 118 | $columns -= length(shift(@_)); | 
| 119 | foreach $word (@_) { | 
| 120 | $wordlength = length($word); | 
| 121 | if ($wordlength + 1 < $columns) { | 
| 122 | print MAKEFILE " $word"; | 
| 123 | $columns -= $wordlength + 1; | 
| 124 | } | 
| 125 | else { | 
| 126 | # | 
| 127 | # Continue onto a new line | 
| 128 | # | 
| 129 | if ($extratab) { | 
| 130 | print MAKEFILE " \\\n\t\t$word"; | 
| 131 | $columns = 62 - $wordlength; | 
| 132 | } | 
| 133 | else { | 
| 134 | print MAKEFILE " \\\n\t$word"; | 
| 135 | $columns = 70 - $wordlength; | 
| 136 | } | 
| 137 | } | 
| 138 | } | 
| 139 | } | 
| 140 |  | 
| 141 | # | 
| 142 | # &LanguageCompiler(compiler, sources); --- determine the correct language | 
| 143 | #    compiler | 
| 144 | # | 
| 145 | sub LanguageCompiler { | 
| 146 | local($compiler) = &toLower(shift(@_)); | 
| 147 | local(@srcs) = @_; | 
| 148 | # | 
| 149 | if (length($compiler) > 0) { | 
| 150 | CASE: { | 
| 151 | grep(/^$compiler$/, ("fc", "f77")) && | 
| 152 | do { $compiler = "FC"; last CASE; }; | 
| 153 | grep(/^$compiler$/, ("cc", "c"))   && | 
| 154 | do { $compiler = "CC"; last CASE; }; | 
| 155 | $compiler = "F90"; | 
| 156 | } | 
| 157 | } | 
| 158 | else { | 
| 159 | CASE: { | 
| 160 | grep(/\.f90$/, @srcs)   && do { $compiler = "F90"; last CASE; }; | 
| 161 | grep(/\.F90$/, @srcs)   && do { $compiler = "F90"; last CASE; }; | 
| 162 | grep(/\.(f|F)$/, @srcs) && do { $compiler = "FC";  last CASE; }; | 
| 163 | grep(/\.c$/, @srcs)     && do { $compiler = "CC";  last CASE; }; | 
| 164 | $compiler = "???"; | 
| 165 | } | 
| 166 | } | 
| 167 | $compiler; | 
| 168 | } | 
| 169 |  | 
| 170 | # | 
| 171 | # &toLower(string); --- convert string into lower case | 
| 172 | # | 
| 173 | sub toLower { | 
| 174 | local($string) = @_[0]; | 
| 175 | $string =~ tr/A-Z/a-z/; | 
| 176 | $string; | 
| 177 | } | 
| 178 |  | 
| 179 | # | 
| 180 | # &uniq(sorted word list); --- remove adjacent duplicate words | 
| 181 | # | 
| 182 | sub uniq { | 
| 183 | local(@words); | 
| 184 | foreach $word (@_) { | 
| 185 | if ($word ne $words[$#words]) { | 
| 186 | push(@words, $word); | 
| 187 | } | 
| 188 | } | 
| 189 | @words; | 
| 190 | } | 
| 191 |  | 
| 192 | # | 
| 193 | # &MakeDepends(language pattern, include file sed pattern); --- dependency | 
| 194 | #    maker | 
| 195 | # | 
| 196 | sub MakeDepends { | 
| 197 | local(@incs); | 
| 198 | local($lang) = @_[0]; | 
| 199 | local($pattern) = @_[1]; | 
| 200 | # | 
| 201 | foreach $file (<${lang}>) { | 
| 202 | open(FILE, $file) || warn "Cannot open $file: $!\n"; | 
| 203 | while (<FILE>) { | 
| 204 | /$pattern/i && push(@incs, $1); | 
| 205 | } | 
| 206 | if (defined @incs) { | 
| 207 | $file =~ s/\.[^.]+$/.o/; | 
| 208 | print MAKEFILE "$file: "; | 
| 209 | &PrintWords(length($file) + 2, 0, @incs); | 
| 210 | print MAKEFILE "\n"; | 
| 211 | undef @incs; | 
| 212 | } | 
| 213 | } | 
| 214 | } | 
| 215 |  | 
| 216 | # | 
| 217 | # &MakeDependsf90(f90 compiler); --- FORTRAN 90 dependency maker | 
| 218 | # | 
| 219 | sub MakeDependsf90 { | 
| 220 | local($compiler) = &toLower(@_[0]); | 
| 221 | local(@dependencies); | 
| 222 | local(%filename); | 
| 223 | local(@incs); | 
| 224 | local(@modules); | 
| 225 | local($objfile); | 
| 226 | # | 
| 227 | # Associate each module with the name of the file that contains it | 
| 228 | # | 
| 229 | foreach $file (<*.$mod_ext>) { | 
| 230 | open(FILE, $file) || warn "Cannot open $file: $!\n"; | 
| 231 | while (<FILE>) { | 
| 232 | /^\s*module\s+([^\s!]+)/i && | 
| 233 | ($filename{&toLower($1)} = $file) =~ s/\.$mod_ext$/.o/; | 
| 234 | } | 
| 235 | } | 
| 236 | # | 
| 237 | # Print the dependencies of each file that has one or more include's or | 
| 238 | # references one or more modules | 
| 239 | # | 
| 240 | foreach $file (<@f90>) { | 
| 241 | open(FILE, $file); | 
| 242 | while (<FILE>) { | 
| 243 | /^\s*include\s+["\']([^"\']+)["\']/i && push(@incs, $1); | 
| 244 | /^\s*use\s+([^\s,!]+)/i && push(@modules, &toLower($1)); | 
| 245 | } | 
| 246 | if (defined @incs || defined @modules) { | 
| 247 | ($objfile = $file) =~ s/\.[^.]+$/.o/; | 
| 248 | print MAKEFILE "$objfile: "; | 
| 249 | undef @dependencies; | 
| 250 | foreach $module (@modules) { | 
| 251 | push(@dependencies, $filename{$module}); | 
| 252 | } | 
| 253 | @dependencies = &uniq(sort(@dependencies)); | 
| 254 | &PrintWords(length($objfile) + 2, 0, | 
| 255 | @dependencies, &uniq(sort(@incs))); | 
| 256 | print MAKEFILE "\n"; | 
| 257 | undef @incs; | 
| 258 | undef @modules; | 
| 259 | # | 
| 260 | # Cray F90 compiler | 
| 261 | # | 
| 262 | if ($compiler eq "cray") { | 
| 263 | print MAKEFILE "\t\$(F90) \$(F90FLAGS) -c "; | 
| 264 | foreach $depend (@dependencies) { | 
| 265 | push(@modules, "-p", $depend); | 
| 266 | } | 
| 267 | push(@modules, $file); | 
| 268 | &PrintWords(30, 1, @modules); | 
| 269 | print MAKEFILE "\n"; | 
| 270 | undef @modules; | 
| 271 | } | 
| 272 | # | 
| 273 | # ParaSoft F90 compiler | 
| 274 | # | 
| 275 | if ($compiler eq "parasoft") { | 
| 276 | print MAKEFILE "\t\$(F90) \$(F90FLAGS) -c "; | 
| 277 | foreach $depend (@dependencies) { | 
| 278 | $depend =~ s/\.o$/.f90/; | 
| 279 | push(@modules, "-module", $depend); | 
| 280 | } | 
| 281 | push(@modules, $file); | 
| 282 | &PrintWords(30, 1, @modules); | 
| 283 | print MAKEFILE "\n"; | 
| 284 | undef @modules; | 
| 285 | } | 
| 286 | } | 
| 287 | } | 
| 288 | } | 
| 289 |  |