2 eval 'exec perl -S $0 "$@"'
3 if $runnning_under_some_shell;
5 # $Id: jmake.SH 20 2008-01-04 23:14:00Z rmanfredi $
7 # Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi
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.
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
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
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
29 # Revision 3.0.1.6 1995/09/25 09:08:01 ram
30 # patch59: will now force macro definitions to the left
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
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
39 # Revision 3.0.1.3 1994/10/29 15:47:01 ram
40 # patch36: added various escapes in strings for perl5 support
42 # Revision 3.0.1.2 1993/08/24 12:12:50 ram
43 # patch3: privlib dir was ~name expanded in the wrong place
45 # Revision 3.0.1.1 1993/08/19 06:42:13 ram
46 # patch1: leading config.sh searching was not aborting properly
48 # Revision 3.0 1993/08/18 12:04:17 ram
49 # Baseline for dist 3.0 netwide release.
52 $dir = '/pro/3gl/CPAN/lib/dist/files';
53 $cpp = '/usr/bin/cpp';
57 ($me = $0) =~ s|.*/(.*)|$1|;
58 $dir = &tilda_expand($dir); # ~name expansion
59 $file = $dir . '/Jmake.tmpl';
61 $cpp_opt = "-I. "; # For Jmakefile, which is local
62 while ($ARGV[0] =~ /^-/) {
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.
74 open(TMPL, $file) || die "$me: can't open $file: $!\n";
76 next unless /^\?([\w_]+):\1\s+=/;
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...
84 open(CPP, "$dir/fixcpp $cpp_opt $file |");
86 # Record defined symbols in Jmakefile. We won't catch symbols
87 # in conditional commands, but that's ok, I hope.
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
96 $Makesym{$current_symbol} .= $val;
97 } elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) {
98 # Found a makefile's macro declaration
100 $current_symbol = $1;
101 if ($val =~ s/\\\s*$//) { # Remove final '\'
102 $in_symbol = 1; # This is a continuation line
104 $Makesym{$current_symbol} = $val;
105 push(@Order, $current_symbol); # Keep track of order
107 # Protect RCS keyword Id or Header from normal substitution
108 s/\$(Id|Header|Log)/\$X-$1/;
109 # Restore possibly escaped C comments
112 # Remove all ^^^ (null space character) up to next non-space character
114 # Remove all ^^ (null space character)
116 # Restore escaped ^^ and ^^^ sequences
119 next if /^#\s+\d+/; # Skip cpp commments
122 s/@#\s?/\n/g; # Kept for backward compatibility
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
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
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++;
143 } elsif (s/^\s*\+//) { # '+' means "initialization section"
144 if (s/^\+(\w+)//) { # '++' means add to variable list
146 } else { # A single '+' means "add as is".
149 } elsif (s/^\|//) { # Command for us
150 if (/suffix\s+(\S+)/) { # Add suffix
151 push(@suffix, $1) unless $seen{$1};
153 } elsif (s/^rule://) { # Add building rule
154 s/^\s(\s*\S+)/\t$1/; # Make sure leading tab is there
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/;
165 warn("$me: -once not found for $1")
166 unless $macro[$i] =~/^-once/;
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
175 print "$me: Warning: unknown command $_\n";
178 next if /^-once/; # Control statement removed
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
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
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";
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++) {
204 next if /^-skip|-expand/; # They might have made a mistake
206 # Strip consecutive blank lines in generated file
209 next if ($last_was_blank);
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.
220 if (/^-shell/) { # Ending shell mode, back to Makefile
221 print MAKEFILE $substmode ? $GROK_START : $SPIT_START;
223 } elsif (/^\|shell/) {
224 die "$me: can't nest 'shell' sections.\n";
226 print MAKEFILE "$_\n";
229 } elsif (/^\|shell/) {
230 print MAKEFILE $substmode ? $GROK_END : $SPIT_END;
231 $shellmode = 1; # Next lines emitted verbatim as shell
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.
240 if (/^-subst/) { # Ending subst mode, back to regular
241 print MAKEFILE $GROK_END;
242 print MAKEFILE $SPIT_START;
245 } elsif (/^\|subst/) {
246 die "$me: can't nest 'subst' sections.\n";
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
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.
260 if (/^-case/) { # Ending current case section
261 if ($casemode == 0) {
262 warn "$me: ignoring spurious '-case'\n";
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;
275 my ($var, $value) = /^\|case\s+(\w+)\s+in\s+(.*)/;
276 die "$me: unparseable directive '$_'\n" if $var eq '';
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;
286 # Process regular line to be generated in Makefile.SH
288 s/<TAG>/[jmake $version PL$patchlevel]/;
290 # Lines starting with ?SYMBOL: (resp. %SYMBOL:) are to be processed
291 # only if SYMBOL is defined (resp. undefined).
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};
300 print "$me: Warning: missing ':' in $_\n";
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
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
315 if (s/^\|//) { # Command for us
316 if (/^skip/) { # Skip until -skip
317 for (; $i <= $#makefile; $i++) {
318 last if $makefile[$i] =~ /^-skip/;
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++) {
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
333 s/^\s/\t/; # Make sure leading tab is there
334 push(@Expand, $_); # Line to be expanded
336 &expand($pattern); # Expand all lines in buffer
338 die "$me: unknown command $_\n";
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.
345 # Dumps core sometimes with perl 4.0 PL10
346 # &protect_dollars(*_);
347 $_ = &protect_dollars($_);
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($_);
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.
362 print MAKEFILE ".SUFFIXES:";
364 # Dumps core sometimes with perl 4.0 PL10
365 # &protect_dollars(*_);
366 $_ = &protect_dollars($_);
367 print MAKEFILE " $_";
369 print MAKEFILE "\n\n";
372 # Dumps core sometimes with perl 4.0 PL10
373 # &protect_dollars(*_);
374 $_ = &protect_dollars($_);
375 print MAKEFILE "$_\n";
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... :-(
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 :-)
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};
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";
411 chop($_ = `make -f $make all | grep ^OUTPUT:`);
415 while (s/^\s*(\w+)!([^!]*)!//) {
417 # Record only length for _first_ expanded symbol
418 $Vars_len = split(/\s\s*/, $2) unless $Vars_len;
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).
428 local($pattern) = shift; # To-be-removed pattern for last chunk
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});
439 $sub =~ s/\/\///g; # // is a void value
440 while (s/!${sym}:([^\s]*)=([^\s]*)/,x##x,/) {
441 # Replacing item is altered by some pattern
445 eval "\$subq =~ s=${p}=${q}=";
450 # Protect substitution in an 'eval' in case of error
451 eval "s/${pattern}\$//" if $pattern && $i == ($Vars_len - 1);
457 # Prints its argument in MAKEFILE and records it also in Generated
459 local($_) = shift(@_); # Line to be printed
460 print MAKEFILE "$_\n";
461 push(@Generated, "$_\n");
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.
468 undef %Gvars; # Reset already generated variables
469 local ($in_symbol) = 0; # True when in variable (Makefile's macro)
470 foreach (@Generated) {
472 if (/^\s*(\w+)\s*=(.*)/) { # Missed the end of previous macro
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
478 $in_symbol = 0 if !(/\\\s*$/); # Last line
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 '\'
488 print MAKE "void::\n"; # Cut incomplete escape sequence
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
496 while ($l =~ s/\$\(([\w_]+)\)//) {
497 $symbol{$1}++ if $wanted{$1};
501 # Perform ~name expansion ala ksh...
502 # (banish csh from your vocabulary ;-)
505 return $path unless $path =~ /^~/;
506 $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
507 $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~