diff --git a/Makefile.in b/Makefile.in index 85ef99c93..2646d3017 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 \ diff --git a/configure.ac b/configure.ac index 891f2d8d6..f5f98e819 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/src/Makefile.in b/src/Makefile.in index ee32a0927..669ff4a96 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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* diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 036ddd118..052d795fd 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -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 diff --git a/src/V3Options.cpp b/src/V3Options.cpp index c483f66a0..e3de5c75c 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -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]; diff --git a/src/config_rev b/src/config_rev new file mode 100755 index 000000000..75f53b834 --- /dev/null +++ b/src/config_rev @@ -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) diff --git a/src/config_rev.pl b/src/config_rev.pl deleted file mode 100755 index b1de61379..000000000 --- a/src/config_rev.pl +++ /dev/null @@ -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,"; diff --git a/src/cppcheck_filtered b/src/cppcheck_filtered index 461c042da..96f2a56b0 100755 --- a/src/cppcheck_filtered +++ b/src/cppcheck_filtered @@ -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!^!; - next if $line =~ m!^!; - next if $line =~ m!^!; - next if $line =~ m!^', line): + continue + if re.search(r'^', line): + continue + if re.search(r'^', line): + continue + # --suppress=unmatchedSuppression doesn't work + if re.search(r'^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'{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 free Verilog EDA software -tool suite. The latest version is available from CPAN and from -L. - -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 +Args, cppcheck_args = parser.parse_known_args() -=head1 SEE ALSO - -C - -=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: diff --git a/src/flexfix b/src/flexfix index 616ddb5a1..7638c9c00 100755 --- a/src/flexfix +++ b/src/flexfix @@ -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 () { +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 \nusing namespace std;\n/; + line = re.sub(r'^class istream;', + '\#include \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='')