ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/scripts/sfmakedepend
Revision: 1496
Committed: Tue Sep 28 20:42:28 2004 UTC (19 years, 9 months ago) by tim
File size: 17410 byte(s)
Log Message:
fix fortran dependency problem

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 use File::Spec;
128
129 package source_file;
130
131 # hashes containing names of included files, modules in files
132 %inc_files = ();
133 %main::mod_files = ();
134
135 # Constructor
136 sub new {
137 my $type = shift;
138 my $filename = shift;
139 my $path = shift;
140 my $self = {};
141 $self->{'source_file'} = $filename;
142 $self->{'filepath'} = $path;
143 $self->{'includes'} = {};
144 $self->{'uses'} = {};
145 $self->{'modules'} = {};
146 bless $self;
147 }
148
149 sub find_includes {
150 my $self = shift;
151 my $file = $self->{'filepath'};
152 my($after, $filepath, $ref, $included, $use, $modname);
153 local(*FILE);
154 local($_);
155
156 if (-f $file) {
157 open(FILE, $file) || warn "Can't open $file: $!\n";
158 } elsif (-f "RCS/$file,v" || -f "$file,v" ) {
159 system("co $file");
160 open(FILE, $file) || warn "Can't open $file: $!\n";
161 $main::rcs{$file} = 1;
162 } else {
163 return;
164 }
165 while (<FILE>) {
166 $included = "";
167 $use = "";
168 # look for Fortran style includes
169 if (/^\s*include\s*['"]([^"']*)["']/i) {
170 $included = $1;
171 $after = $';
172 # C preprocessor style includes
173 } elsif (/^#\s*include\s*["<]([^">]*)[">]/) {
174 $included = $1;
175 $after = $';
176 # Fortran 90 "use"
177 } elsif (/^\s*use\s+(\w+)/i) {
178 $use = $1;
179 # Make the module name lowercase except for SGI & HP.
180 # May be compiler dependent!!
181 if ($main::sgi || $main::hp) {
182 $use = uc($use);
183 } else {
184 $use = lc($use);
185 }
186 $self->{'uses'}{$use} = 1;
187 # Fortran 90 module
188 } elsif (/^\s*module\s+(\w+)/i) {
189 $modname = $1;
190 if ($main::sgi || $main::hp) {
191 $modname = uc($modname);
192 } else {
193 $modname = lc($modname);
194 }
195 unless (lc($modname) eq "procedure") {
196 $main::mod_files{$modname} = $file;
197 $self->{'modules'}{$modname} = 1;
198 }
199 }
200 if ($included) {
201 if ( $inc_files{$included} ) {
202 $filepath = $inc_files{$included}{'filepath'};
203 } else {
204 $filepath = &main::findfile($included);
205 $ref = new source_file($included, $filepath);
206 $inc_files{$included} = $ref;
207 # Search included file for includes
208 $ref->find_includes();
209 }
210 if ( $filepath ) {
211 $self->{'includes'}{$included} = 1;
212 } else {
213 if ($after !~ /bogus/i) {
214 warn "Can't find file: $included\n";
215 }
216 }
217 }
218 }
219 close FILE;
220 }
221
222 sub print_includes {
223 my $self = shift;
224 my $target = shift;
225 my $len_sum = shift;
226 my $objdir = shift;
227 my($file, $ref);
228 my %printed = ();
229
230 foreach $file (keys %{$self->{'includes'}}) {
231 next if $printed{$file};
232 $ref = $inc_files{$file};
233 $rel_path = File::Spec->abs2rel( $ref->{'filepath'} ) ;
234 my $len = length($rel_path) + length($objdir) + 2;
235 if (($len_sum + $len > 80) &&
236 (length($target) + length($objdir) + 2 < $len_sum)) {
237 print "\n" . $objdir . "/" . "$target:";
238 $len_sum = length($target) + length($objdir) + 2;
239 }
240 #print " " . $objdir . "/" . $ref->{'filepath'};
241 print " " . $rel_path;
242 $printed{$file} = 1;
243 $len_sum += $len;
244 $len_sum = $ref->print_includes($target, $len_sum, $objdir);
245 }
246 $len_sum;
247 }
248
249 # return list of modules used by included files
250 sub inc_mods {
251 my $self = shift;
252 my($file, $ref, $mod, @sub_list);
253 my @list = ();
254 my %printed = ();
255
256 foreach $mod (keys %{$self->{'uses'}}) {
257 push(@list, $mod);
258 }
259
260 foreach $file (keys %{$self->{'includes'}}) {
261 next if $printed{$file};
262 $ref = $inc_files{$file};
263 $printed{$file} = 1;
264 @sub_list = $ref->inc_mods();
265 @list = (@list, @sub_list);
266 }
267 @list;
268 }
269
270 # filenames containing the list of modules used by file and all its includes
271 sub find_mods {
272 my $self = shift;
273 my($ref, $modname, $file, @list, $base);
274 my @module_files = ();
275 my @mod_list = ();
276 my @tmp_list = ();
277
278 # find modules used by include files
279 if (%{$self->{'includes'}}) {
280 foreach $file (keys %{$self->{'includes'}}) {
281 $ref = $inc_files{$file};
282 @list = $ref->inc_mods();
283 @tmp_list = @mod_list;
284 @mod_list = (@tmp_list, @list);
285 }
286 }
287
288 # add them to the uses list (hash ensures uniqueness)
289 foreach $modname (@mod_list) {
290 $self->{'uses'}{$modname} = 1;
291 }
292
293 # now find the filename that contains the module information
294 foreach $modname (keys %{$self->{'uses'}}) {
295 if ($main::cray || $main::parasoft) {
296 if ($file = $main::mod_files{$modname}) {
297 $base = &main::basename($file, @main::suffixes);
298 $file = $base . "." . $main::obj_ext;
299 push(@module_files, $file);
300 } else {
301 warn "Don't know where module $modname lives.\n";
302 }
303 } else {
304 $modname .= "." . $main::mod_ext;
305 push(@module_files, $modname);
306 }
307 }
308 sort(@module_files);
309 }
310
311 sub print {
312 my $self = shift;
313 my $objdir = shift;
314 my $source = $self->{'source_file'};
315 my $compile_string = "\t" . '$(CFT) $(FFLAGS) -c';
316 my($base, $object, $modname, $flag, $target, $ftarget);
317
318 $base = &main::basename($source, @main::suffixes);
319 $target = $base . "." . $main::obj_ext;
320 if ($main::stupid) {
321 $ftarget = $base . "." . $main::ext;
322 }
323
324 if ($main::cray) {
325 $flag = " -p ";
326 } elsif ($main::parasoft) {
327 $flag = " -module ";
328 }
329
330 # print out "include" dependencies
331 if (%{$self->{'includes'}}) {
332 my $len_sum = length($target) + 1;
333 if ($main::add_ext) {
334 $target .= " $base.$main::add_ext";
335 $len_sum += length($base) + length($main::add_ext) + 2;
336 }
337 print $objdir . "/" . "$target:";
338 $self->print_includes($target, $len_sum, $objdir);
339 print "\n";
340 if ($main::stupid) {
341 $len_sum = length($ftarget) + 1;
342 print $objdir . "/" . "$ftarget:";
343 $self->print_includes($ftarget, $len_sum, $objdir);
344 print "\n";
345 }
346 }
347
348 # clean out "use" of modules in own file
349 foreach $mod ( keys %{$self->{'uses'}} ) {
350 if ( ${$self->{'modules'}}{$mod} ) {
351 delete ${$self->{'uses'}}{$mod};
352 }
353 }
354
355 # print out "use" dependencies
356 if (%{$self->{'uses'}} || %{$self->{'includes'}}) {
357 @module_files = $self->find_mods();
358 my $len_sum = length($target) + length($objdir) + 2;
359 print $objdir . "/" . "$target:";
360 foreach $file (@module_files) {
361 my $len = length($objdir) + length($file) + 2;
362 if (($len_sum + $len > 80) &&
363 (length($objdir) + length($target) + 2 < $len_sum)) {
364 print "\n" . $objdir . "/" . "$target:";
365 $len_sum = length($objdir) + length($target) + 2;
366 }
367 $len_sum += $len;
368 print " " . $objdir . "/" . $file;
369 }
370 if ($main::need_f) {
371 my $len = length($ftarget) +length($objdir) + 2;
372 if (($len_sum + $len > 80) &&
373 (length($target) +length($objdir) + 2 < $len_sum)) {
374 print "\n" . $objdir . "/" . "$target:";
375 $len_sum = length($target) +length($objdir)+ 2;
376 }
377 print " " . $objdir . "/" . $ftarget;
378 }
379 print "\n";
380 # extra Cray / Parasoft stuff
381 if ($main::cray || $main::parasoft) {
382 print $compile_string;
383 foreach $file (@module_files) {
384 print $flag . $file;
385 }
386 if ($main::stupid) {
387 print " " . $ftarget . "\n";
388 } else {
389 print " " . $source . "\n";
390 }
391 }
392 }
393 }
394
395
396 # Start of main program
397 package main;
398
399 if ($] < 5.000) { die "Need perl 5.000 or newer\n"; }
400 use File::Basename;
401 use Getopt::Long;
402 @suffixes = qw( .c .C .cc .cxx .cpp .f .F .fcm .FCM .f90 .F90 .for);
403
404 GetOptions("s", "e=s", "f=s", "I=s@", "d=s", "m=s", "c", "p", "g", "h", "o=s", "a=s")
405 || die "problem in GetOptions";
406
407 # For compilers that don't invoke cpp for you
408 if ($opt_s) {
409 $stupid = 1;
410 }
411 if ($opt_e) {
412 $ext = $opt_e;
413 } else {
414 $ext = "f";
415 }
416
417 # list of directories to search, starting with current directory
418 if (@opt_I) {
419 @incdirs = @opt_I;
420 } elsif (@opt_i) {
421 @incdirs = @opt_i;
422 }
423
424 if ($opt_D) {
425 $objdir = $opt_D;
426 } elsif ($opt_d) {
427 $objdir = $opt_d;
428 }
429
430 if ($opt_f) {
431 $mf = $opt_f;
432 } elsif (-f "makefile") {
433 $mf = 'makefile';
434 } else {
435 $mf = 'Makefile';
436 }
437 if ( !(-f $mf)) {
438 system "touch $mf";
439 }
440
441 # extension used for compiler's private module information
442 if ($opt_m) {
443 $mod_ext = $opt_m;
444 } else {
445 $mod_ext = 'mod';
446 }
447
448 if ($opt_c) {
449 $cray = 1;
450 }
451
452 if ($opt_p) {
453 $parasoft = 1;
454 }
455
456 if ($opt_g) {
457 $sgi = 1;
458 $mod_ext = 'kmo';
459 }
460
461 if ($opt_h) {
462 $hp = 1;
463 }
464
465 # need to add some more dependencies so the .f file gets created
466 if ($stupid && ($cray || $parasoft)) {
467 $need_f = 1;
468 }
469
470 if ($opt_c && $opt_p) {
471 die "Doesn't make sense to have both Cray and Parasoft options!";
472 }
473
474 # object file extension
475 if ($opt_o) {
476 $obj_ext = $opt_o;
477 } else {
478 $obj_ext = 'o';
479 }
480
481 # extension for additional targets (like .prj)
482 if ($opt_a) {
483 $add_ext = $opt_a;
484 }
485
486 $mystring = '# DO NOT DELETE THIS LINE - used by make depend';
487
488 # Search for the includes in all the files
489 foreach $file (@ARGV) {
490 $sources{$file} = new source_file($file, $file);
491 $sources{$file}->find_includes();
492 }
493
494 # Create new Makefile with new dependencies.
495
496 open(MFILE, $mf) || die "can't read Makefile $mf: $!\n";
497 open(NMFILE, "> Makefile.new") || die "can't write Makefile.new: $!\n";
498 select(NMFILE);
499
500 while (<MFILE>) {
501 if (!/$mystring/) {
502 print;
503 } else {
504 last;
505 }
506 }
507
508 # comment this out if we are using make depend
509 #print $mystring, "\n";
510
511 # Now print out include and use dependencies in sorted order.
512 foreach $target (sort keys(%sources)) {
513 $sources{$target}->print($objdir);
514 }
515
516 # print out module dependencies
517 if ( !( $cray || $parasoft) ) {
518 foreach $modname (sort keys(%mod_files)) {
519 ($name, $path, $suffix) =
520 &fileparse($sources{$mod_files{$modname}}->{'filepath'}, @suffixes);
521 $object = $objdir . "/" . $name . "." . $obj_ext;
522 print "$objdir/$modname.$mod_ext: $object\n";
523 }
524 }
525
526 # Sort out the Makefiles
527
528 rename($mf, "$mf.old") || warn "can't overwrite $mf.old: $!\n";
529 rename('Makefile.new', $mf) ||
530 warn "can't move Makefile.new to $mf: $!\n";
531
532 # Delete those RCS files we checked out
533 foreach $file (keys %rcs) {
534 unlink($file);
535 }
536
537 #
538 # End of main
539 #
540
541 sub findfile {
542 # Let's see if we can find the included file. Look in current
543 # directory first, then in directories from -I arguments. Finally,
544 # look for RCS files in current directory.
545 my $file = shift;
546 my($found, $i, $filepath);
547
548 $found = 0;
549
550 if ( -f $file ) {
551 $found = 1;
552 $file =~ s#^\./##; # convert ./foo.h to foo.h
553 return $file;
554 }
555 foreach $i (0 .. $#incdirs) {
556 $filepath = $incdirs[$i]."/".$file;
557 if ( -f $filepath ) {
558 $found = 1;
559 $filepath =~ s#^\./##; # convert ./foo.h to foo.h
560 return $filepath;
561 }
562 }
563 #see if it is a checked-in RCS file
564 if (-f "RCS/$file,v" || -f "$file,v" ) {
565 $found = 1;
566 system("co $file");
567 $filepath = $file;
568 $rcs{$file} = 1;
569 }
570 if ( ! $found ) {
571 $filepath = "";
572 }
573 $filepath;
574 }
575

Properties

Name Value
svn:executable *