[project @ 1996-01-08 20:28:12 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     ($of = $sf) =~ s/\.l?hs$/$Obj_suffix/;
150     push(@Depend_lines, "$of : $sf\n");
151
152     # if it's a literate file, .lhs, then we de-literatize it:
153     if ( $sf !~ /\.lhs$/ ) {
154         $file_to_read = $sf;
155     } else {
156         $file_to_read = "$Tmp_prefix.hs";
157         local($to_do) = "$Unlit $sf $file_to_read";
158         &run_something($to_do, 'unlit');
159     }
160     &slurp_file_for_imports($file_to_read, $sf);
161
162     if ( $sf =~ /\.lhs$/ ) {
163         unlink "$Tmp_prefix.hs";
164     }
165 }
166
167 # OK, mangle the Makefile
168 unlink("$Makefile.bak");
169 rename($Makefile,"$Makefile.bak");
170 # now copy Makefile.bak into Makefile, rm'ing old dependencies
171 # and adding the new
172 open(OMKF,"< $Makefile.bak") || die "$Pgm: can't open $Makefile.bak: $!\n";
173 open(NMKF,"> $Makefile") || die "$Pgm: can't open $Makefile: $!\n";
174 select(NMKF);
175 $_ = <OMKF>;
176 while ($_ && $_ ne $Begin_magic_str) { # copy through, 'til Begin_magic_str
177     print $_;
178     $_ = <OMKF>;
179 }
180 while ($_ && $_ ne $End_magic_str) { # delete 'til End_magic_str
181     $_ = <OMKF>;
182 }
183 # insert dependencies
184 print $Begin_magic_str;
185 print @Depend_lines;
186 print $End_magic_str;
187 while (<OMKF>) { # copy the rest through
188     print $_;
189 }
190 close(NMKF) || exit(1);
191 close(OMKF) || exit(1);
192 chmod 0444, 'Makefile';
193 exit 0;
194
195 sub mangle_command_line_args {
196     while($_ = $ARGV[0]) {
197         shift(@ARGV);
198
199         if ( /^--$/ ) {
200             $Dashdashes_seen++;
201
202         } elsif ( /^-D(.*)/ ) { # recognized wherever they occur
203             push(@Defines, $_);
204         } elsif ( /^-i(.*)/ ) {
205             $Import_dirs .= ":$1";
206         } elsif ( /^-I/ ) {
207             $Include_dirs .= " $_";
208         } elsif ( /^-syslib$/ ) {
209             push(@Syslibs, &grab_arg_arg($_,''));
210         } elsif ( /^-fhaskell-1\.3/ ) {
211             $Haskell_1_3 = 1;
212         } elsif ( /^-stable$/ ) { 
213             # user-defined syslibs that she believes are stable.
214             push(@StableLibs, &grab_arg_arg($_,''));
215
216         } elsif ($Dashdashes_seen != 1) { # not between -- ... --
217             if ( /^-v$/ ) {
218                 $Verbose        = '-v';
219             } elsif ( /^-f(.*)/ ) {
220                 $Makefile       = &grab_arg_arg('-f',$1);
221             } elsif ( /^-o(.*)/ ) {
222                 $Obj_suffix     = &grab_arg_arg('-o',$1);
223             } elsif ( /^-bs(.*)/ ) {
224                 $Begin_magic_str = &grab_arg_arg('-bs',$1) . "\n";
225             } elsif ( /^-es(.*)/ ) {
226                 $End_magic_str = &grab_arg_arg('-es',$1) . "\n";
227             } elsif ( /^-w(.*)/ ) {
228                 $Width  = &grab_arg_arg('-w',$1);
229             } elsif ( /^-/ ) {
230                 print STDERR "$Pgm: unknown option ignored: $_\n";
231             } else {
232                 push(@Src_files, $_);
233             }
234
235         } elsif ($Dashdashes_seen == 1) { # where we ignore unknown options
236             push(@Src_files,$_) if ! /^-/;
237         }
238     }
239 }
240
241 sub grab_arg_arg {
242     local($option, $rest_of_arg) = @_;
243     
244     if ($rest_of_arg) {
245         return($rest_of_arg);
246     } elsif ($#ARGV >= 0) {
247         local($temp) = $ARGV[0]; shift(@ARGV); 
248         return($temp);
249     } else {
250         print STDERR "$Pgm: no argument following $option option\n";
251         $Status++;
252     }
253 }
254
255 sub slurp_file_for_imports {
256     local($file_to_read, $orig_src_file) = @_;
257     local($follow_file);
258
259     local($last_seen_dir) = $orig_src_file;
260     $last_seen_dir =~ s/\/[^\/]+$//; # strip to dir name
261     $last_seen_dir = '.' if ($last_seen_dir eq $orig_src_file);
262
263     # we mangle #include's so they will also leave something
264     # behind to indicate the dependency on _them_
265
266     print STDERR "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;
267
268     open(SRCFILE, "sed -e '/^# *include/{p;s/^# *include/!include/;};s/'\\''//g;s/\"//g' $file_to_read | $Cpp $Include_dirs -I$last_seen_dir @Defines |")
269         || die "$Pgm: Can't open $file_to_read: $!\n";
270
271     while (<SRCFILE>) {
272         if (/^>?\s*import\s+([A-Z][A-Za-z0-9_']*)/ || /^!include\s+"(\S+)"/) {
273             $modname = $1;
274             if (/^>?\s*import/) {
275                 $follow_file = &find_in_Import_dirs($orig_src_file, $modname, $last_seen_dir);
276             } else {
277                 $follow_file = &find_in_Include_dirs($orig_src_file, $modname, $last_seen_dir);
278             }
279
280             if ($follow_file) { # it found something
281
282                 if ($follow_file ne '__syslib__') {
283                     local($int_file);
284                     ($int_file = $follow_file) =~ s/\.l?hs$/\.hi/;
285
286                     push(@Depend_lines, "$of : $int_file\n");
287                 }
288             } else {
289                 die "$orig_src_file: Couldn't handle: $_\n";
290             }
291         }
292     }
293     close(SRCFILE) || exit(1);
294 }
295
296 # when we see something, we cache that fact ('y').
297 # also, when we get a miss, we cache that (so we don't try later); ('n')
298 %FileExists = ();
299
300 sub find_in_Import_dirs {
301     local($orig_src_file, $modname, $last_seen_dir) = @_;
302     local($import_dir);
303     local($do_magical_check) = 0;
304     local($name_to_check);
305
306     # hop along Import_dir list
307     foreach $import_dir (split(/:/,$Import_dirs)) {
308         # handle . magically
309         if ($import_dir eq '.') {
310             # record that we should do a SPECIAL try for a file in last_seen_dir (LAST)
311             $do_magical_check = 1;
312         }
313
314         $name_to_check = "$import_dir/$modname.hi";
315         if ( $FileExists{$name_to_check} ne 'n' ) { # either 'y' or nothing
316             print STDERR "trying $name_to_check...\n" if $Verbose;
317             return($name_to_check) if $FileExists{$name_to_check} eq 'y';
318             if (-f $name_to_check) {
319                 $FileExists{$name_to_check} = 'y';
320                 return($name_to_check) ;
321             } else {
322                 $FileExists{$name_to_check} = 'n';
323             }
324         }
325
326         $name_to_check = "$import_dir/$modname.hs";
327         print STDERR "trying... $name_to_check\n" if $Verbose;
328         return($name_to_check) if -f $name_to_check;
329
330         $name_to_check = "$import_dir/$modname.lhs";
331         print STDERR "trying... $name_to_check\n" if $Verbose;
332         return($name_to_check) if -f $name_to_check;
333     }
334     if ($do_magical_check == 1) {
335         $name_to_check = "$last_seen_dir/$modname.hi";
336
337         if ( $FileExists{$name_to_check} ne 'n' ) { # either 'y' or nothing
338             print STDERR "trying $name_to_check...\n" if $Verbose;
339             return($name_to_check) if $FileExists{$name_to_check} eq 'y';
340             if (-f $name_to_check) {
341                 $FileExists{$name_to_check} = 'y';
342                 return($name_to_check) ;
343             } else {
344                 $FileExists{$name_to_check} = 'n';
345             }
346         }
347
348         $name_to_check = "$last_seen_dir/$modname.lhs";
349         print STDERR "trying... $name_to_check\n" if $Verbose;
350         return($name_to_check) if -f $name_to_check;
351
352         $name_to_check = "$last_seen_dir/$modname.hs";
353         print STDERR "trying... $name_to_check\n" if $Verbose;
354         return($name_to_check) if -f $name_to_check;
355     }
356     # OK, maybe it's referring to something in a system library
357     foreach $lib ( @Syslibs ) {
358         if ( $lib eq 'ghc' ) {
359             return('__syslib__') if $GhcLibIfaces{$modname};
360         } elsif ( $lib eq 'hbc' ) {
361             return('__syslib__') if $HbcLibIfaces{$modname};
362         } else {
363             die "Unrecognised syslib: $lib\n";
364         }
365     }
366
367     # HACK HACK: Let the user define his own "stable" modules.
368     foreach $stableLib ( @StableLibs ) {
369         return('__syslib__') if ( $stableLib eq $modname );
370     }
371
372     # Might be a Haskell 1.3 Module (but only if we've said -fhaskell-1.3)
373     if ( $Haskell_1_3 == 1 ) {
374         return('__syslib__') if $IO13Ifaces{$modname};
375     }
376
377     # Last hope: referring to a Prelude interface
378     return('__syslib__') if $PreludeIfaces{$modname};
379
380     die "No file `$modname.hi', `$modname.lhs' or `$modname.hs' (reqd from file `$orig_src_file')\namong import directories:\n\t$Import_dirs\n";
381 }
382
383 sub find_in_Include_dirs {
384     local($orig_src_file, $name, $last_seen_dir) = @_;
385     local($include_dir);
386     local($do_magical_check) = 0;
387
388     # no funny name guessing here
389
390     # hop along Include_dir list
391     foreach $include_dir (split(/\s+/,$Include_dirs)) {
392         $include_dir =~ s/^-I//;
393
394         # handle . magically
395         if ($include_dir eq '.') {
396             # record that we should do a SPECIAL try for a file in last_seen_dir (LAST)
397             $do_magical_check = 1;
398         }
399         print STDERR "trying $include_dir/$name...\n" if $Verbose;
400         if (-f "$include_dir/$name") {
401             return("$include_dir/$name");
402         }
403     }
404     if ($do_magical_check == 1) {
405         print STDERR "trying $last_seen_dir/$name...\n" if $Verbose;
406         if (-f "$last_seen_dir/$name") {
407             return("$last_seen_dir/$name");
408         }
409     }
410     die "No file `$name' (reqd from file `$orig_src_file') among include directories: $Include_dirs\n";
411 }
412
413 # out of the driver, actually
414 sub run_something {
415     local($str_to_do, $tidy_name) = @_;
416
417     print STDERR "\n$tidy_name:\n\t" if $Verbose;
418     print STDERR "$str_to_do\n" if $Verbose;
419
420     local($return_val) = system($str_to_do) >> 8;
421
422     if ($return_val != 0) {
423         local($die_msg) = "$Pgm: execution of the $tidy_name had trouble";
424         $die_msg .= " (program not found)" if $return_val == 255;
425         $die_msg .= " ($!)" if $Verbose && $! != 0;
426         $die_msg .= "\n";
427         print STDERR $die_msg;
428         exit $return_val;
429     }
430 }