ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/oopse-1.0/scripts/sfmakedepend
Revision: 1447
Committed: Fri Jul 30 21:01:35 2004 UTC (19 years, 11 months ago) by gezelter
File size: 17307 byte(s)
Log Message:
Initial import of OOPSE sources into cvs tree

File Contents

# Content
1 #!/usr/bin/perl
2 #
3 # Usage: sfmakedepend [-s] [-e ext] [-f file] [-I incdir] [-d objdir]
4 # [-m mod_ext] [-c] [-p] [-g] [-h] [-o obj_ext]
5 # [-a add_ext] file ...
6 #
7 # This is a makedepend script for Fortran, including Fortran 90.
8 # It searches for Fortran style includes, C preprocessor includes,
9 # and module dependencies to the extent that I understand them.
10 #
11 # Your files must have an extension listed in the @suffixes list
12 # below. You might also want to modify $compile_string if you use
13 # the -c or -p option. I call the compiler $(CFT) for historical
14 # reasons.
15 #
16 # The switch [-s] is for stupid Fortran compilers that don't know
17 # how to automatically send things through the C preprocessor.
18 # It is possible to force 'make' to invoke 'cpp' to create a .f
19 # file from a .F file (which has cpp directives), but make won't
20 # know that a .f file will depend on the files that the .F file
21 # included. This option will provide those dependencies.
22 #
23 # The [-e ext] switch is used with the [-s] switch for compilers
24 # which expect an extension other than .f on source files. For
25 # instance, for the Connection Machine one would use "-e fcm".
26 #
27 # The [-f file] switch is used to change the name of the current
28 # Makefile.
29 #
30 # The [-I incdir] option tells sfmakedepend to look in alternate
31 # directories for the include files. There can be several "-I dir"
32 # options used at once. The current directory is still searched
33 # first.
34 #
35 # The [-d objdir] option tells sfmakedepend that the object and
36 # module files will be built in a separate directory from the sources.
37 #
38 # The [-m mod_ext] option tells sfmakedepend what extension to
39 # use for Fortran 90 module files. The default for "use My_Mod"
40 # is to list the dependency as "my_mod.mod" since this is what
41 # NAG f90 and IBM xlf both use. Let me know if other compilers
42 # use a different filename for the module information.
43 #
44 # The [-c] option specifies that the Cray compiler is being used.
45 # This compiler requires a "-p file.o" option for each object file
46 # that contains a module used by your current source file.
47 #
48 # The [-p] option specifies that the Parasoft compiler is being used.
49 # This compiler requires a "-module file.o" option for each object file
50 # that contains a module used by your current source file.
51 #
52 # The [-g] option specifies that the SGI compiler is being used.
53 # This compiler names the module file in uppercase with the extension
54 # .kmo.
55 #
56 # The [-h] option specifies that the HP compiler is being used.
57 # This compiler names the module file in uppercase with the extension
58 # .mod (added by Patrick Jessee who also fixed an include bug).
59 #
60 # The [-o obj_ext] option tells sfmakedepend what extension to use for
61 # object files. The default is "o", but "obj", for instance, is
62 # appropriate on MS-DOG etc. This option was added by Dave Love.
63 #
64 # The [-a add_ext] option (also added by Dave Love) tells sfmakedepend
65 # to add targets with extension add_ext to the rules for object files.
66 # For instance, to operate with (f77) ftnchek .prj files, you could use
67 # `-a prj' to get rules like:
68 # foo.prj foo.o: ...
69 #
70 # The final arguments contain the list of source files to be
71 # searched for dependencies.
72 #
73 # EXAMPLE
74 # sfmakedepend -I /usr/local/include *.F
75 #
76 # NOTES
77 # This makedepend script is my first attempt at using perl 5
78 # objects. Therefore, it may not be the best example of how
79 # to do this. Also, it requires perl 5 and will die if you
80 # to use it with an older perl. The latest version is
81 # available from:
82 #
83 # http://marine.rutgers.edu/po/perl.html
84 # ftp://ahab.rutgers.edu/pub/perl/sfmakedepend
85 #
86 # Fortran 90 introduces some interesting dependencies. Two
87 # compilers I have access to (NAG f90 and IBM xlf) produce a
88 # private "mod_name.mod" file if you define "module mod_name"
89 # in your code. This file is used by the compiler when you
90 # use the module as a consistency check (type-safe). On the
91 # other hand, the Cray and Parasoft compilers store the module
92 # information in the object file and then files which use the
93 # modules need to be compiled with extra flags pointing to the
94 # module object files.
95 #
96 # This script assumes that all the files using and defining
97 # modules are in the same directory and are all in the list of
98 # files to be searched. It seems that the industry has not
99 # settled on a practical way to deal with a separate modules
100 # directory, anyway.
101 #
102 # I sometimes include non-existent files as a compile time
103 # consistency check:
104 #
105 # #ifndef PLOTS
106 # #include "must_define_PLOTS" /* bogus include */
107 # #endif
108 #
109 # This program warns about include files it can't find, but
110 # not if there is a "bogus" on the same line.
111 #
112 # * The f90 module dependencies can confuse some versions of
113 # make, especially of the System V variety. We use gnu
114 # make because it has no problems with these dependencies.
115 #
116 # BUGS
117 # It can sometimes produce duplicate dependencies.
118 #
119 # It treats C preprocessor includes the same as Fortran
120 # includes. This can add unnecessary dependencies if you
121 # use the -s flag and both kinds of includes.
122 #
123 # Please let me know if you find any others.
124 # Kate Hedstrom
125 # kate@ahab.rutgers.edu
126 #
127
128 package source_file;
129
130 # hashes containing names of included files, modules in files
131 %inc_files = ();
132 %main::mod_files = ();
133
134 # Constructor
135 sub new {
136 my $type = shift;
137 my $filename = shift;
138 my $path = shift;
139 my $self = {};
140 $self->{'source_file'} = $filename;
141 $self->{'filepath'} = $path;
142 $self->{'includes'} = {};
143 $self->{'uses'} = {};
144 $self->{'modules'} = {};
145 bless $self;
146 }
147
148 sub find_includes {
149 my $self = shift;
150 my $file = $self->{'filepath'};
151 my($after, $filepath, $ref, $included, $use, $modname);
152 local(*FILE);
153 local($_);
154
155 if (-f $file) {
156 open(FILE, $file) || warn "Can't open $file: $!\n";
157 } elsif (-f "RCS/$file,v" || -f "$file,v" ) {
158 system("co $file");
159 open(FILE, $file) || warn "Can't open $file: $!\n";
160 $main::rcs{$file} = 1;
161 } else {
162 return;
163 }
164 while (<FILE>) {
165 $included = "";
166 $use = "";
167 # look for Fortran style includes
168 if (/^\s*include\s*['"]([^"']*)["']/i) {
169 $included = $1;
170 $after = $';
171 # C preprocessor style includes
172 } elsif (/^#\s*include\s*["<]([^">]*)[">]/) {
173 $included = $1;
174 $after = $';
175 # Fortran 90 "use"
176 } elsif (/^\s*use\s+(\w+)/i) {
177 $use = $1;
178 # Make the module name lowercase except for SGI & HP.
179 # May be compiler dependent!!
180 if ($main::sgi || $main::hp) {
181 $use = uc($use);
182 } else {
183 $use = lc($use);
184 }
185 $self->{'uses'}{$use} = 1;
186 # Fortran 90 module
187 } elsif (/^\s*module\s+(\w+)/i) {
188 $modname = $1;
189 if ($main::sgi || $main::hp) {
190 $modname = uc($modname);
191 } else {
192 $modname = lc($modname);
193 }
194 unless (lc($modname) eq "procedure") {
195 $main::mod_files{$modname} = $file;
196 $self->{'modules'}{$modname} = 1;
197 }
198 }
199 if ($included) {
200 if ( $inc_files{$included} ) {
201 $filepath = $inc_files{$included}{'filepath'};
202 } else {
203 $filepath = &main::findfile($included);
204 $ref = new source_file($included, $filepath);
205 $inc_files{$included} = $ref;
206 # Search included file for includes
207 $ref->find_includes();
208 }
209 if ( $filepath ) {
210 $self->{'includes'}{$included} = 1;
211 } else {
212 if ($after !~ /bogus/i) {
213 warn "Can't find file: $included\n";
214 }
215 }
216 }
217 }
218 close FILE;
219 }
220
221 sub print_includes {
222 my $self = shift;
223 my $target = shift;
224 my $len_sum = shift;
225 my $objdir = shift;
226 my($file, $ref);
227 my %printed = ();
228
229 foreach $file (keys %{$self->{'includes'}}) {
230 next if $printed{$file};
231 $ref = $inc_files{$file};
232 my $len = length($ref->{'filepath'}) + length($objdir) + 2;
233 if (($len_sum + $len > 80) &&
234 (length($target) + length($objdir) + 2 < $len_sum)) {
235 print "\n" . $objdir . "/" . "$target:";
236 $len_sum = length($target) + length($objdir) + 2;
237 }
238 print " " . $objdir . "/" . $ref->{'filepath'};
239 $printed{$file} = 1;
240 $len_sum += $len;
241 $len_sum = $ref->print_includes($target, $len_sum, $objdir);
242 }
243 $len_sum;
244 }
245
246 # return list of modules used by included files
247 sub inc_mods {
248 my $self = shift;
249 my($file, $ref, $mod, @sub_list);
250 my @list = ();
251 my %printed = ();
252
253 foreach $mod (keys %{$self->{'uses'}}) {
254 push(@list, $mod);
255 }
256
257 foreach $file (keys %{$self->{'includes'}}) {
258 next if $printed{$file};
259 $ref = $inc_files{$file};
260 $printed{$file} = 1;
261 @sub_list = $ref->inc_mods();
262 @list = (@list, @sub_list);
263 }
264 @list;
265 }
266
267 # filenames containing the list of modules used by file and all its includes
268 sub find_mods {
269 my $self = shift;
270 my($ref, $modname, $file, @list, $base);
271 my @module_files = ();
272 my @mod_list = ();
273 my @tmp_list = ();
274
275 # find modules used by include files
276 if (%{$self->{'includes'}}) {
277 foreach $file (keys %{$self->{'includes'}}) {
278 $ref = $inc_files{$file};
279 @list = $ref->inc_mods();
280 @tmp_list = @mod_list;
281 @mod_list = (@tmp_list, @list);
282 }
283 }
284
285 # add them to the uses list (hash ensures uniqueness)
286 foreach $modname (@mod_list) {
287 $self->{'uses'}{$modname} = 1;
288 }
289
290 # now find the filename that contains the module information
291 foreach $modname (keys %{$self->{'uses'}}) {
292 if ($main::cray || $main::parasoft) {
293 if ($file = $main::mod_files{$modname}) {
294 $base = &main::basename($file, @main::suffixes);
295 $file = $base . "." . $main::obj_ext;
296 push(@module_files, $file);
297 } else {
298 warn "Don't know where module $modname lives.\n";
299 }
300 } else {
301 $modname .= "." . $main::mod_ext;
302 push(@module_files, $modname);
303 }
304 }
305 sort(@module_files);
306 }
307
308 sub print {
309 my $self = shift;
310 my $objdir = shift;
311 my $source = $self->{'source_file'};
312 my $compile_string = "\t" . '$(CFT) $(FFLAGS) -c';
313 my($base, $object, $modname, $flag, $target, $ftarget);
314
315 $base = &main::basename($source, @main::suffixes);
316 $target = $base . "." . $main::obj_ext;
317 if ($main::stupid) {
318 $ftarget = $base . "." . $main::ext;
319 }
320
321 if ($main::cray) {
322 $flag = " -p ";
323 } elsif ($main::parasoft) {
324 $flag = " -module ";
325 }
326
327 # print out "include" dependencies
328 if (%{$self->{'includes'}}) {
329 my $len_sum = length($target) + 1;
330 if ($main::add_ext) {
331 $target .= " $base.$main::add_ext";
332 $len_sum += length($base) + length($main::add_ext) + 2;
333 }
334 print $objdir . "/" . "$target:";
335 $self->print_includes($target, $len_sum, $objdir);
336 print "\n";
337 if ($main::stupid) {
338 $len_sum = length($ftarget) + 1;
339 print $objdir . "/" . "$ftarget:";
340 $self->print_includes($ftarget, $len_sum, $objdir);
341 print "\n";
342 }
343 }
344
345 # clean out "use" of modules in own file
346 foreach $mod ( keys %{$self->{'uses'}} ) {
347 if ( ${$self->{'modules'}}{$mod} ) {
348 delete ${$self->{'uses'}}{$mod};
349 }
350 }
351
352 # print out "use" dependencies
353 if (%{$self->{'uses'}} || %{$self->{'includes'}}) {
354 @module_files = $self->find_mods();
355 my $len_sum = length($target) + length($objdir) + 2;
356 print $objdir . "/" . "$target:";
357 foreach $file (@module_files) {
358 my $len = length($objdir) + length($file) + 2;
359 if (($len_sum + $len > 80) &&
360 (length($objdir) + length($target) + 2 < $len_sum)) {
361 print "\n" . $objdir . "/" . "$target:";
362 $len_sum = length($objdir) + length($target) + 2;
363 }
364 $len_sum += $len;
365 print " " . $objdir . "/" . $file;
366 }
367 if ($main::need_f) {
368 my $len = length($ftarget) +length($objdir) + 2;
369 if (($len_sum + $len > 80) &&
370 (length($target) +length($objdir) + 2 < $len_sum)) {
371 print "\n" . $objdir . "/" . "$target:";
372 $len_sum = length($target) +length($objdir)+ 2;
373 }
374 print " " . $objdir . "/" . $ftarget;
375 }
376 print "\n";
377 # extra Cray / Parasoft stuff
378 if ($main::cray || $main::parasoft) {
379 print $compile_string;
380 foreach $file (@module_files) {
381 print $flag . $file;
382 }
383 if ($main::stupid) {
384 print " " . $ftarget . "\n";
385 } else {
386 print " " . $source . "\n";
387 }
388 }
389 }
390 }
391
392
393 # Start of main program
394 package main;
395
396 if ($] < 5.000) { die "Need perl 5.000 or newer\n"; }
397 use File::Basename;
398 use Getopt::Long;
399 @suffixes = qw( .c .C .cc .cxx .cpp .f .F .fcm .FCM .f90 .F90 .for);
400
401 GetOptions("s", "e=s", "f=s", "I=s@", "d=s", "m=s", "c", "p", "g", "h", "o=s", "a=s")
402 || die "problem in GetOptions";
403
404 # For compilers that don't invoke cpp for you
405 if ($opt_s) {
406 $stupid = 1;
407 }
408 if ($opt_e) {
409 $ext = $opt_e;
410 } else {
411 $ext = "f";
412 }
413
414 # list of directories to search, starting with current directory
415 if (@opt_I) {
416 @incdirs = @opt_I;
417 } elsif (@opt_i) {
418 @incdirs = @opt_i;
419 }
420
421 if ($opt_D) {
422 $objdir = $opt_D;
423 } elsif ($opt_d) {
424 $objdir = $opt_d;
425 }
426
427 if ($opt_f) {
428 $mf = $opt_f;
429 } elsif (-f "makefile") {
430 $mf = 'makefile';
431 } else {
432 $mf = 'Makefile';
433 }
434 if ( !(-f $mf)) {
435 system "touch $mf";
436 }
437
438 # extension used for compiler's private module information
439 if ($opt_m) {
440 $mod_ext = $opt_m;
441 } else {
442 $mod_ext = 'mod';
443 }
444
445 if ($opt_c) {
446 $cray = 1;
447 }
448
449 if ($opt_p) {
450 $parasoft = 1;
451 }
452
453 if ($opt_g) {
454 $sgi = 1;
455 $mod_ext = 'kmo';
456 }
457
458 if ($opt_h) {
459 $hp = 1;
460 }
461
462 # need to add some more dependencies so the .f file gets created
463 if ($stupid && ($cray || $parasoft)) {
464 $need_f = 1;
465 }
466
467 if ($opt_c && $opt_p) {
468 die "Doesn't make sense to have both Cray and Parasoft options!";
469 }
470
471 # object file extension
472 if ($opt_o) {
473 $obj_ext = $opt_o;
474 } else {
475 $obj_ext = 'o';
476 }
477
478 # extension for additional targets (like .prj)
479 if ($opt_a) {
480 $add_ext = $opt_a;
481 }
482
483 $mystring = '# DO NOT DELETE THIS LINE - used by make depend';
484
485 # Search for the includes in all the files
486 foreach $file (@ARGV) {
487 $sources{$file} = new source_file($file, $file);
488 $sources{$file}->find_includes();
489 }
490
491 # Create new Makefile with new dependencies.
492
493 open(MFILE, $mf) || die "can't read Makefile $mf: $!\n";
494 open(NMFILE, "> Makefile.new") || die "can't write Makefile.new: $!\n";
495 select(NMFILE);
496
497 while (<MFILE>) {
498 if (!/$mystring/) {
499 print;
500 } else {
501 last;
502 }
503 }
504
505 # comment this out if we are using make depend
506 #print $mystring, "\n";
507
508 # Now print out include and use dependencies in sorted order.
509 foreach $target (sort keys(%sources)) {
510 $sources{$target}->print($objdir);
511 }
512
513 # print out module dependencies
514 if ( !( $cray || $parasoft) ) {
515 foreach $modname (sort keys(%mod_files)) {
516 ($name, $path, $suffix) =
517 &fileparse($sources{$mod_files{$modname}}->{'filepath'}, @suffixes);
518 $object = $objdir . "/" . $name . "." . $obj_ext;
519 print "$objdir/$modname.$mod_ext: $object\n";
520 }
521 }
522
523 # Sort out the Makefiles
524
525 rename($mf, "$mf.old") || warn "can't overwrite $mf.old: $!\n";
526 rename('Makefile.new', $mf) ||
527 warn "can't move Makefile.new to $mf: $!\n";
528
529 # Delete those RCS files we checked out
530 foreach $file (keys %rcs) {
531 unlink($file);
532 }
533
534 #
535 # End of main
536 #
537
538 sub findfile {
539 # Let's see if we can find the included file. Look in current
540 # directory first, then in directories from -I arguments. Finally,
541 # look for RCS files in current directory.
542 my $file = shift;
543 my($found, $i, $filepath);
544
545 $found = 0;
546
547 if ( -f $file ) {
548 $found = 1;
549 $file =~ s#^\./##; # convert ./foo.h to foo.h
550 return $file;
551 }
552 foreach $i (0 .. $#incdirs) {
553 $filepath = $incdirs[$i]."/".$file;
554 if ( -f $filepath ) {
555 $found = 1;
556 $filepath =~ s#^\./##; # convert ./foo.h to foo.h
557 return $filepath;
558 }
559 }
560 #see if it is a checked-in RCS file
561 if (-f "RCS/$file,v" || -f "$file,v" ) {
562 $found = 1;
563 system("co $file");
564 $filepath = $file;
565 $rcs{$file} = 1;
566 }
567 if ( ! $found ) {
568 $filepath = "";
569 }
570 $filepath;
571 }
572

Properties

Name Value
svn:executable *