case $CONFIG in '') if test -f config.sh; then TOP=.; elif test -f ../config.sh; then TOP=..; elif test -f ../../config.sh; then TOP=../..; elif test -f ../../../config.sh; then TOP=../../..; elif test -f ../../../../config.sh; then TOP=../../../..; else echo "Can't find config.sh."; exit 1 fi . $TOP/config.sh ;; esac case "$0" in */*) cd `expr X$0 : 'X\(.*\)/'` ;; esac echo "Extracting jmake/jmake (with variable substitutions)" $spitshell >jmake <>jmake <<'!NO!SUBS!' ($me = $0) =~ s|.*/(.*)|$1|; $dir = &tilda_expand($dir); # ~name expansion $file = $dir . '/Jmake.tmpl'; $cpp_opt = "-I. "; # For Jmakefile, which is local while ($ARGV[0] =~ /^-/) { $_ = shift; last if /--/; $cpp_opt .= "$_ "; } $cpp_opt .= "-I$dir"; # Pass 0 is looking at the template for "?CP:CP =" lines that are to be # emitted if the CP variable is needed. Later on, when we see $(CP) being # used, we'll be able to set the $symbol{CP} entry to 1 to have the CP # variable initialized by the template. open(TMPL, $file) || die "$me: can't open $file: $!\n"; while () { next unless /^\?([\w_]+):\1\s+=/; $wanted{$1}++; } close TMPL; # Thank you HP-UX for having a cpp that blindly strips trailing backslashes # in the text. Run through cpp by using the fixcpp script... open(CPP, "$dir/fixcpp $cpp_opt $file |"); while () { # Record defined symbols in Jmakefile. We won't catch symbols # in conditional commands, but that's ok, I hope. if ($in_symbol) { $val = $_; $in_symbol = 0 if !($val =~ s/\\\s*$//); # Last line if ($val = /^\|expand/) { # Found an expand command $in_symbol = 0; # Stop gathering value $val .= "void::x"; # Stop any incomplete escape sequence } chop($val); $Makesym{$current_symbol} .= $val; } elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) { # Found a makefile's macro declaration $val = $2; $current_symbol = $1; if ($val =~ s/\\\s*$//) { # Remove final '\' $in_symbol = 1; # This is a continuation line } $Makesym{$current_symbol} = $val; push(@Order, $current_symbol); # Keep track of order } # Protect RCS keyword Id or Header from normal substitution s/\$(Id|Header|Log)/\$X-$1/; # Restore possibly escaped C comments s|/#\*|/*|g; s|\*#/|*/|g; # Remove all ^^^ (null space character) up to next non-space character s|\^\^\^\s*||g; # Remove all ^^ (null space character) s|\^\^||g; # Restore escaped ^^ and ^^^ sequences s|\^\\\^\\\^|^^^|g; s|\^\\\^|^^|g; next if /^#\s+\d+/; # Skip cpp commments s/^;#/#/; s/@#\s?/\n/g; # Kept for backward compatibility s/@!\s?/\n/g; s/@@\s?/\n\t/g; # A '\r' is added to all lines, in order to let 'split' keep them # As lines ending with '\' won't fit in the next regular # expression (why ?), we have to treat that special case separately s/\n$/\r\n/gm; s/\\\s*$/\\\r/gm; # Remove spaces after final '\' and add '\r' @macro = split(/\n/); for ($i = 0; $i <= $#macro; $i++) { chop($_ = $macro[$i]); # Remove final '\r' s/\s+$//g; # Remove possible useless spaces if (/^TOP\s*=\s*(\S+)/) { # Get the top from generated file $top = $1; } find_wanted($_); # Look for known $(VAR) usage if (s/^\s*>//) { # '>' means "symbol wanted" warn "$me: the '>$_' construct is deprecated for known symbols\n" if $wanted{$_} && !$warned_wanted_symbol_deprecated++; $symbol{$_} = 1; } elsif (s/^\s*\+//) { # '+' means "initialization section" if (s/^\+(\w+)//) { # '++' means add to variable list $added{$1} .= $_; } else { # A single '+' means "add as is". push(@init, $_); } } elsif (s/^\|//) { # Command for us if (/suffix\s+(\S+)/) { # Add suffix push(@suffix, $1) unless $seen{$1}; $seen{$1} = 1; } elsif (s/^rule://) { # Add building rule s/^\s(\s*\S+)/\t$1/; # Make sure leading tab is there push(@rule, $_); } elsif (/^skip/) { # Unconditional skip... funny! push(@makefile, "|$_"); # Skip handled in pass 2 } elsif (/^expand/) { push(@makefile, "|$_"); # Expand handled in pass 2 } elsif (/^once\s+(.*)/) { # Once handled in pass 1 if ($Once{$1}++) { # Symbol already seen -- skip for (; $i <= $#macro; $i++) { last if $macro[$i] =~/^-once/; } warn("$me: -once not found for $1") unless $macro[$i] =~/^-once/; } } elsif (/^shell/) { # Escaping to shell push(@makefile, "|$_"); # will be handled in pass 2 } elsif (/^case/) { # Conditional generation push(@makefile, "|$_"); # will be handled in pass 2 } elsif (/^subst/) { # Section with var substitution push(@makefile, "|$_"); # will be handled in pass 2 } else { print "$me: Warning: unknown command $_\n"; } } else { next if /^-once/; # Control statement removed push(@makefile, $_); } } } close CPP; @key = keys(%added); $last_was_blank = 1; # To avoid blank line at the top of the file $symbol{'INIT'} = 1 if ($#init >= 0 || $#key >=0); # Initializations $symbol{'SUFFIX'} = 1 if ($#suffix >= 0 || $#rule >=0); # Rules or suffixes $symbol{'TOP'} = 1 if $top eq '.'; # If imake invoked for the top $shellmode = 0; # Set to true within "shell" section $casemode = 0; # Counts nesting levels within "case" section $substmode = 0; # True when within section with variable substitution $SPIT_START = "\$spitshell >>Makefile <<'!NO!SUBS!'\n"; $SPIT_END = "!NO!SUBS!\n"; $GROK_START = "\$spitshell >>Makefile <Makefile.SH"); # We have to use for instead of foreach to handle 'skip' easily line: for ($i = 0; $i <= $#makefile; $i++) { $_ = $makefile[$i]; next if /^-skip|-expand/; # They might have made a mistake # Strip consecutive blank lines in generated file if (/^\s*$/) { next if ($last_was_blank); $last_was_blank = 1; } else { $last_was_blank = 0; } # In shell mode, we're transparent, untill we reach a "-shell" # We don't call print_makefile() as we don't want to record # those non-makefile lines in the @Generated array. if ($shellmode) { if (/^-shell/) { # Ending shell mode, back to Makefile print MAKEFILE $substmode ? $GROK_START : $SPIT_START; $shellmode = 0; } elsif (/^\|shell/) { die "$me: can't nest 'shell' sections.\n"; } else { print MAKEFILE "$_\n"; } next; } elsif (/^\|shell/) { print MAKEFILE $substmode ? $GROK_END : $SPIT_END; $shellmode = 1; # Next lines emitted verbatim as shell next; } # In subst mode, the section until "-subst" is emitted regularily, # excepted that it will be in a grok section, so its $var will be # substituted by the shell. if ($substmode) { if (/^-subst/) { # Ending subst mode, back to regular print MAKEFILE $GROK_END; print MAKEFILE $SPIT_START; $substmode = 0; next; } elsif (/^\|subst/) { die "$me: can't nest 'subst' sections.\n"; } # Continue with line } elsif (/^\|subst/) { print MAKEFILE $SPIT_END; # End spit section in Makefile.SH print MAKEFILE $GROK_START; $substmode = 1; # Next lines subject to $ interpretation next; } # In a "case" section, the Makefile will be conditionally generated # based on the value of the supplied variable, as evaluated by the shell. # We can nest "case" sections without problems. if (/^-case/) { # Ending current case section if ($casemode == 0) { warn "$me: ignoring spurious '-case'\n"; next; } print MAKEFILE $substmode ? $GROK_END : $SPIT_END; my $indent = "\t" x ($casemode - 1); print MAKEFILE "${indent}\t;;\n"; print MAKEFILE "${indent}esac\n"; print MAKEFILE "${indent}", $substmode ? $GROK_START : $SPIT_START; $casemode--; next; } if (/^\|case/) { my ($var, $value) = /^\|case\s+(\w+)\s+in\s+(.*)/; die "$me: unparseable directive '$_'\n" if $var eq ''; $casemode++; print MAKEFILE $substmode ? $GROK_END : $SPIT_END; my $indent = "\t" x ($casemode - 1); print MAKEFILE "${indent}case \"\$$var\" in\n"; print MAKEFILE "${indent}$value)\n"; print MAKEFILE "${indent}\t", $substmode ? $GROK_START : $SPIT_START; next; } # Process regular line to be generated in Makefile.SH s//[jmake $version-$revision]/; # Lines starting with ?SYMBOL: (resp. %SYMBOL:) are to be processed # only if SYMBOL is defined (resp. undefined). # Apply in sequence while (/^\s*\?|\s*%/) { if (s/^\s*\?(\w+)://) { # Wanted symbol ? next line unless $symbol{$1}; } elsif (s/^\s*%(\w+)://) { # Unwanted symbol ? next line if $symbol{$1}; } else { print "$me: Warning: missing ':' in $_\n"; last; } } # We wish to make sure there is a leading tab if the line starts with # a space to prevent problems later on. However, variable definitions # might want to be aligned on the '=' (imake style). Not all make # may be able to cope with those though, so they are left justified # again. s/^\s/\t/ unless /^\s+\w+\s+=/; # Make sure leading tab is there s/^\s+(\w+\s+=)/$1/; # Left justify variable definition s/^;#/#/; # Comments in Jmakefile if (s/^\|//) { # Command for us if (/^skip/) { # Skip until -skip for (; $i <= $#makefile; $i++) { last if $makefile[$i] =~ /^-skip/; } } elsif (s/^expand//) { &init_expand($_); # Initializes data structures $i++; # Skip expand line undef @Expand; # Storage for expanded lines $pattern = ''; # Assume no pattern for (; $i <= $#makefile; $i++) { $_ = $makefile[$i]; if (s/^-expand//) { # Reached end of expansion if (s/^\s*(.*)/$1/) { # Expand followed by a pattern $pattern = $_; # Get pattern to be removed } last; } s/^\s/\t/; # Make sure leading tab is there push(@Expand, $_); # Line to be expanded } &expand($pattern); # Expand all lines in buffer } else { die "$me: unknown command $_\n"; } } elsif (/^INIT/) { # Initialization section # All the initializations are put in the variable substitution # section of the Makefile.SH. Therefore, we have to protect all # the '$' signs that are not followed by an alphanumeric character. foreach (@init) { # Dumps core sometimes with perl 4.0 PL10 # &protect_dollars(*_); $_ = &protect_dollars($_); &print_makefile($_); } foreach (@key) { # @key set earlier to keys(%added) $_ .= " = " . $added{$_}; # Dumps core sometimes with perl 4.0 PL10 # &protect_dollars(*_); $_ = &protect_dollars($_); &print_makefile($_); } } elsif (/^SUFFIX/) { # Suffixes/Rules section # Rules and suffixes are put in the variable substitution # section of the Makefile.SH. Therefore, we have to protect all # the '$' signs that are not followed by an alphanumeric character. if ($#suffix >= 0) { print MAKEFILE ".SUFFIXES:"; foreach (@suffix) { # Dumps core sometimes with perl 4.0 PL10 # &protect_dollars(*_); $_ = &protect_dollars($_); print MAKEFILE " $_"; } print MAKEFILE "\n\n"; } foreach (@rule) { # Dumps core sometimes with perl 4.0 PL10 # &protect_dollars(*_); $_ = &protect_dollars($_); print MAKEFILE "$_\n"; } } else { &print_makefile($_); } } close MAKEFILE; sub protect_dollars { # Dumps core sometimes with perl 4.0 PL10 # local(*_) = shift(@_); s/\\\$/\\=/g; # Protect already escaped '$' s/(\$\W)/\\$1/g; # Escape unprotected '$' s/\\=/\\\$/g; # Restore escaped '$' $_; # Because perl dumps core... :-( } # Initializes data structures for expansion. If we detect Makefile # macro in the 'expand' line (the argument), then we write a small # makefile that will do the substitution for us -- I'm lazy today :-) sub init_expand { local($_) = shift(@_); undef %Vars; # Reset array of variables $Vars_len = 0; # Number of "symbols" in first expanded if (/\$\(\w+\)/) { # If at least one macro local($make) = "/tmp/mkjm$$"; open(MAKE, ">$make") || die "$me: can't create $make: $!\n"; &gen_variables(); # Generates already computed variables foreach $var (@Order) { # Print each in order we found them print MAKE "$var = $Makesym{$var}\n" if !$Gvars{$var}; } # We prepend OUTPUT: in front of the line that interests us, because # some makes can print extra information, especially GNU make with # its entering/leaving blurb when invoked from another makefile. print MAKE "all:\n\t\@echo 'OUTPUT: $_'\n"; close MAKE; chop($_ = `make -f $make all | grep ^OUTPUT:`); unlink($make); } s/^OUTPUT: //; while (s/^\s*(\w+)!([^!]*)!//) { $Vars{$1} = $2; # Record only length for _first_ expanded symbol $Vars_len = split(/\s\s*/, $2) unless $Vars_len; } } # Expand lines in the @Expand array. The argument is a pattern which is to # be removed from the last chunk of expanded lines. # For each symbol s, !s is replaced by the next item, and !s:p=q does the # same after having replaced the pattern 'p' by pattern 'q' in the item. # Spaces are NOT allowed in 'p' or 'q'. Substitution is done once (no /g). sub expand { local($pattern) = shift; # To-be-removed pattern for last chunk local($_); local($sub); local($i); local(@expands); for ($i = 0; $i < $Vars_len; $i++) { foreach $line (@Expand) { $_ = $line; # Don't modify elements in array foreach $sym (keys %Vars) { @expands = split(/\s\s*/, $Vars{$sym}); $sub = $expands[$i]; $sub =~ s/\/\///g; # // is a void value while (s/!${sym}:([^\s]*)=([^\s]*)/,x##x,/) { # Replacing item is altered by some pattern local($p) = $1; local($q) = $2; local($subq) = $sub; eval "\$subq =~ s=${p}=${q}="; s/,x##x,/${subq}/; } s/!${sym}/${sub}/g; } # Protect substitution in an 'eval' in case of error eval "s/${pattern}\$//" if $pattern && $i == ($Vars_len - 1); &print_makefile($_); } } } # Prints its argument in MAKEFILE and records it also in Generated sub print_makefile { local($_) = shift(@_); # Line to be printed print MAKEFILE "$_\n"; push(@Generated, "$_\n"); } # Generates in MAKE file all the generated variable we have so far for # final Makefile. This is mainly intended to allow expansion of variables # which are already defined with an expand. sub gen_variables { undef %Gvars; # Reset already generated variables local ($in_symbol) = 0; # True when in variable (Makefile's macro) foreach (@Generated) { if ($in_symbol) { if (/^\s*(\w+)\s*=(.*)/) { # Missed the end of previous macro $in_symbol = 0; $Gvars{$1} = 1; # Definition of variable seen $in_symbol = 1 if (/\\\s*$/); # There is a final '\' print MAKE "void::\n"; # Cut incomplete esc sequence } else { $in_symbol = 0 if !(/\\\s*$/); # Last line } print MAKE; } elsif (/^\s*(\w+)\s*=(.*)/ && !$in_symbol) { # Found a makefile's macro declaration $Gvars{$1} = 1; # Definition of variable seen $in_symbol = 1 if (/\\\s*$/); # There is a final '\' print MAKE; } } print MAKE "void::\n"; # Cut incomplete escape sequence } # Parse line to extract all $(VAR) usage and trigger the symbol if VAR # is among the wanted set, as if they had manually said ">VAR" like in # the old days. sub find_wanted { my ($l) = @_; while ($l =~ s/\$\(([\w_]+)\)//) { $symbol{$1}++ if $wanted{$1}; } } !NO!SUBS! $grep -v '^;#' ../pl/tilde.pl >>jmake chmod 755 jmake $eunicefix jmake