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