ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/scripts/sfmakedepend
Revision: 1490
Committed: Fri Sep 24 04:16:43 2004 UTC (19 years, 9 months ago) by gezelter
File size: 17307 byte(s)
Log Message:
Import of OOPSE v. 2.0

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    
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 *