Internals: Convert config_rev, cppcheck_filtered, flexfix to python3

This commit is contained in:
Wilson Snyder 2020-12-23 15:41:14 -05:00
parent b7a533109d
commit 922eab5f93
9 changed files with 238 additions and 277 deletions

View File

@ -429,7 +429,7 @@ CPPCHECK_H = $(wildcard \
CPPCHECK_YL = $(wildcard \
$(srcdir)/src/*.y \
$(srcdir)/src/*.l )
CPPCHECK = src/cppcheck_filtered
CPPCHECK = src/cppcheck_filtered cppcheck
CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
--suppress=nullPointerRedundantCheck
@ -477,6 +477,9 @@ YAPF_FLAGS = -i
YAPF_FILES = \
examples/xml_py/vl_file_copy \
examples/xml_py/vl_hier_graph \
src/config_rev \
src/cppcheck_filtered \
src/flexfix \
nodist/code_coverage \
nodist/code_coverage.dat \
nodist/dot_importer \

View File

@ -139,6 +139,11 @@ if test "x$PERL" = "x" ; then
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
fi
AC_PATH_PROG(PYTHON3,python3)
if test "x$PYTHON3" = "x" ; then
AC_MSG_ERROR([Cannot find "python3" in your PATH, please install it])
fi
AC_PATH_PROG(LEX,flex)
if test "x$LEX" = "x" ; then
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])

View File

@ -18,7 +18,7 @@
#### Start of system configuration section. ####
srcdir = @srcdir@
PERL = @PERL@
PYTHON3 = @PYTHON3@
EXEEXT = @EXEEXT@
# VPATH only does sources; fix install_test's not creating ../bin
vpath %.h @srcdir@
@ -78,8 +78,8 @@ endif
prefiles::
prefiles:: config_rev.h
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP)
$(PYTHON3) ${srcdir}/config_rev ${srcdir} >$@
# Human convenience
format:
@ -90,7 +90,7 @@ clang-format:
maintainer-copy::
clean mostlyclean distclean maintainer-clean::
-rm -rf obj_* *.log *.dmp *.vpd core
-rm -f *.o *.d perlxsi.c *_gen_*
-rm -f *.o *.d *_gen_*
-rm -f *__gen* obj_*
-rm -f .objcache*

View File

@ -41,6 +41,7 @@ LINK = @CXX@
LEX = @LEX@
LFLAGS = -d
PERL = @PERL@
PYTHON3 = @PYTHON3@
YACC = @YACC@
OBJCACHE ?= @OBJCACHE@
@ -138,7 +139,7 @@ make_info:
@echo " Compile flags: " $(CXX) ${CFLAGS} ${CXXFLAGS} ${CPPFLAGS}
clean mostlyclean distclean maintainer-clean::
-rm -f *.o *.d perlxsi.c *_gen_*
-rm -f *.o *.d *_gen_*
-rm -f *__gen*
-rm -f obj_* .objcache*
@ -332,7 +333,7 @@ V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
${LEX} ${LFLAGS} -o$@ $<
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
$(PERL) $(FLEXFIX) V3Lexer <$< >$@
$(PYTHON3) $(FLEXFIX) V3Lexer <$< >$@
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
${LEX} --version

View File

@ -1435,16 +1435,16 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
shift;
parseOptsFile(fl, parseFileArg(optdir, argv[i]), false);
} else if (!strcmp(sw, "-gdb")) {
// Used only in perl shell
// Processed only in bin/verilator shell
} else if (!strcmp(sw, "-waiver-output") && (i + 1) < argc) {
shift;
m_waiverOutput = argv[i];
} else if (!strcmp(sw, "-rr")) {
// Used only in perl shell
// Processed only in bin/verilator shell
} else if (!strcmp(sw, "-gdbbt")) {
// Used only in perl shell
// Processed only in bin/verilator shell
} else if (!strcmp(sw, "-quiet-exit")) {
// Used only in perl shell
// Processed only in bin/verilator shell
} else if (!strcmp(sw, "-mod-prefix") && (i + 1) < argc) {
shift;
m_modPrefix = argv[i];

42
src/config_rev Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
######################################################################
#
# Copyright 2005-2020 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
#
######################################################################
# DESCRIPTION: Query git to get version number
import argparse
import os
import re
import sys
parser = argparse.ArgumentParser()
parser.add_argument('directory')
Args = parser.parse_args()
os.chdir(Args.directory)
rev = 'UNKNOWN_REV'
data = os.popen('git describe').read()
match = re.search(r'^(v[0-9].*)', data)
if match:
rev = match.group(1)
rev = re.sub('_', '.', rev)
data = os.popen('git status').read()
if (re.search('Changed but not updated', data, flags=re.IGNORECASE)
or re.search('Changes to be committed', data, flags=re.IGNORECASE)
or re.search('Changes not staged', data, flags=re.IGNORECASE)):
rev += " (mod)"
print("static const char* const DTVERSION_rev = \"" + rev + "\";")
# Warn after the print, so at least the header has good contents
if re.search('UNKNOWN', rev):
print("%Warning: No git revision found in config_rev.py", file=sys.stderr)

View File

@ -1,38 +0,0 @@
#!/usr/bin/env perl
######################################################################
#
# Copyright 2005-2020 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
#
######################################################################
# DESCRIPTION: Query's subversion to get version number
use warnings;
my $dir = $ARGV[0]; defined $dir or die "%Error: No directory argument,";
chdir $dir;
my $rev = 'UNKNOWN_REV';
my $data = `git describe`;
if ($data =~ /^(v[0-9].*)/i) {
$rev = $1;
}
elsif ($data =~ /verilator_?(.*)/i) {
$rev = "v".$1;
$rev =~ s/_/./g;
}
$data = `git status`;
if ($data =~ /Changed but not updated/i
|| $data =~ /Changes to be committed/i
|| $data =~ /Changes not staged/i) {
$rev .= " (mod)";
}
print "static const char* const DTVERSION_rev = \"$rev\";\n";
# Die after the print, so at least the header has good contents
$rev =~ /UNKNOWN/ and warn "%Warning: No git revision found,";

View File

@ -1,245 +1,183 @@
#!/usr/bin/env perl
# See copyright, etc in below POD section.
#!/usr/bin/env python3
######################################################################
use warnings;
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw($Debug $VERSION);
import argparse
import os
import re
import sys
$VERSION = '3.881';
our %SuppressMap = (
# New cpp check error Can suppress with old error
'nullPointerRedundantCheck' => 'nullPointer',
);
#======================================================================
# main
our $Opt_Debug;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev","pass_through");
our @Opt_Args = ("cppcheck", grep { $_ ne "--debug" } @ARGV);
if (! GetOptions(
# Local options
"debug!" => sub { $Debug = 9; },
"help" => \&usage,
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
)) {
die "%Error: Bad usage, try 'cppcheck_filtered --help'\n";
SuppressMap = {
# New cpp check error Can suppress with old error
'nullPointerRedundantCheck': 'nullPointer'
}
process();
######################################################################
#----------------------------------------------------------------------
sub usage {
print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT, -noperldoc=>1);
exit(1); # Unreachable
}
#######################################################################
sub process {
my $cmd = join(' ', @Opt_Args);
print "\t$cmd\n" if $Debug;
my $fh = IO::File->new("$cmd 2>&1 |");
$fh or die "%Error: '$cmd' failed: $!\n";
my %uniq;
my %errs;
my $last_error = "";
while (defined(my $line = $fh->getline())) {
print ">>>$line" if $Debug;
$line =~ s/^\s+//;
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
def process(cppcheck_args):
cmd = " ".join(cppcheck_args) + " 2>&1"
if Args.debug:
print("\t" + cmd)
fh = os.popen(cmd)
uniq = {}
errs = False
last_error = ""
for line in fh:
line = line.rstrip()
if Args.debug:
print(">>>" + line)
line = re.sub(r'^\s+', '', line)
# Sometimes tacked at end-of-line
line = re.sub(r'Checking usage of global functions\.+', '', line)
# General gunk
next if $uniq{$line}++;
next if $line =~ m!^<\?xml version!;
next if $line =~ m!^<cppcheck!;
next if $line =~ m!^<results!;
next if $line =~ m!^</results>!;
next if $line =~ m!^<errors!;
next if $line =~ m!^</error>!;
next if $line =~ m!^</errors>!;
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
next if $line =~ m!^Checking !;
next if $line =~ m!^make.*Entering directory !;
next if $line =~ m!^make.*Leaving directory !;
next if $line =~ m!^\s+$!g;
if line in uniq:
continue
uniq[line] = 1
if re.search(r'^<\?xml version', line):
continue
if re.search(r'^<cppcheck', line):
continue
if re.search(r'^<results', line):
continue
if re.search(r'^</results>', line):
continue
if re.search(r'^<errors', line):
continue
if re.search(r'^</error>', line):
continue
if re.search(r'^</errors>', line):
continue
# --suppress=unmatchedSuppression doesn't work
if re.search(r'^<error.*id="unmatchedSuppression"', line):
continue
# An earlier id line is more specific
if re.search(r'Cppcheck cannot find all the include files', line):
continue
if re.search(r'^Checking ', line):
continue
if re.search(r'^make.*Entering directory ', line):
continue
if re.search(r'^make.*Leaving directory ', line):
continue
if re.search(r'^\s+$', line):
continue
# Specific suppressions (see _suppress also)
next if $line =~ m!id="unusedPrivateFunction" .*::debug!; # Doesn't know UINFO will use it
# Doesn't know UINFO will use it
if re.search(r'id="unusedPrivateFunction" .*::debug', line):
continue
# Output
if ($line =~ /^cppcheck --/) {
print $line if $Debug;
} elsif ($line =~ m!^\d+/\d+ files checked!) {
print $line;
} else {
my $suppress;
# --xml-format=1
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
my $file = $1; my $linenum = $2; my $id = $3;
#$file = $1 if $line =~ /file0="([^"]+)"/; # Still incorrect
$suppress = 1 if _suppress($file,$linenum,$id);
}
# --xml-format=2
if ($line =~ /<error id.*/) {
$last_error = $line;
chomp $last_error;
$suppress = 1;
}
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
my $file = $1; my $linenum = $2; my $id;
#$file = $1 if $line =~ /file0="([^"]+)"/; # Still incorrect
if ($last_error =~ / id="([^"]+)"/) {
$id = $1;
} else {
$id = "?";
}
$suppress = 1 if _suppress($file,$linenum,$id);
$suppress = 1 if $file eq "*";
if (!$suppress) {
chomp $line;
print "$file:$linenum: ".$last_error."\n";
$suppress = 1;
}
}
if (!$suppress) {
my $eline = "%Error: cppcheck: $line";
print $eline;
$errs{$eline}++;
}
}
}
if (scalar(keys %errs)) {
#my $all = join('',sort(keys %errs));
#$Self->error("Cppcheck errors:\n$all");
#die "%Error: cppcheck_filtered found errors\n";
exit(1);
}
}
if re.search(r'^cppcheck --', line):
if Args.debug:
print(line)
continue
if re.search(r'^\d+/\d+ files checked', line):
print(line)
continue
suppress = False
# --xml-format=2
if re.search(r'<error id', line):
last_error = line
continue
match = re.search(r'<location.* file="([^"]+)"\s+line="(\d+)"', line)
if match:
file = match.group(1)
linenum = match.group(2)
match = re.search(r' id="([^"]+)"', last_error)
id = match.group(1) if match else '?'
if _suppress(file, linenum, id):
suppress = True
if file == "*":
suppress = True
if not suppress:
print(file + ":" + linenum + ": " + last_error)
suppress = True
if not suppress:
eline = "%Error: cppcheck: " + line
print(eline)
errs = True
if errs:
sys.exit(1)
######################################################################
sub _suppress {
my $filename = shift;
my $linenum = shift;
my $id = shift;
#print "-Suppression search $filename $linenum $id\n" if $Self->{verbose};
return undef if $filename eq "*";
def _suppress(filename, linenum, id):
if Args.debug:
print("-Suppression search %s %s %s" % (filename, linenum, id))
if filename == "*":
return False
# Cleanup for e.g. ../V3AstNodes.h
$filename = "src/$1" if $filename =~ m!^\.\./(.*)!;
filename = re.sub(r'^\.\./(.*)', r'src/\1', filename)
# Specific suppressions
return 1 if $id eq "missingInclude" && $filename =~ m!systemc.h!;
return 1 if $id eq "missingInclude" && $filename =~ m!svdpi.h!;
return 1 if $id eq "unusedFunction" && $filename =~ m!verilated_dpi.cpp!;
return 1 if $id eq "unusedFunction" && $filename =~ m!verilated_vpi.cpp!;
return 1 if $id eq "unreachableCode" && $filename =~ /V3ParseBison.c/;
return 1 if $id eq 'variableScope' && $filename =~ /fstapi.c/;
if id == 'missingInclude' and re.search(r'systemc.h', filename):
return True
if id == 'missingInclude' and re.search(r'svdpi.h', filename):
return True
if id == 'unusedFunction' and re.search(r'verilated_dpi.cpp', filename):
return True
if id == 'unusedFunction' and re.search(r'verilated_vpi.cpp', filename):
return True
if id == 'unreachableCode' and re.search(r'V3ParseBison.c', filename):
return True
if id == 'variableScope' and re.search(r'fstapi.c', filename):
return True
my $fh = IO::File->new("<$filename");
if (!$fh) {
warn "%Warning: $! $filename,";
return undef;
}
my $l = 0;
while (defined(my $line = $fh->getline())) {
++$l;
if ($l+1 == $linenum) {
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
my $supids = $1;
foreach my $supid (split /\s+/, $supids) {
if ($supid eq $id
|| $supid eq ($SuppressMap{$id}||'')) {
return 1;
}
}
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
}
}
if ($l == $linenum) {
if (0 && # We now use VL_DANGLING instead of this rule
$id eq "uselessAssignmentPtrArg"
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
return 1;
}
}
}
return undef;
}
if not os.path.exists(filename):
print("%Warning: " + filename + " does not exist, ignored",
file=sys.stderr)
return False
with open(filename) as fh:
l = 0
for line in fh:
l += 1
if (l + 1 == linenum):
match = re.search(r'cppcheck-suppress((\s+\S+)+)', line)
if match:
for supid in match.group(1).split():
if (supid == id or
(id in SuppressMap and supid == SuppressMap[id])):
return True
return False
1;
#######################################################################
__END__
#######################################################################
=pod
parser = argparse.ArgumentParser(
allow_abbrev=False,
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""cppcheck_filtered passes all arguments to cppcheck, then
filters out unnecessary warnings related to Verilator. Run as:
=head1 NAME
cppcheck_filtered - cppcheck wrapper with post-processing
=head1 SYNOPSIS
cppcheck_filtered ...normal cpp check flags...
=head1 DESCRIPTION
Cppcheck_Filtered is a wrapper for cppcheck that filters out unnecessary
warnings related to Verilator.
=head1 ARGUMENTS
Most arguments are passed through to cppcheck
=over 4
=item --help
Displays this message and program version and exits.
=item --version
Print the version number and exit.
=back
=head1 DISTRIBUTION
This is part of the L<https://www.veripool.org/> free Verilog EDA software
tool suite. The latest version is available from CPAN and from
L<https://www.veripool.org/>.
Copyright 2014-2020 by Wilson Snyder. This program is free software; you
cd $VERILATOR_ROOT
make -k cppcheck""",
epilog=
"""Copyright 2014-2020 by Wilson Snyder. This program is free software; you
can redistribute it and/or modify it under the terms of either the GNU
Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
Lesser General Public License Version 3 or the Perl Artistic License
Version 2.0.
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
=head1 AUTHORS
parser.add_argument('--debug', action='store_true', help='enable debug')
Wilson Snyder <wsnyder@wsnyder.org>
Args, cppcheck_args = parser.parse_known_args()
=head1 SEE ALSO
C<cppcheck>
=cut
process(cppcheck_args)
######################################################################
### Local Variables:
### compile-command: "./cppcheck_filtered --xml V3Width.cpp"
### compile-command: "cd .. ; src/cppcheck_filtered cppcheck --xml --enable=all src/V3Width.cpp"
### End:

View File

@ -1,4 +1,4 @@
#!/usr/bin/env perl
#!/usr/bin/env python3
######################################################################
#
# Copyright 2002-2020 by Wilson Snyder. This program is free software; you
@ -10,32 +10,42 @@
######################################################################
# DESCRIPTION: Edits flex output to get around various broken flex issues.
use warnings;
import argparse
import re
import sys
my $Opt_Prefix = $ARGV[0] or die "%Error: No prefix specified,";
foreach my $line (<STDIN>) {
for line in sys.stdin:
# Fix flex 2.6.1 warning
$line =~ s/for \( i = 0; i < _yybytes_len; \+\+i \)/for ( i = 0; (yy_size_t)(i) < (yy_size_t)(_yybytes_len); ++i )/g;
line = re.sub(
r'for \( i = 0; i < _yybytes_len; \+\+i \)',
r'for ( i = 0; (yy_size_t)(i) < (yy_size_t)(_yybytes_len); ++i )',
line)
# Fix flex 2.6.0 warning
$line =~ s/\(\(int\) \(\(yy_n_chars\) \+ number_to_move\) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size\)/((int) ((yy_n_chars) + number_to_move) > (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size)/g;
$line =~ s/ number_to_move == YY_MORE_ADJ / (int)number_to_move == (int)YY_MORE_ADJ /;
line = re.sub(
r'\(\(int\) \(\(yy_n_chars\) \+ number_to_move\) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size\)',
r'((int) ((yy_n_chars) + number_to_move) > (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size)',
line)
line = re.sub(r' number_to_move == YY_MORE_ADJ ',
r' (int)number_to_move == (int)YY_MORE_ADJ ', line)
# Fix flex 2.5.4 namespace omission
$line =~ s/^class istream;/\#include <iostream>\nusing namespace std;\n/;
line = re.sub(r'^class istream;',
'\#include <iostream>\nusing namespace std;\n', line)
# Fix flex 2.5.31 redefinition
$line =~ s!(\#define\s+yyFlexLexer\s+yyFlexLexer)!//flexfix: $1!g;
line = re.sub(r'(\#define\s+yyFlexLexer\s+yyFlexLexer)', r'//flexfix: \1',
line)
# Fix flex 2.5.1 yytext_ptr undef
$line =~ s!(\#undef\s+yytext_ptr)!//flexfix: $1!g;
line = re.sub(r'(\#undef\s+yytext_ptr)', r'//flexfix: \1', line)
# Fix flex 2.5.4 and GCC 4.1.0 warn_unused_result
$line =~ s!\(void\) *fwrite\((.*)\)!if (fwrite($1)) {}!g;
line = re.sub(r'\(void\) *fwrite\((.*)\)', r'if (fwrite(\1)) {}', line)
# Fix flex 2.5.33 and GCC 4.1.2 "warning: comparison between signed and unsigned integer expressions" in YY_INPUT
$line =~ s!for \( n = 0; n < max_size && !for ( n = 0; ((size_t)n < (size_t)max_size) && !g;
line = re.sub(r'for \( n = 0; n < max_size && ',
r'for ( n = 0; ((size_t)n < (size_t)max_size) && ', line)
# Fix flex 2.5.4 and GCC 4.0.2 under FLEX_DEBUG
$line =~ s!--accepting rule at line %d !--accepting rule at line %ld !g;
line = re.sub(r'--accepting rule at line %d ',
r'--accepting rule at line %ld ', line)
# Fix compiler warning filenames
$line =~ s!(#line \d+ ".*)_pretmp!$1!;
line = re.sub(r'(#line \d+ ".*)_pretmp', r'\1', line)
# Fix 'register' storage class specifier is deprecated and incompatible with C++17
$line =~ s!register !!g;
line = re.sub(r'register ', '', line)
print "$line";
}
print(line, end='')