[project @ 1996-01-11 14:06:51 by partain]
[ghc-hetmet.git] / ghc / utils / mkdependHS / mkdependHS.prl
1 # *** MSUB does some substitutions here ***
2 # *** grep for $( ***
3 #
4 # tries to work like mkdependC
5 #
6 # ToDo: strip out all the .h junk
7 #
8 ($Pgm = $0) =~ s/.*\/([^\/]+)$/\1/;
9 $Usage  = "usage: $Pgm: not done yet\n";
10
11 $Status  = 0; # just used for exit() status
12 $Verbose = '';
13 $Dashdashes_seen = 0;
14
15 $OrigCpp = '$(RAWCPP)';
16 if ( $OrigCpp =~ /(\S+)\s+(.*)/ ) {
17     $cmd  = $1;
18     $rest = $2;
19     if ( -x $cmd ) { # cool
20         $Cpp = $OrigCpp;
21     } else { # oops; try to guess
22         $GccV = `gcc -v 2>&1`;
23         if ( $GccV =~ /Reading specs from (.*)\/specs/ ) {
24             $Cpp = "$1/cpp $rest";
25         } else {
26             die "hscpp: don't know how to run cpp: $OrigCpp\n";
27         }
28     }
29 } else {
30     $Cpp = $OrigCpp;
31 }
32
33 $Tmp_prefix = (( $ENV{'TMPDIR'} ) # to make tmp file names
34                 ? ($ENV{'TMPDIR'} . "/mkdependHS$$")
35                 : "$(TMPDIR)/mkdependHS$$" );
36
37 #------------------------------------------------------------------------
38 # If you are adjusting paths by hand for a binary GHC distribution,
39 # de-commenting the line to set GLASGOW_HASKELL_ROOT should do.
40 # Or you can leave it as is, and set the environment variable externally.
41 #------------------------------------------------------------------------
42 # $ENV{'GLASGOW_HASKELL_ROOT'} = '/some/absolute/path/name';
43
44 if (! $ENV{'GLASGOW_HASKELL_ROOT'}) { # good -- death to environment variables
45     $TopPwd         = '$(TOP_PWD)';
46     $InstLibDirGhc  = '$(INSTLIBDIR_GHC)';
47     $InstDataDirGhc = '$(INSTDATADIR_GHC)';
48 } else {
49     $TopPwd = $ENV{'GLASGOW_HASKELL_ROOT'};
50
51     if ( '$(INSTLIBDIR_GHC)' =~ /\/local\/fp(\/.*)/ ) {
52         $InstLibDirGhc  = $ENV{'GLASGOW_HASKELL_ROOT'} . $1;
53     } else {
54         print STDERR "GLASGOW_HASKELL_ROOT environment variable is set;\nBut can't untangle $(INSTLIBDIR_GHC).\n(Installation error)\n";
55         exit(1);
56     }
57
58     if ( '$(INSTDATADIR_GHC)' =~ /\/local\/fp(\/.*)/ ) {
59         $InstDataDirGhc = $ENV{'GLASGOW_HASKELL_ROOT'} . $1;
60     } else {
61         print STDERR "GLASGOW_HASKELL_ROOT environment variable is set;\nBut can't untangle $(INSTDATADIR_GHC).\n(Installation error)\n";
62         exit(1);
63     }
64 }
65
66 $Unlit = ( $(INSTALLING) ) ? "$InstLibDirGhc/unlit"
67                              : "$TopPwd/$(CURRENT_DIR)/$(GHC_UNLIT)";
68
69 $Begin_magic_str = "# DO NOT DELETE: Beginning of Haskell dependencies\n";
70 $End_magic_str = "# DO NOT DELETE: End of Haskell dependencies\n";
71 $Obj_suffix = '.o';
72 $ghc_version_info = $(PROJECTVERSION) * 100;
73 @Defines = ('-D__HASKELL1__=2', "-D__GLASGOW_HASKELL__=$ghc_version_info");
74
75 $Import_dirs = '.';
76 %Syslibs = ();
77 %StableLibs = ();
78 %PreludeIfaces = ( 'Prelude', '1',
79                    'PreludeGlaST', '1',
80                    'PreludeGlaMisc', '1',
81                    'Concurrent', '1',
82                    'Parallel', '1');
83 %GhcLibIfaces = (  'Bag', '1',
84                    'BitSet', '1',
85                    # CharSeq not supposed to be used by user (I think. WDP)
86                    'FiniteMap', '1',
87                    'ListSetOps', '1',
88                    'Maybes', '1',
89                    'PackedString', '1',
90                    'Regex', '1',
91                    'MatchPS', '1',
92                    'Readline', '1',
93                    'Socket', '1',
94                    'SocketPrim', '1',
95                    'BSD', '1',
96                    'Pretty', '1',
97                    'Set', '1',
98                    'Util', '1' );
99 %HbcLibIfaces = (  'Algebra', '1',
100                    'Hash', '1',
101                    'ListUtil', '1',
102                    'Miranda', '1',
103                    'NameSupply', '1',
104                    'Native', '1',
105                    'Number', '1',
106                    'Parse', '1',
107                    'Pretty', '1',
108                    'Printf', '1',
109                    'QSort', '1',
110                    'Random', '1',
111                    'SimpleLex', '1',
112                    'Time', '1',
113                    'Trace', '1',
114                    'Word', '1' );
115 %IO13Ifaces = (    'LibSystem', '1',
116                    'LibCPUTime', '1',
117                    'LibDirectory', '1',
118                    'LibPosix', '1',
119                    'LibTime', '1' );
120
121 $Haskell_1_3 = 0; # assume Haskell 1.2, still. Changed by -fhaskell-1.3
122 $Include_dirs = '-I.';
123 $Col_width = 78; # ignored
124 $Makefile = '';
125 @Src_files = ();
126
127 &mangle_command_line_args();
128
129 if ( ! $Makefile && -f 'makefile' ) {
130     $Makefile = 'makefile';
131 } elsif ( ! $Makefile && -f 'Makefile') {
132     $Makefile = 'Makefile';
133 } else {
134     die "$Pgm: no makefile or Makefile found\n";
135 }
136
137 @Depend_lines = ();
138
139 print STDERR "CPP defines=@Defines\n" if $Verbose;
140 print STDERR "Import_dirs=$Import_dirs\n" if $Verbose;
141 print STDERR "Include_dirs=$Include_dirs\n" if $Verbose;
142
143 foreach $sf (@Src_files) {
144     # just like lit-inputter
145     # except it puts each file through CPP and
146     # a de-commenter (not implemented);
147     # builds up @Depend_lines
148     print STDERR "Here we go for source file: $sf\n" if $Verbose;
149     ($bf = $sf) =~ s/\.l?hs$//;
150     push(@Depend_lines, "$bf$Obj_suffix : $sf\n");
151     foreach $suff (@File_suffix) {
152         push(@Depend_lines, "$bf$suff$Obj_suffix : $sf\n");
153     }
154
155     # if it's a literate file, .lhs, then we de-literatize it:
156     if ( $sf !~ /\.lhs$/ ) {
157         $file_to_read = $sf;
158     } else {
159         $file_to_read = "$Tmp_prefix.hs";
160         local($to_do) = "$Unlit $sf $file_to_read";
161         &run_something($to_do, 'unlit');
162     }
163     &slurp_file_for_imports($file_to_read, $sf);
164
165     if ( $sf =~ /\.lhs$/ ) {
166         unlink "$Tmp_prefix.hs";
167     }
168 }
169
170 # OK, mangle the Makefile
171 unlink("$Makefile.bak");
172 rename($Makefile,"$Makefile.bak");
173 # now copy Makefile.bak into Makefile, rm'ing old dependencies
174 # and adding the new
175 open(OMKF,"< $Makefile.bak") || die "$Pgm: can't open $Makefile.bak: $!\n";
176 open(NMKF,"> $Makefile") || die "$Pgm: can't open $Makefile: $!\n";
177 select(NMKF);
178 $_ = <OMKF>;
179 while ($_ && $_ ne $Begin_magic_str) { # copy through, 'til Begin_magic_str
180     print $_;
181     $_ = <OMKF>;
182 }
183 while ($_ && $_ ne $End_magic_str) { # delete 'til End_magic_str
184     $_ = <OMKF>;
185 }
186 # insert dependencies
187 print $Begin_magic_str;
188 print @Depend_lines;
189 print $End_magic_str;
190 while (<OMKF>) { # copy the rest through
191     print $_;
192 }
193 close(NMKF) || exit(1);
194 close(OMKF) || exit(1);
195 chmod 0444, 'Makefile';
196 exit 0;
197
198 sub mangle_command_line_args {
199     while($_ = $ARGV[0]) {
200         shift(@ARGV);
201
202         if ( /^--$/ ) {
203             $Dashdashes_seen++;
204
205         } elsif ( /^-D(.*)/ ) { # recognized wherever they occur
206             push(@Defines, $_);
207         } elsif ( /^-i(.*)/ ) {
208             $Import_dirs .= ":$1";
209         } elsif ( /^-I/ ) {
210             $Include_dirs .= " $_";
211         } elsif ( /^-syslib$/ ) {
212             push(@Syslibs, &grab_arg_arg($_,''));
213         } elsif ( /^-fhaskell-1\.3/ ) {
214             $Haskell_1_3 = 1;
215         } elsif ( /^-stable$/ ) { 
216             # user-defined syslibs that she believes are stable.
217             push(@StableLibs, &grab_arg_arg($_,''));
218
219         } elsif ($Dashdashes_seen != 1) { # not between -- ... --
220             if ( /^-v$/ ) {
221                 $Verbose        = '-v';
222             } elsif ( /^-f(.*)/ ) {
223                 $Makefile       = &grab_arg_arg('-f',$1);
224             } elsif ( /^-o(.*)/ ) {
225                 $Obj_suffix     = &grab_arg_arg('-o',$1);
226             } elsif ( /^-s(.*)/ ) {
227                 local($suff)    =  &grab_arg_arg('-s',$1);
228                 $File_suffix{$suff} = $suff;
229             } elsif ( /^-bs(.*)/ ) {
230                 $Begin_magic_str = &grab_arg_arg('-bs',$1) . "\n";
231             } elsif ( /^-es(.*)/ ) {
232                 $End_magic_str = &grab_arg_arg('-es',$1) . "\n";
233             } elsif ( /^-w(.*)/ ) {
234                 $Width  = &grab_arg_arg('-w',$1);
235             } elsif ( /^-/ ) {
236                 print STDERR "$Pgm: unknown option ignored: $_\n";
237             } else {
238                 push(@Src_files, $_);
239             }
240
241         } elsif ($Dashdashes_seen == 1) { # where we ignore unknown options
242             push(@Src_files,$_) if ! /^-/;
243         }
244     }
245     @File_suffix = sort (keys %File_suffix);
246 }
247
248 sub grab_arg_arg {
249     local($option, $rest_of_arg) = @_;
250     
251     if ($rest_of_arg) {
252         return($rest_of_arg);
253     } elsif ($#ARGV >= 0) {
254         local($temp) = $ARGV[0]; shift(@ARGV); 
255         return($temp);
256     } else {
257         print STDERR "$Pgm: no argument following $option option\n";
258         $Status++;
259     }
260 }
261
262 sub slurp_file_for_imports {
263     local($file_to_read, $orig_src_file) = @_;
264     local($follow_file);
265
266     local($last_seen_dir) = $orig_src_file;
267     $last_seen_dir =~ s/\/[^\/]+$//; # strip to dir name
268     $last_seen_dir = '.' if ($last_seen_dir eq $orig_src_file);
269
270     # we mangle #include's so they will also leave something
271     # behind to indicate the dependency on _them_
272
273     print STDERR "/usr/bin/sed -e '/^# *include/{p;s/^# *include/!include/;};s/'\\''//g;s/\"//g' $file_to_read | $Cpp $Include_dirs -I$last_seen_dir @Defines |\n" if $Verbose;
274
275     open(SRCFILE, "/usr/bin/sed -e '/^# *include/{p;s/^# *include/!include/;};s/'\\''//g;s/\"//g' $file_to_read | $Cpp $Include_dirs -I$last_seen_dir @Defines |")
276         || die "$Pgm: Can't open $file_to_read: $!\n";
277
278     while (<SRCFILE>) {
279         if (/^>?\s*import\s+([A-Z][A-Za-z0-9_']*)/ || /^!include\s+"(\S+)"/) {
280             $modname = $1;
281             if (/^>?\s*import/) {
282                 $follow_file = &find_in_Import_dirs($orig_src_file, $modname, $last_seen_dir);
283             } else {
284                 $follow_file = &find_in_Include_dirs($orig_src_file, $modname, $last_seen_dir);
285             }
286
287             if ($follow_file) { # it found something
288
289                 if ($follow_file ne '__syslib__') {
290                     local($int_file);
291                     $int_file = $follow_file;
292                     if ( $int_file !~ /\.(l?hs|hi)$/ ) {
293                         push(@Depend_lines, "$bf$Obj_suffix : $int_file\n");
294                         foreach $suff (@File_suffix) {
295                             push(@Depend_lines, "$bf$suff$Obj_suffix : $int_file\n");
296                         }
297
298                     } else {
299                         $int_file =~ s/\.l?hs$//;
300                         $int_file =~ s/\.hi$//;
301
302                         push(@Depend_lines, "$bf$Obj_suffix : $int_file.hi\n");
303                         foreach $suff (@File_suffix) {
304                             push(@Depend_lines, "$bf$suff$Obj_suffix : $int_file$suff.hi\n");
305                         }
306                     }
307                 }
308             } else {
309                 die "$orig_src_file: Couldn't handle: $_\n";
310             }
311         }
312     }
313     close(SRCFILE) || exit(1);
314 }
315
316 # when we see something, we cache that fact ('y').
317 # also, when we get a miss, we cache that (so we don't try later); ('n')
318 %FileExists = ();
319
320 sub find_in_Import_dirs {
321     local($orig_src_file, $modname, $last_seen_dir) = @_;
322     local($import_dir);
323     local($do_magical_check) = 0;
324     local($name_to_check);
325
326     # hop along Import_dir list
327     foreach $import_dir (split(/:/,$Import_dirs)) {
328         # handle . magically
329         if ($import_dir eq '.') {
330             # record that we should do a SPECIAL try for a file in last_seen_dir (LAST)
331             $do_magical_check = 1;
332         }
333
334         $name_to_check = "$import_dir/$modname.hi";
335         if ( $FileExists{$name_to_check} ne 'n' ) { # either 'y' or nothing
336             print STDERR "trying $name_to_check...\n" if $Verbose;
337             return($name_to_check) if $FileExists{$name_to_check} eq 'y';
338             if (-f $name_to_check) {
339                 $FileExists{$name_to_check} = 'y';
340                 return($name_to_check) ;
341             } else {
342                 $FileExists{$name_to_check} = 'n';
343             }
344         }
345
346         $name_to_check = "$import_dir/$modname.hs";
347         print STDERR "trying... $name_to_check\n" if $Verbose;
348         return($name_to_check) if -f $name_to_check;
349
350         $name_to_check = "$import_dir/$modname.lhs";
351         print STDERR "trying... $name_to_check\n" if $Verbose;
352         return($name_to_check) if -f $name_to_check;
353     }
354     if ($do_magical_check == 1) {
355         $name_to_check = "$last_seen_dir/$modname.hi";
356
357         if ( $FileExists{$name_to_check} ne 'n' ) { # either 'y' or nothing
358             print STDERR "trying $name_to_check...\n" if $Verbose;
359             return($name_to_check) if $FileExists{$name_to_check} eq 'y';
360             if (-f $name_to_check) {
361                 $FileExists{$name_to_check} = 'y';
362                 return($name_to_check) ;
363             } else {
364                 $FileExists{$name_to_check} = 'n';
365             }
366         }
367
368         $name_to_check = "$last_seen_dir/$modname.lhs";
369         print STDERR "trying... $name_to_check\n" if $Verbose;
370         return($name_to_check) if -f $name_to_check;
371
372         $name_to_check = "$last_seen_dir/$modname.hs";
373         print STDERR "trying... $name_to_check\n" if $Verbose;
374         return($name_to_check) if -f $name_to_check;
375     }
376     # OK, maybe it's referring to something in a system library
377     foreach $lib ( @Syslibs ) {
378         if ( $lib eq 'ghc' ) {
379             return('__syslib__') if $GhcLibIfaces{$modname};
380         } elsif ( $lib eq 'hbc' ) {
381             return('__syslib__') if $HbcLibIfaces{$modname};
382         } else {
383             die "Unrecognised syslib: $lib\n";
384         }
385     }
386
387     # HACK HACK: Let the user define his own "stable" modules.
388     foreach $stableLib ( @StableLibs ) {
389         return('__syslib__') if ( $stableLib eq $modname );
390     }
391
392     # Might be a Haskell 1.3 Module (but only if we've said -fhaskell-1.3)
393     if ( $Haskell_1_3 == 1 ) {
394         return('__syslib__') if $IO13Ifaces{$modname};
395     }
396
397     # Last hope: referring to a Prelude interface
398     return('__syslib__') if $PreludeIfaces{$modname};
399
400     die "No file `$modname.hi', `$modname.lhs' or `$modname.hs' (reqd from file `$orig_src_file')\namong import directories:\n\t$Import_dirs\n";
401 }
402
403 sub find_in_Include_dirs {
404     local($orig_src_file, $name, $last_seen_dir) = @_;
405     local($include_dir);
406     local($do_magical_check) = 0;
407
408     # no funny name guessing here
409
410     # hop along Include_dir list
411     foreach $include_dir (split(/\s+/,$Include_dirs)) {
412         $include_dir =~ s/^-I//;
413
414         # handle . magically
415         if ($include_dir eq '.') {
416             # record that we should do a SPECIAL try for a file in last_seen_dir (LAST)
417             $do_magical_check = 1;
418         }
419         print STDERR "trying $include_dir/$name...\n" if $Verbose;
420         if (-f "$include_dir/$name") {
421             return("$include_dir/$name");
422         }
423     }
424     if ($do_magical_check == 1) {
425         print STDERR "trying $last_seen_dir/$name...\n" if $Verbose;
426         if (-f "$last_seen_dir/$name") {
427             return("$last_seen_dir/$name");
428         }
429     }
430     die "No file `$name' (reqd from file `$orig_src_file') among include directories: $Include_dirs\n";
431 }
432
433 # out of the driver, actually
434 sub run_something {
435     local($str_to_do, $tidy_name) = @_;
436
437     print STDERR "\n$tidy_name:\n\t" if $Verbose;
438     print STDERR "$str_to_do\n" if $Verbose;
439
440     local($return_val) = system($str_to_do) >> 8;
441
442     if ($return_val != 0) {
443         local($die_msg) = "$Pgm: execution of the $tidy_name had trouble";
444         $die_msg .= " (program not found)" if $return_val == 255;
445         $die_msg .= " ($!)" if $Verbose && $! != 0;
446         $die_msg .= "\n";
447         print STDERR $die_msg;
448         exit $return_val;
449     }
450 }