This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Also add all utilities for building from units to repo
[metaconfig.git] / bin / jmake
1 #!/usr/bin/perl
2         eval 'exec perl -S $0 "$@"'
3                 if $runnning_under_some_shell;
4
5 # $Id: jmake.SH 20 2008-01-04 23:14:00Z rmanfredi $
6 #
7 #  Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi
8 #  
9 #  You may redistribute only under the terms of the Artistic Licence,
10 #  as specified in the README file that comes with the distribution.
11 #  You may reuse parts of this distribution only within the terms of
12 #  that same Artistic Licence; a copy of which may be found at the root
13 #  of the source tree for dist 4.0.
14 #
15 # $Log: jmake.SH,v $
16 # Revision 3.0.1.9  2004/08/22 09:01:42  ram
17 # patch71: renamed |test as |case as the construct has its syntax
18 # patch71: added |subst section to allow variable substitutions
19 #
20 # Revision 3.0.1.8  2004/08/21 23:19:46  ram
21 # patch71: added '|shell' section to emit verbatim code in Makefile.SH
22 # patch71: new '|test' to conditionally generate Makefile sections
23 #
24 # Revision 3.0.1.7  2004/08/21 20:59:57  ram
25 # patch71: replaced old "do foo()" with modern "&foo()" syntax
26 # patch71: take care of junk emitted by GNU make when running commands
27 # patch71: new ^^^ escape sequence, removing extra spaces afterwards
28 #
29 # Revision 3.0.1.6  1995/09/25  09:08:01  ram
30 # patch59: will now force macro definitions to the left
31 #
32 # Revision 3.0.1.5  1995/07/25  13:34:47  ram
33 # patch56: all error messages are now prefixed with the program name
34 #
35 # Revision 3.0.1.4  1995/03/21  08:45:27  ram
36 # patch52: now invokes cpp through new fixcpp script
37 # patch52: first pass now skips cpp comments alltogether
38 #
39 # Revision 3.0.1.3  1994/10/29  15:47:01  ram
40 # patch36: added various escapes in strings for perl5 support
41 #
42 # Revision 3.0.1.2  1993/08/24  12:12:50  ram
43 # patch3: privlib dir was ~name expanded in the wrong place
44 #
45 # Revision 3.0.1.1  1993/08/19  06:42:13  ram
46 # patch1: leading config.sh searching was not aborting properly
47 #
48 # Revision 3.0  1993/08/18  12:04:17  ram
49 # Baseline for dist 3.0 netwide release.
50 #
51
52 $dir = '/pro/3gl/CPAN/lib/dist/files';
53 $cpp = '/usr/bin/cpp';
54 $version = '3.5';
55 $patchlevel = '0';
56
57 ($me = $0) =~ s|.*/(.*)|$1|;
58 $dir = &tilda_expand($dir);             # ~name expansion
59 $file = $dir . '/Jmake.tmpl';
60
61 $cpp_opt = "-I. ";                              # For Jmakefile, which is local
62 while ($ARGV[0] =~ /^-/) {
63         $_ = shift;
64         last if /--/;
65         $cpp_opt .= "$_ ";
66 }
67 $cpp_opt .= "-I$dir";
68
69 # Pass 0 is looking at the template for "?CP:CP =" lines that are to be
70 # emitted if the CP variable is needed.  Later on, when we see $(CP) being
71 # used, we'll be able to set the $symbol{CP} entry to 1 to have the CP
72 # variable initialized by the template.
73
74 open(TMPL, $file) || die "$me: can't open $file: $!\n";
75 while (<TMPL>) {
76         next unless /^\?([\w_]+):\1\s+=/;
77         $wanted{$1}++;
78 }
79 close TMPL;
80
81 # Thank you HP-UX for having a cpp that blindly strips trailing backslashes
82 # in the text. Run through cpp by using the fixcpp script...
83
84 open(CPP, "$dir/fixcpp $cpp_opt $file |");
85 while (<CPP>) {
86         # Record defined symbols in Jmakefile. We won't catch symbols
87         # in conditional commands, but that's ok, I hope.
88         if ($in_symbol) {
89                 $val = $_;
90                 $in_symbol = 0 if !($val =~ s/\\\s*$//);        # Last line
91                 if ($val = /^\|expand/) {               # Found an expand command
92                         $in_symbol = 0;                         # Stop gathering value
93                         $val .= "void::x";                      # Stop any incomplete escape sequence
94                 }
95                 chop($val);
96                 $Makesym{$current_symbol} .= $val;
97         } elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) {
98                 # Found a makefile's macro declaration
99                 $val = $2;
100                 $current_symbol = $1;
101                 if ($val =~ s/\\\s*$//) {       # Remove final '\'
102                         $in_symbol = 1;                 # This is a continuation line
103                 }
104                 $Makesym{$current_symbol} = $val;
105                 push(@Order, $current_symbol);  # Keep track of order
106         }
107         # Protect RCS keyword Id or Header from normal substitution
108         s/\$(Id|Header|Log)/\$X-$1/;
109         # Restore possibly escaped C comments
110         s|/#\*|/*|g;
111         s|\*#/|*/|g;
112         # Remove all ^^^ (null space character) up to next non-space character
113         s|\^\^\^\s*||g;
114         # Remove all ^^ (null space character)
115         s|\^\^||g;
116         # Restore escaped ^^ and ^^^ sequences
117         s|\^\\\^\\\^|^^^|g;
118         s|\^\\\^|^^|g;
119         next if /^#\s+\d+/;             # Skip cpp commments
120
121         s/^;#/#/;
122         s/@#\s?/\n/g;           # Kept for backward compatibility
123         s/@!\s?/\n/g;
124         s/@@\s?/\n\t/g;
125
126         # A '\r' is added to all lines, in order to let 'split' keep them
127         # As lines ending with '\' won't fit in the next regular
128         # expression (why ?), we have to treat that special case separately
129         s/\n$/\r\n/gm;
130         s/\\\s*$/\\\r/gm;       # Remove spaces after final '\' and add '\r'
131         @macro = split(/\n/);
132         for ($i = 0; $i <= $#macro; $i++) {
133                 chop($_ = $macro[$i]);                          # Remove final '\r'
134                 s/\s+$//g;                                                      # Remove possible useless spaces
135                 if (/^TOP\s*=\s*(\S+)/) {                       # Get the top from generated file
136                         $top = $1;
137                 }
138                 find_wanted($_);                                        # Look for known $(VAR) usage
139                 if (s/^\s*>//) {                                        # '>' means "symbol wanted"
140                         warn "$me: the '>$_' construct is deprecated for known symbols\n"
141                                 if $wanted{$_} && !$warned_wanted_symbol_deprecated++;
142                         $symbol{$_} = 1;
143                 } elsif (s/^\s*\+//) {                          # '+' means "initialization section"
144                         if (s/^\+(\w+)//) {                             # '++' means add to variable list
145                                 $added{$1} .= $_;
146                         } else {                                                # A single '+' means "add as is".
147                                 push(@init, $_);
148                         }
149                 } elsif (s/^\|//) {                                     # Command for us
150                         if (/suffix\s+(\S+)/) {                 # Add suffix
151                                 push(@suffix, $1) unless $seen{$1};
152                                 $seen{$1} = 1;
153                         } elsif (s/^rule://) {                  # Add building rule
154                                 s/^\s(\s*\S+)/\t$1/;            # Make sure leading tab is there
155                                 push(@rule, $_);
156                         } elsif (/^skip/) {                             # Unconditional skip... funny!
157                                 push(@makefile, "|$_");         # Skip handled in pass 2
158                         } elsif (/^expand/) {
159                                 push(@makefile, "|$_");         # Expand handled in pass 2
160                         } elsif (/^once\s+(.*)/) {              # Once handled in pass 1
161                                 if ($Once{$1}++) {                      # Symbol already seen -- skip
162                                         for (; $i <= $#macro; $i++) {
163                                                 last if $macro[$i] =~/^-once/;
164                                         }
165                                         warn("$me: -once not found for $1")
166                                                 unless $macro[$i] =~/^-once/;
167                                 }
168                         } elsif (/^shell/) {                    # Escaping to shell
169                                 push(@makefile, "|$_");         # will be handled in pass 2
170                         } elsif (/^case/) {                             # Conditional generation
171                                 push(@makefile, "|$_");         # will be handled in pass 2
172                         } elsif (/^subst/) {                    # Section with var substitution
173                                 push(@makefile, "|$_");         # will be handled in pass 2
174                         } else {
175                                 print "$me: Warning: unknown command $_\n";
176                         }
177                 } else {
178                         next if /^-once/;                       # Control statement removed
179                         push(@makefile, $_);
180                 }
181         }
182 }
183 close CPP;
184
185 @key = keys(%added);
186 $last_was_blank = 1;    # To avoid blank line at the top of the file
187 $symbol{'INIT'} = 1 if ($#init >= 0 || $#key >=0);              # Initializations
188 $symbol{'SUFFIX'} = 1 if ($#suffix >= 0 || $#rule >=0); # Rules or suffixes
189 $symbol{'TOP'} = 1 if $top eq '.';              # If imake invoked for the top
190
191 $shellmode = 0;                 # Set to true within "shell" section
192 $casemode = 0;                  # Counts nesting levels within "case" section
193 $substmode = 0;                 # True when within section with variable substitution
194
195 $SPIT_START = "\$spitshell >>Makefile <<'!NO!SUBS!'\n";
196 $SPIT_END = "!NO!SUBS!\n";
197 $GROK_START = "\$spitshell >>Makefile <<!GROK!THIS!\n";
198 $GROK_END = "!GROK!THIS!\n";
199
200 open(MAKEFILE, ">Makefile.SH");
201 # We have to use for instead of foreach to handle 'skip' easily
202 line: for ($i = 0; $i <= $#makefile; $i++) {
203         $_ = $makefile[$i];
204         next if /^-skip|-expand/;               # They might have made a mistake
205
206         # Strip consecutive blank lines in generated file
207
208         if (/^\s*$/) {
209                 next if ($last_was_blank);
210                 $last_was_blank = 1;
211         } else {
212                 $last_was_blank = 0;
213         }
214
215         # In shell mode, we're transparent, untill we reach a "-shell"
216         # We don't call print_makefile() as we don't want to record
217         # those non-makefile lines in the @Generated array.
218
219         if ($shellmode) {
220                 if (/^-shell/) {                        # Ending shell mode, back to Makefile
221                         print MAKEFILE $substmode ? $GROK_START : $SPIT_START;
222                         $shellmode = 0;
223                 } elsif (/^\|shell/) {
224                         die "$me: can't nest 'shell' sections.\n";
225                 } else {
226                         print MAKEFILE "$_\n";
227                 }
228                 next;
229         } elsif (/^\|shell/) {
230                 print MAKEFILE $substmode ? $GROK_END : $SPIT_END;
231                 $shellmode = 1;                         # Next lines emitted verbatim as shell
232                 next;
233         }
234
235         # In subst mode, the section until "-subst" is emitted regularily,
236         # excepted that it will be in a grok section, so its $var will be
237         # substituted by the shell.
238
239         if ($substmode) {
240                 if (/^-subst/) {                        # Ending subst mode, back to regular
241                         print MAKEFILE $GROK_END;
242                         print MAKEFILE $SPIT_START;
243                         $substmode = 0;
244                         next;
245                 } elsif (/^\|subst/) {
246                         die "$me: can't nest 'subst' sections.\n";
247                 } 
248                 # Continue with line
249         } elsif (/^\|subst/) {
250                 print MAKEFILE $SPIT_END;       # End spit section in Makefile.SH
251                 print MAKEFILE $GROK_START;
252                 $substmode = 1;                         # Next lines subject to $ interpretation
253                 next;
254         }
255
256         # In a "case" section, the Makefile will be conditionally generated
257         # based on the value of the supplied variable, as evaluated by the shell.
258         # We can nest "case" sections without problems.
259
260         if (/^-case/) {                                 # Ending current case section
261                 if ($casemode == 0) {
262                         warn "$me: ignoring spurious '-case'\n";
263                         next;
264                 }
265                 print MAKEFILE $substmode ? $GROK_END : $SPIT_END;
266                 my $indent = "\t" x ($casemode - 1);
267                 print MAKEFILE "${indent}\t;;\n";
268                 print MAKEFILE "${indent}esac\n";
269                 print MAKEFILE "${indent}", $substmode ? $GROK_START : $SPIT_START;
270                 $casemode--;
271                 next;
272         }
273
274         if (/^\|case/) {
275                 my ($var, $value) = /^\|case\s+(\w+)\s+in\s+(.*)/;
276                 die "$me: unparseable directive '$_'\n" if $var eq '';
277                 $casemode++;
278                 print MAKEFILE $substmode ? $GROK_END : $SPIT_END;
279                 my $indent = "\t" x ($casemode - 1);
280                 print MAKEFILE "${indent}case \"\$$var\" in\n";
281                 print MAKEFILE "${indent}$value)\n";
282                 print MAKEFILE "${indent}\t", $substmode ? $GROK_START : $SPIT_START;
283                 next;
284         }
285
286         # Process regular line to be generated in Makefile.SH
287
288         s/<TAG>/[jmake $version PL$patchlevel]/;
289
290         # Lines starting with ?SYMBOL: (resp. %SYMBOL:) are to be processed
291         # only if SYMBOL is defined (resp. undefined).
292
293         # Apply in sequence
294         while (/^\s*\?|\s*%/) {
295                 if (s/^\s*\?(\w+)://) {                                 # Wanted symbol ?
296                         next line unless $symbol{$1};
297                 } elsif (s/^\s*%(\w+)://) {                             # Unwanted symbol ?
298                         next line if $symbol{$1};
299                 } else {
300                         print "$me: Warning: missing ':' in $_\n";
301                         last;
302                 }
303         }
304
305         # We wish to make sure there is a leading tab if the line starts with
306         # a space to prevent problems later on. However, variable definitions
307         # might want to be aligned on the '=' (imake style). Not all make
308         # may be able to cope with those though, so they are left justified
309         # again.
310
311         s/^\s/\t/ unless /^\s+\w+\s+=/;         # Make sure leading tab is there
312         s/^\s+(\w+\s+=)/$1/;                            # Left justify variable definition
313         s/^;#/#/;                                                       # Comments in Jmakefile
314
315         if (s/^\|//) {                                          # Command for us
316                 if (/^skip/) {                                  # Skip until -skip
317                         for (; $i <= $#makefile; $i++) {
318                                 last if $makefile[$i] =~ /^-skip/;
319                         }
320                 } elsif (s/^expand//) {
321                         &init_expand($_);                       # Initializes data structures
322                         $i++;                                           # Skip expand line
323                         undef @Expand;                          # Storage for expanded lines
324                         $pattern = '';                          # Assume no pattern
325                         for (; $i <= $#makefile; $i++) {
326                                 $_ = $makefile[$i];
327                                 if (s/^-expand//) {                     # Reached end of expansion
328                                         if (s/^\s*(.*)/$1/) {   # Expand followed by a pattern
329                                                 $pattern = $_;          # Get pattern to be removed
330                                         }
331                                         last;
332                                 }
333                                 s/^\s/\t/;                              # Make sure leading tab is there
334                                 push(@Expand, $_);              # Line to be expanded
335                         }
336                         &expand($pattern);                      # Expand all lines in buffer
337                 } else {
338                         die "$me: unknown command $_\n";
339                 }
340         } elsif (/^INIT/) {                                             # Initialization section
341                 # All the initializations are put in the variable substitution
342                 # section of the Makefile.SH. Therefore, we have to protect all
343                 # the '$' signs that are not followed by an alphanumeric character.
344                 foreach (@init) {
345                         # Dumps core sometimes with perl 4.0 PL10
346                         # &protect_dollars(*_);
347                         $_ = &protect_dollars($_);
348                         &print_makefile($_);
349                 }
350                 foreach (@key) {        # @key set earlier to keys(%added)
351                         $_ .= " = " . $added{$_};
352                         # Dumps core sometimes with perl 4.0 PL10
353                         # &protect_dollars(*_);
354                         $_ = &protect_dollars($_);
355                         &print_makefile($_);
356                 }
357         } elsif (/^SUFFIX/) {                                   # Suffixes/Rules section
358                 # Rules and suffixes are put in the variable substitution
359                 # section of the Makefile.SH. Therefore, we have to protect all
360                 # the '$' signs that are not followed by an alphanumeric character.
361                 if ($#suffix >= 0) {
362                         print MAKEFILE ".SUFFIXES:";
363                         foreach (@suffix) {
364                                 # Dumps core sometimes with perl 4.0 PL10
365                                 # &protect_dollars(*_);
366                                 $_ = &protect_dollars($_);
367                                 print MAKEFILE " $_";
368                         }
369                         print MAKEFILE "\n\n";
370                 }
371                 foreach (@rule) {
372                         # Dumps core sometimes with perl 4.0 PL10
373                         # &protect_dollars(*_);
374                         $_ = &protect_dollars($_);
375                         print MAKEFILE "$_\n";
376                 }
377         } else {
378                 &print_makefile($_);
379         }
380 }
381 close MAKEFILE;
382
383 sub protect_dollars {
384         # Dumps core sometimes with perl 4.0 PL10
385         # local(*_) = shift(@_);
386         s/\\\$/\\=/g;           # Protect already escaped '$'
387         s/(\$\W)/\\$1/g;        # Escape unprotected '$'
388         s/\\=/\\\$/g;           # Restore escaped '$'
389         $_;                                     # Because perl dumps core... :-(
390 }
391
392 # Initializes data structures for expansion. If we detect Makefile
393 # macro in the 'expand' line (the argument), then we write a small
394 # makefile that will do the substitution for us -- I'm lazy today :-)
395 sub init_expand {
396         local($_) = shift(@_);
397         undef %Vars;            # Reset array of variables
398         $Vars_len = 0;          # Number of "symbols" in first expanded
399         if (/\$\(\w+\)/) {      # If at least one macro
400                 local($make) = "/tmp/mkjm$$";
401                 open(MAKE, ">$make") || die "$me: can't create $make: $!\n";
402                 &gen_variables();                       # Generates already computed variables
403                 foreach $var (@Order) {         # Print each in order we found them
404                         print MAKE "$var = $Makesym{$var}\n" if !$Gvars{$var};
405                 }
406                 # We prepend OUTPUT: in front of the line that interests us, because
407                 # some makes can print extra information, especially GNU make with
408                 # its entering/leaving blurb when invoked from another makefile.
409                 print MAKE "all:\n\t\@echo 'OUTPUT: $_'\n";
410                 close MAKE;
411                 chop($_ = `make -f $make all | grep ^OUTPUT:`);
412                 unlink($make);
413         }
414         s/^OUTPUT: //;
415         while (s/^\s*(\w+)!([^!]*)!//) {
416                 $Vars{$1} = $2;
417                 # Record only length for _first_ expanded symbol
418                 $Vars_len = split(/\s\s*/, $2) unless $Vars_len;
419         }
420 }
421
422 # Expand lines in the @Expand array. The argument is a pattern which is to
423 # be removed from the last chunk of expanded lines.
424 # For each symbol s, !s is replaced by the next item, and !s:p=q does the
425 # same after having replaced the pattern 'p' by pattern 'q' in the item.
426 # Spaces are NOT allowed in 'p' or 'q'. Substitution is done once (no /g).
427 sub expand {
428         local($pattern) = shift;                # To-be-removed pattern for last chunk
429         local($_);
430         local($sub);
431         local($i);
432         local(@expands);
433         for ($i = 0; $i < $Vars_len; $i++) {
434                 foreach $line (@Expand) {
435                         $_ = $line;             # Don't modify elements in array
436                         foreach $sym (keys %Vars) {
437                                 @expands = split(/\s\s*/, $Vars{$sym});
438                                 $sub = $expands[$i];
439                                 $sub =~ s/\/\///g;              # // is a void value
440                                 while (s/!${sym}:([^\s]*)=([^\s]*)/,x##x,/) {
441                                         # Replacing item is altered by some pattern
442                                         local($p) = $1;
443                                         local($q) = $2;
444                                         local($subq) = $sub;
445                                         eval "\$subq =~ s=${p}=${q}=";
446                                         s/,x##x,/${subq}/;
447                                 }
448                                 s/!${sym}/${sub}/g;
449                         }
450                         # Protect substitution in an 'eval' in case of error
451                         eval "s/${pattern}\$//" if $pattern && $i == ($Vars_len - 1);
452                         &print_makefile($_);
453                 }
454         }
455 }
456
457 # Prints its argument in MAKEFILE and records it also in Generated
458 sub print_makefile {
459         local($_) = shift(@_);          # Line to be printed
460         print MAKEFILE "$_\n";
461         push(@Generated, "$_\n");
462 }
463
464 # Generates in MAKE file all the generated variable we have so far for
465 # final Makefile. This is mainly intended to allow expansion of variables
466 # which are already defined with an expand.
467 sub gen_variables {
468         undef %Gvars;                           # Reset already generated variables
469         local ($in_symbol) = 0;         # True when in variable (Makefile's macro)
470         foreach (@Generated) {
471                 if ($in_symbol) {
472                         if (/^\s*(\w+)\s*=(.*)/) {              # Missed the end of previous macro
473                                 $in_symbol = 0;
474                                 $Gvars{$1} = 1;                                 # Definition of variable seen
475                                 $in_symbol = 1 if (/\\\s*$/);   # There is a final '\'
476                                 print MAKE "void::\n";                  # Cut incomplete esc sequence
477                         } else  {
478                                 $in_symbol = 0 if !(/\\\s*$/);  # Last line
479                         }
480                         print MAKE;
481                 } elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) {
482                         # Found a makefile's macro declaration
483                         $Gvars{$1} = 1;                                 # Definition of variable seen
484                         $in_symbol = 1 if (/\\\s*$/);   # There is a final '\'
485                         print MAKE;
486                 }
487         }
488         print MAKE "void::\n";          # Cut incomplete escape sequence
489 }
490
491 # Parse line to extract all $(VAR) usage and trigger the symbol if VAR
492 # is among the wanted set, as if they had manually said ">VAR" like in
493 # the old days.
494 sub find_wanted {
495         my ($l) = @_;
496         while ($l =~ s/\$\(([\w_]+)\)//) {
497                 $symbol{$1}++ if $wanted{$1};
498         }
499 }
500
501 # Perform ~name expansion ala ksh...
502 # (banish csh from your vocabulary ;-)
503 sub tilda_expand {
504         local($path) = @_;
505         return $path unless $path =~ /^~/;
506         $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e;                    # ~name
507         $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e;   # ~
508         $path;
509 }
510