build(utils/makehelp.pl): Introduced awareness for Make variables.

This commit is contained in:
Stephan Barth 2024-11-07 17:03:25 +01:00
parent fba71e5e38
commit cf0bd0211a

View File

@ -4,22 +4,35 @@ use strict;
use warnings;
my %msg = ();
my @start = ();
my %reorder = (help=>-1);
# We do not want every Makefile syntax error to break help completely,
# so we just disable the kind of features where the syntax error occurs
# In that case we store also the error message here
my %brokenFeatures = ();
my @blocks = ();
my @plainCode = ();
READ: while(<>) {
my $lnum = $.;
if(m/^# HELP HEADER START/) {
my @start = ();
while(<>) {
next READ if m/^# HELP HEADER END/;
do {
push @blocks, { kind=>'start', text=>\@start, line=>$lnum };
next READ
} if m/^# HELP HEADER END/;
if(m/# (.*)/) {
push @start, $1
} else {
die "$0: Invalid HELP HEADER section in Makefile!\n";
}
}
push @blocks, { kind=>'start', text=>\@start, line=>$lnum };
next READ
}
if(m/# HELP((?:\([^\(\)]+\))?):\s*(.*)/) {
if(m/^# HELP((?:\((?:[^\(\)]|\([^\(\)]+\))+\))?):\s*(.*)/) {
my ($target, $message) = ($1, $2);
if($target=~m/\((.*)\)/) {
$target = $1;
@ -29,13 +42,125 @@ READ: while(<>) {
$line=~m/^([^:]+):/ or die "$0: HELP marker expects target but no target found!\n";
$target = $1
}
$msg{$target} .= $message
push @blocks, { kind=>'target', target=>$target, message=>$message, line=>$lnum };
next READ
}
if(m/^# HELPVAR\((.*)\)/) {
push @blocks, { kind=>'helpvar', content=>$1, line=>$lnum };
next READ;
}
push @plainCode, [$lnum, $_]
}
my %kindBlocks = ();
for(@blocks) {
push @{$kindBlocks{$_->{kind}}}, $_
}
my @matchies = ();
HELPVARS: {
for my $hv(@{$kindBlocks{helpvar}}) {
my $reVar = qr((?:\$\((?<name>[A-Z]+)(?:,(?<re>[^\(\)]+))?\)));
my $reVarNoGroups = qr((?:\$\((?:[A-Z]+)(?:,(?:[^\(\)]+))?\)));
my @parts = split /($reVarNoGroups)/, $hv->{content};
my %setvars = ();
my @reParts = ();
for my $p(@parts) {
if($p=~m#^$reVar$#) {
my $name = $+{name};
my $re = $+{re};
if(defined $re) {
if(exists $setvars{$name}) {
$brokenFeatures{helpvars} = "Makefile line $hv->{line}: Multiple definitions of variable $name found!";
last HELPVARS
}
$setvars{$name} = $re;
push @reParts, [1,qr((?<$name>$re))];
} else {
if(not exists $setvars{$name}) {
$brokenFeatures{helpvars} = "Makefile line $hv->{line}: Variable $name used without definition!";
last HELPVARS
}
push @reParts, [0,$name]; #qr((?:\k<$name>)); -- problem: cannot reference variable when not defined
}
} else {
push @reParts, [1,qr((?:\Q$p\E))];
}
}
my $reCol = qr((?:));
for my $r(@reParts) {
my ($isRe, $reg) = @$r;
if($isRe) {
$reCol = qr((?:$reCol$reg));
} else {
eval {
$reCol = qr((?:$reCol(?:\k<$reg>)));
};
if($@) {
$brokenFeatures{helpvars} = "Makefile line $hv->{line}: Variable $reg caused an internal error ($@)!";
last HELPVARS
}
}
}
push @matchies, $reCol
}
}
print "$_\n" for @start;
print "\n" if @start;
for my $tar(sort {($reorder{$a}||0) <=> ($reorder{$b}||0) || $a cmp $b } keys %msg) {
print "$tar\n $msg{$tar}\n\n"
my %helpvars = ();
for my $rowr(@plainCode) {
my ($lnum, $row) = @$rowr;
my @matches = ();
for my $re(@matchies) {
if($row=~m#^$re$#) {
my %h = %+;
push @matches, \%h
}
}
if(@matches>1) {
$brokenFeatures{helpvars} = "Makefile line $lnum: Multiple variable definitions match on row '$row'\n";
}
if(1==@matches) {
my %h = %{$matches[0]};
for my $k(keys %h) {
push @{$helpvars{$k}}, $h{$k}
}
}
}
my @start = ();
@start = @{$kindBlocks{start}} if exists $kindBlocks{start};
for my $tg(@{$kindBlocks{target}}) {
my $tgv = $tg->{target};
my @build = ();
$tgv=~s#\$\(([A-Z]+)(?:,[^\(\)]*)?\)#push @build, {name=>$1,elm=>$helpvars{$1}}; $1#ge;
unshift @build, $tg->{message};
$msg{$tgv} = \@build;
}
sub msgprinter {
my $el = shift;
if('HASH' eq ref $el) {
print " Where $el->{name} is one of\n";
print " $_\n" for @{$el->{elm}};
return
}
$el =~ s#(.{40,76})\s+#$1\n #g;
print " $el\n";
}
for(@start) {
print "$_\n" for @{$_->{text}}
}
print "\n" if @start;
for my $tar(sort {($reorder{$a}||0) <=> ($reorder{$b}||0) || $a cmp $b } keys %msg) {
print "$tar\n";
msgprinter($_) for @{$msg{$tar}};
print "\n";
}
for my $k(keys %brokenFeatures) {
warn "\n!!!!!\nFailed to complete construct the help message from the Makefile.\nFeature '$k' disabled, because: $brokenFeatures{$k}\n\n";
}