ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/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

# User Rev Content
1 gezelter 1490 #!/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 tim 1496 use File::Spec;
128 gezelter 1490
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 tim 1496 $rel_path = File::Spec->abs2rel( $ref->{'filepath'} ) ;
234     my $len = length($rel_path) + length($objdir) + 2;
235 gezelter 1490 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 tim 1496 #print " " . $objdir . "/" . $ref->{'filepath'};
241     print " " . $rel_path;
242 gezelter 1490 $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 *