1 |
#!/usr/bin/perl -w |
2 |
# Copyright (c) The University of Edinburgh |
3 |
# This is a utility to generate make files |
4 |
# for Fortran 90. It was originally in shell script and was re-written |
5 |
# in perl for greater speed and (hopefully) portability. |
6 |
# Initial tests suggest speed is 10x better than the sh version. |
7 |
|
8 |
# A basic makefile entry for bork.f90 would be |
9 |
# bork.o:bork.f90 |
10 |
# <-tab->$(F90) -c bork.f90 |
11 |
# |
12 |
# however if bork.f90 contains the line "use gunge" then |
13 |
# (A) |
14 |
# the entry has to be |
15 |
# bork.o:bork.f90 garple.o <-- Forces bork to be recompiled if a module it |
16 |
# <-tab->$(F90) -c bork.f90 uses is changed |
17 |
# where garple.f90 is the program containing the line "module gunge |
18 |
# (B) |
19 |
# The same type of entry has to be done for garple.f90 |
20 |
# |
21 |
# We also need to generate an entry for the link step. If the main program |
22 |
# was in baz.f90 then this should be |
23 |
# baz:baz.o bork.o......... |
24 |
# <-tab->$(F90) -o baz baz.o bork.o ..... |
25 |
# The list of object files to be linked should have foo.o in it once |
26 |
# and only once for each foo.f90 that was compiled |
27 |
|
28 |
#------------------------------------------------- |
29 |
# First check if the luser has any relevent environment vars set |
30 |
#-------------------------------------------- |
31 |
if ( $ENV{FMKMF_F90} ) { |
32 |
print "\# FMKMF_F90 set to $ENV{FMKMF_F90}\n"; |
33 |
$f90=$ENV{FMKMF_F90}; |
34 |
} |
35 |
else { |
36 |
print "\# FMKMF_F90 not set: using f90\n"; |
37 |
$f90="f90"; |
38 |
} |
39 |
|
40 |
|
41 |
if ( $ENV{FMKMF_SFTAG} ) { |
42 |
print "\# FMKMF_SFTAG set to $ENV{FMKMF_SFTAG}\n"; |
43 |
$sftag=$ENV{FMKMF_SFTAG}; |
44 |
} |
45 |
else { |
46 |
print "\# FMKMF_SFTAG not set: using f90\n"; |
47 |
$sftag="f90"; |
48 |
} |
49 |
|
50 |
if ( $ENV{FMKMF_SPATH} ) { |
51 |
print "\# FMKMF_SPATH set to $ENV{FMKMF_SPATH}\n"; |
52 |
$spath=$ENV{FMKMF_SPATH}; |
53 |
} |
54 |
else { |
55 |
print "\# FMKMF_SPATH not set: using . \n"; |
56 |
$spath="."; |
57 |
} |
58 |
|
59 |
if ( $ENV{FMKMF_LINKOPTS} ) { |
60 |
print "\# FMKMF_LINKOPTS set to $ENV{FMKMF_LINKOPTS}\n"; |
61 |
$linkopts=$ENV{FMKMF_LINKOPTS}; |
62 |
} |
63 |
else { |
64 |
print "\# FMKMF_LINKOPTS not set: using no link options \n"; |
65 |
$linkopts=" "; |
66 |
} |
67 |
|
68 |
#------------------------------ |
69 |
# Done with environment variables. Now we need to process commandline args |
70 |
# These supersede anything supplied via environment variables. |
71 |
#------------------------------ |
72 |
|
73 |
|
74 |
while (@ARGV){ |
75 |
|
76 |
$arg=shift; |
77 |
if ($arg =~ /^-p$/){ |
78 |
$spath=shift; |
79 |
print "# Using search path $spath from cmd line\n"; |
80 |
} |
81 |
if ($arg =~ /^-f90$/){ |
82 |
$f90=shift; |
83 |
print "# Using compile cmd $f90 from cmd line\n"; |
84 |
} |
85 |
if ($arg =~ /^-tag$/){ |
86 |
$sftag=shift; |
87 |
print "# Using source file tag $sftag from cmd line\n"; |
88 |
} |
89 |
if ($arg =~ /^-l$/){ |
90 |
$linkopts=shift; |
91 |
print "# Using Link options $linkopts from cmd line\n"; |
92 |
} |
93 |
|
94 |
} |
95 |
|
96 |
|
97 |
#------------------------------------------- |
98 |
# Done processing command line args |
99 |
#------------------------------------------- |
100 |
|
101 |
|
102 |
@spath=split(/:/,$spath); |
103 |
|
104 |
|
105 |
@global_outlines=(); |
106 |
@global_objlist=(); |
107 |
@global_modfiles=(); |
108 |
|
109 |
$mainprogfile=$arg; |
110 |
|
111 |
print "# Main program is $mainprogfile \n" ; |
112 |
|
113 |
|
114 |
|
115 |
# this subroutine (def below) does most of the work. |
116 |
process_fsource($mainprogfile); |
117 |
|
118 |
# set some makefile . |
119 |
|
120 |
print "\n# ------------------Macro-Defs---------------------\n"; |
121 |
|
122 |
print "F90=$f90 \n"; |
123 |
|
124 |
print "\n# -------------------End-macro-Defs---------------------------\n"; |
125 |
|
126 |
# Generate a name for the executable file |
127 |
$execfile=$mainprogfile; |
128 |
$execfile=~s/\.${sftag}//; |
129 |
$execfile=~s|.*/||; |
130 |
|
131 |
# Generate makefile entry for the Link step |
132 |
print "\n# Here is the link step \n"; |
133 |
|
134 |
print "$execfile:@global_objlist \n"; |
135 |
print "\t \$(F90) -o $execfile @global_objlist $linkopts \n"; |
136 |
|
137 |
print "\n# Here are the compile steps\n "; |
138 |
print STDOUT @global_outlines; |
139 |
|
140 |
# Add an entry for make clean at the end of the make file. this |
141 |
# removes most of the gubbage left around by most of the Unix Fortran |
142 |
# 90 compilers I have tried. |
143 |
|
144 |
print "# This entry allows you to type \" make clean \" to get rid of\n"; |
145 |
print "# all object and module files \n"; |
146 |
|
147 |
print "clean:\n"; |
148 |
print "\trm -f -r f_{files,modd}* *.o *.mod *.M *.d V*.inc *.vo \\\n"; |
149 |
print "\tV*.f *.dbg album F.err"; |
150 |
print "\n \n"; |
151 |
|
152 |
# End of main program |
153 |
|
154 |
############################################## |
155 |
# Here is the subroutine that generates the compile entries in the makefile |
156 |
# These end up in the global array @global_outlines. The magic part is |
157 |
# that this subroutine calls itself recursively. |
158 |
############################################## |
159 |
sub process_fsource { |
160 |
|
161 |
my $mainprogfile=$_[0]; |
162 |
print"# process_fsource called with arg $mainprogfile \n"; |
163 |
open( MAINPROG, $mainprogfile) or |
164 |
die "Can't find main program file $mainprogfile: $! \n"; |
165 |
|
166 |
# Read through Fortran source looking for USE statements |
167 |
# There should be nothing but whitespace before the USE. Sloppily, |
168 |
# we allow tabs, although the standard (IIRC) does not |
169 |
my @modulelist=(); |
170 |
while ($line=<MAINPROG>) { |
171 |
if ($line =~ /^[ \t]*use (\w+)/i ) { # line matches regexp between / / |
172 |
print "# $mainprogfile Uses Module $1\n"; |
173 |
@modulelist=(@modulelist,$1); |
174 |
} |
175 |
} |
176 |
|
177 |
close(MAINPROG); |
178 |
|
179 |
#print "# Full list of modules in $mainprogfile: @modulelist \n"; |
180 |
|
181 |
print "# Full list of modules in $mainprogfile: @modulelist \n"; |
182 |
# Find which file each module is in. |
183 |
|
184 |
|
185 |
|
186 |
my @modfiles=(); |
187 |
MODLOOP:foreach $module (@modulelist){ |
188 |
foreach $directory (@spath){ |
189 |
# print "# Looking in directory $directory\n"; |
190 |
opendir( DIRHANDLE, $directory) or die |
191 |
"Can't open directory $directory : $! \n"; |
192 |
@sourcefiles=grep /\.${sftag}\Z/, sort(readdir(DIRHANDLE)); |
193 |
foreach $sourcefile (@sourcefiles){ |
194 |
$pathsourcefile="$directory/$sourcefile"; |
195 |
#print "\# Checking $pathsourcefile\n"; |
196 |
open( SOURCEFILE, "$pathsourcefile") or |
197 |
die "Can't find source file $pathsourcefile: $! \n"; |
198 |
while ($line=<SOURCEFILE>){ |
199 |
if ($line =~ /^ *module (\w+)/i ){ |
200 |
if($1 =~ /^$module$/i){ |
201 |
print "# Uses $module which is in $pathsourcefile\n"; |
202 |
@modfiles=(@modfiles,$pathsourcefile); |
203 |
|
204 |
if (grep (/$pathsourcefile/,@global_modfiles )){ |
205 |
print "# $pathsourcefile already in list\n"; |
206 |
} |
207 |
else { |
208 |
@global_modfiles=(@global_modfiles,$pathsourcefile); |
209 |
process_fsource($pathsourcefile); |
210 |
|
211 |
} |
212 |
# We found this module -- go on to the next one |
213 |
close (SOURCEFILE); |
214 |
next MODLOOP; |
215 |
} |
216 |
} |
217 |
} |
218 |
close( SOURCEFILE ); |
219 |
} |
220 |
} |
221 |
# exhausted source files |
222 |
print STDERR "Couldn't find source file for module $module\n"; |
223 |
} |
224 |
|
225 |
# name of file we want to make |
226 |
$objfile=$mainprogfile; |
227 |
# replace source file name with .o |
228 |
$objfile=~s/\.${sftag}/\.o/; |
229 |
# strip path so object files go in current dir |
230 |
$objfile=~s|.*/||; |
231 |
@global_objlist=(@global_objlist,$objfile); |
232 |
# list of dependencies |
233 |
@objlist=(); |
234 |
foreach $mf (@modfiles) { |
235 |
$obj=$mf; |
236 |
# replace source file name with .o |
237 |
$obj=~s/\.${sftag}/\.o/; |
238 |
# strip path so object files go in current dir |
239 |
$obj=~s|.*/||; |
240 |
@objlist=(@objlist,$obj); |
241 |
} |
242 |
|
243 |
@global_outlines=(@global_outlines,"\n$objfile:$mainprogfile @objlist \n"); |
244 |
@global_outlines=(@global_outlines,"\t \$(F90) -c $mainprogfile \n"); |
245 |
|
246 |
} |
247 |
|
248 |
|