1 |
cnh |
1.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 |
|
|
|