Commit 503e3deedf for perl

commit 503e3deedf1aea0392f250401ae11a325e312040
Author: Yves Orton <demerphq@gmail.com>
Date:   Sun Sep 13 17:28:43 2026 +0200

    regen: unify full regeneration targets

    Enhance regen_all and regen-all as the complete regeneration workflow across the
    supported makefile variants. The workflow builds Perl, runs the standard
    generators, regenerates keywords and Unicode data, updates distribution
    metadata, and finishes with a final build.  On *nix it includes regen_perly,
    which is excluded on other platforms because it requires Bison.

    Add individual targets and diagnostics for the keyword, inversion-list, and
    character-class generators. Also adds regen_keywords which uses the installed
    Perl because Devel::Tokenizer::C is not part of the build tree, additionally
    the generator now reports how to install the missing dependency.

    Adds and documents REGEN_VERBOSE alongside -v for regeneration scripts and
    update the porting regeneration test with target-specific recovery commands.

diff --git a/Cross/Makefile-cross-SH b/Cross/Makefile-cross-SH
index e9749de82d..f2e3fd6ff4 100644
--- a/Cross/Makefile-cross-SH
+++ b/Cross/Makefile-cross-SH
@@ -842,12 +842,48 @@ CHMOD_W = chmod +w
 # with your existing copy of perl
 # (make regen_headers is kept for backwards compatibility)

-.PHONY: regen_headers regen_all
+.PHONY: regen_headers regen-headers regen_perly regen-perly \
+	regen_keywords regen-keywords regen_invlist regen-invlist \
+	regen_charclass regen-charclass \
+	regen_meta regen-meta regen_all regen-all

-regen regen_headers:	FORCE
+regen:	FORCE
 	-perl regen.pl

-regen_all: regen
+regen_meta: META.yml META.json
+
+# Requires Devel::Tokenizer::C 0.05 or newer in the installed Perl.
+regen_keywords regen-keywords:
+	perl regen/keywords.pl
+
+regen_invlist regen-invlist:
+	$(LDLIBPTH) $(RUN) ./perl$(EXE_EXT) -Ilib regen/mk_invlists.pl
+
+regen_charclass regen-charclass:
+	$(LDLIBPTH) $(RUN) ./perl$(EXE_EXT) -Ilib regen/regcharclass.pl
+
+regen_headers regen-headers:	FORCE
+	-perl regen.pl -v
+
+regen_perly regen-perly:
+	perl regen_perly.pl
+
+regen_all regen-all:
+	@echo "If this fails, run the regeneration steps one at a time:"
+	@echo "  make regen"
+	@echo "  make regen_perly"
+	@echo "  make regen_keywords"
+	@echo "  make regen_invlist"
+	@echo "  make regen_charclass"
+	@echo "  make regen_meta"
+	$(MAKE)
+	$(MAKE) regen
+	$(MAKE) regen_perly
+	$(MAKE) regen_keywords
+	$(MAKE) regen_invlist
+	$(MAKE) regen_charclass
+	$(MAKE) regen_meta
+	$(MAKE)

 .PHONY:	manisort manicheck

diff --git a/Makefile.SH b/Makefile.SH
index 5534a9cc1e..d8c8082868 100755
--- a/Makefile.SH
+++ b/Makefile.SH
@@ -1277,7 +1277,10 @@ CHMOD_W = chmod +w
 # with your existing copy of perl
 # (make regen_headers is kept for backwards compatibility)

-.PHONY: regen_headers regen_all
+.PHONY: regen_headers regen-headers regen_perly regen-perly \
+	regen_keywords regen-keywords regen_invlist regen-invlist \
+	regen_charclass regen-charclass \
+	regen_meta regen-meta regen_all regen-all

 regen:	FORCE
 	-perl regen.pl
@@ -1287,6 +1290,16 @@ regen_headers regen-headers:	FORCE

 regen_meta regen-meta:  META.yml META.json

+# Requires Devel::Tokenizer::C 0.05 or newer in the installed Perl.
+regen_keywords regen-keywords:
+	perl regen/keywords.pl
+
+regen_invlist regen-invlist:
+	$(RUN_PERL) regen/mk_invlists.pl
+
+regen_charclass regen-charclass:
+	$(RUN_PERL) regen/regcharclass.pl
+
 META.yml:   FORCE
 	PATH="`pwd`:${PATH}" PERL5LIB="`pwd`/lib" $(RUN_PERL) Porting/makemeta -y

@@ -1294,7 +1307,22 @@ META.json:   FORCE
 	PATH="`pwd`:${PATH}" PERL5LIB="`pwd`/lib" $(RUN_PERL) Porting/makemeta -j


-regen_all regen-all: regen regen_meta
+regen_all regen-all:
+	@echo "If this fails, run the regeneration steps one at a time:"
+	@echo "  make regen"
+	@echo "  make regen_perly"
+	@echo "  make regen_keywords"
+	@echo "  make regen_invlist"
+	@echo "  make regen_charclass"
+	@echo "  make regen_meta"
+	$(MAKE)
+	$(MAKE) regen
+	$(MAKE) regen_perly
+	$(MAKE) regen_keywords
+	$(MAKE) regen_invlist
+	$(MAKE) regen_charclass
+	$(MAKE) regen_meta
+	$(MAKE)

 .PHONY:	manisort manicheck

diff --git a/Porting/makemeta b/Porting/makemeta
index 1cd68e3287..72ede369ad 100644
--- a/Porting/makemeta
+++ b/Porting/makemeta
@@ -23,6 +23,7 @@ getopts('nbyj', \%switches);
 =head1 SYNOPSIS

   ./perl -Ilib Porting/makemeta
+  make regen_meta

 =head1 OPTIONS

diff --git a/Porting/pumpkin.pod b/Porting/pumpkin.pod
index 9e49832f77..69ea917832 100644
--- a/Porting/pumpkin.pod
+++ b/Porting/pumpkin.pod
@@ -424,15 +424,28 @@ Note that in the old days, you had to do C<make run_byacc> instead.

 =head2 make regen_all

-This target takes care of the regen_headers target.
-(It used to also call the regen_pods target, but that has been eliminated.)
+This target builds Perl, runs the standard regeneration targets, regenerates
+the keyword and Unicode data files, and then regenerates C<META.yml> and
+C<META.json>.
+The hyphenated alias C<make regen-all> is also available.
+On Unix-like systems this also runs C<regen_perly>.  That step is omitted by
+the Windows and VMS makefiles because it depends on tools not known to be
+available there.
+The Unicode steps can be run separately with C<make regen_invlist> and
+C<make regen_charclass>.  The keyword files can be regenerated with
+C<make regen_keywords>, which requires C<Devel::Tokenizer::C> 0.05 or newer
+in the installed Perl.  Since C<regen_all> runs this target, it has the same
+requirement.
+

 =head2 make regen_headers

-The F<embed.h>, F<keywords.h>, and F<opcode.h> files are all automatically
-generated by perl scripts.  Since the user isn't guaranteed to have a
-working perl, we can't require the user to generate them.  Hence you have
-to, if you're making a distribution.
+This is the verbose form of C<make regen>.  The name is retained for
+backwards compatibility.  It does not limit regeneration to header files.
+
+The generated files are supplied in the Perl distribution.  Users are not
+guaranteed to have a working Perl available to regenerate them, so the
+pumpkin must run this target when preparing a distribution.

 I used to include rules like the following in the makefile:

diff --git a/charclass_invlists.inc b/charclass_invlists.inc
index 3bcc9b5b4b..d2a96c9ef5 100644
--- a/charclass_invlists.inc
+++ b/charclass_invlists.inc
@@ -502816,5 +502816,5 @@ static const U8 WB_dfa_table[] = {
  * a0079d7556b20c2de1fdc3d492797a91b8ec8a06006f94460006185cb6380962 lib/unicore/version
  * 0a6b5ab33bb1026531f816efe81aea1a8ffcd34a27cbea37dd6a70a63d73c844 regen/charset_translations.pl
  * 6bbb462516a4ea79e28d58cf387f0b4b63ba83c7d381cd61bdda0b188e148082 regen/mk_PL_charclass.pl
- * e0db8fe02138f978cc88968bd89e4f8e5d9fffe540499ba788dead2a5ecf5e37 regen/mk_invlists.pl
+ * 40e5b8500d364b2adc31055248fc92e05e86fedc487abe5b303be24f38d30b18 regen/mk_invlists.pl
  * ex: set ro ft=c: */
diff --git a/keywords.c b/keywords.c
index 792d67dbaa..f6788d9927 100644
--- a/keywords.c
+++ b/keywords.c
@@ -3612,5 +3612,5 @@ unknown:
 }

 /* Generated from:
- * 6314472316769769d8176b08a4b0fe3c461bc38d52170a303f7abd00c5a56677 regen/keywords.pl
+ * 23f7d491b2465a6afedc597fbe7d069b433c61cb2e3b5355759ce585b05f2595 regen/keywords.pl
  * ex: set ro ft=c: */
diff --git a/keywords.h b/keywords.h
index 32112b8416..3709281ae3 100644
--- a/keywords.h
+++ b/keywords.h
@@ -284,5 +284,5 @@
 #define KEY_y			268

 /* Generated from:
- * 6314472316769769d8176b08a4b0fe3c461bc38d52170a303f7abd00c5a56677 regen/keywords.pl
+ * 23f7d491b2465a6afedc597fbe7d069b433c61cb2e3b5355759ce585b05f2595 regen/keywords.pl
  * ex: set ro ft=c: */
diff --git a/lib/unicore/uni_keywords.pl b/lib/unicore/uni_keywords.pl
index d295b0a209..b5295bc827 100644
--- a/lib/unicore/uni_keywords.pl
+++ b/lib/unicore/uni_keywords.pl
@@ -1455,5 +1455,5 @@
 # a0079d7556b20c2de1fdc3d492797a91b8ec8a06006f94460006185cb6380962 lib/unicore/version
 # 0a6b5ab33bb1026531f816efe81aea1a8ffcd34a27cbea37dd6a70a63d73c844 regen/charset_translations.pl
 # 6bbb462516a4ea79e28d58cf387f0b4b63ba83c7d381cd61bdda0b188e148082 regen/mk_PL_charclass.pl
-# e0db8fe02138f978cc88968bd89e4f8e5d9fffe540499ba788dead2a5ecf5e37 regen/mk_invlists.pl
+# 40e5b8500d364b2adc31055248fc92e05e86fedc487abe5b303be24f38d30b18 regen/mk_invlists.pl
 # ex: set ro ft=perl:
diff --git a/perly.act b/perly.act
index 7be76ffbd9..4ffcf041e8 100644
--- a/perly.act
+++ b/perly.act
@@ -2325,5 +2325,5 @@ case 2: /* @1: %empty  */

 /* Generated from:
  * 0540b64053bede9454d33873d5bc9a003be0e21cd244ab0ae3f0a386e00ffb9a perly.y
- * 1a4cfc5b32006b09aba17cc80cd31ade3503ab1e829681adfe337d9c26e19fe0 regen_perly.pl
+ * ba173fe7f0e9b6b5465fb5d0705af3290ac7d8b511f0eead585307eb6c68918d regen_perly.pl
  * ex: set ro ft=c: */
diff --git a/perly.h b/perly.h
index 3a481a7f06..95fb2440c0 100644
--- a/perly.h
+++ b/perly.h
@@ -249,5 +249,5 @@ int yyparse (void);

 /* Generated from:
  * 0540b64053bede9454d33873d5bc9a003be0e21cd244ab0ae3f0a386e00ffb9a perly.y
- * 1a4cfc5b32006b09aba17cc80cd31ade3503ab1e829681adfe337d9c26e19fe0 regen_perly.pl
+ * ba173fe7f0e9b6b5465fb5d0705af3290ac7d8b511f0eead585307eb6c68918d regen_perly.pl
  * ex: set ro ft=c: */
diff --git a/perly.tab b/perly.tab
index a8852188de..b7364ccd74 100644
--- a/perly.tab
+++ b/perly.tab
@@ -1668,5 +1668,5 @@ static const toketypes yy_type_tab[] =

 /* Generated from:
  * 0540b64053bede9454d33873d5bc9a003be0e21cd244ab0ae3f0a386e00ffb9a perly.y
- * 1a4cfc5b32006b09aba17cc80cd31ade3503ab1e829681adfe337d9c26e19fe0 regen_perly.pl
+ * ba173fe7f0e9b6b5465fb5d0705af3290ac7d8b511f0eead585307eb6c68918d regen_perly.pl
  * ex: set ro ft=c: */
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 1dc7545a5f..d5b00ebe5e 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -447,6 +447,16 @@ well.

 =item *

+The regeneration targets have been expanded.  C<regen_all> (and
+C<regen-all>) now builds Perl, runs the standard, parser, keyword, Unicode,
+and metadata regeneration steps, and performs a final build.  Separate
+targets are available for keyword, inversion-list, and character-class
+generation, with platform-specific makefile support and clearer diagnostics
+from F<t/porting/regen.t>.  The regeneration scripts also accept
+C<REGEN_VERBOSE=1> as an alternative to C<-v>.
+
+=item *
+
 During regex compilation, C<S_reg> will attempt to flatten nested BRANCH
 structures, in an attempt to give the TRIE optimizer more alternations
 to consider. The intent is that patterns that were previously compiled
diff --git a/regcharclass.h b/regcharclass.h
index 2495a4e77e..f9861b40bf 100644
--- a/regcharclass.h
+++ b/regcharclass.h
@@ -4003,6 +4003,6 @@
  * 50f73270fdef0981edb4e24be003f71001cf76876591fc8703276d65ef488c9b lib/unicore/mktables
  * a0079d7556b20c2de1fdc3d492797a91b8ec8a06006f94460006185cb6380962 lib/unicore/version
  * 0a6b5ab33bb1026531f816efe81aea1a8ffcd34a27cbea37dd6a70a63d73c844 regen/charset_translations.pl
- * 852a8a7814f08a155d79fead2656fe2b4450ab17a2bce8a1127016119c9c3bc3 regen/regcharclass.pl
+ * cad98ca9e7be21f5f2a127f4f6304302e3ea1de98295124986eabd91ab2e9643 regen/regcharclass.pl
  * 1ce43daf54162d0a267412453ce2a613f60f3a7631365775cc52d34213251a83 regen/regcharclass_multi_char_folds.pl
  * ex: set ro ft=c: */
diff --git a/regen.pl b/regen.pl
index 989598eba2..8974821083 100644
--- a/regen.pl
+++ b/regen.pl
@@ -1,6 +1,8 @@
 #!/usr/bin/perl -w
 #
 # regen.pl - a wrapper that runs all *.pl scripts to autogenerate files
+#
+# Normally run with `make regen`.

 require 5.004;	# keep this compatible, an old perl is all we may have before
                 # we build the new one
diff --git a/regen/keywords.pl b/regen/keywords.pl
index a9868bf2ea..dd550f1cce 100755
--- a/regen/keywords.pl
+++ b/regen/keywords.pl
@@ -7,9 +7,19 @@
 # from information stored in the DATA section of this file.
 #
 # Accepts the standard regen_lib -q and -v args.
+#
+# Normally run with `make regen_keywords`.

 use strict;
-use Devel::Tokenizer::C 0.05;
+BEGIN {
+    eval {
+        require Devel::Tokenizer::C;
+        Devel::Tokenizer::C->VERSION(0.05);
+        1;
+    } or die "regen/keywords.pl requires Devel::Tokenizer::C 0.05 or newer.\n",
+              "Install that module in the Perl used to run this script,\n",
+              "then run 'make regen_keywords' again.\n";
+}

 require './regen/regen_lib.pl';

diff --git a/regen/mk_invlists.pl b/regen/mk_invlists.pl
index bbc81acc8f..11a742f053 100644
--- a/regen/mk_invlists.pl
+++ b/regen/mk_invlists.pl
@@ -37,7 +37,7 @@ sub stack_trace {
     return "; called from line(s) $return";
 }

-print "Starting...\n" if DEBUG;
+print "Starting mk_invlists...\n" if DEBUG;

 # This program outputs charclass_invlists.inc, which contains various inversion
 # lists in the form of C arrays that are to be used as-is for inversion lists.
@@ -49,6 +49,8 @@ print "Starting...\n" if DEBUG;
 # in the headers is used to minimize the possibility of things getting
 # out-of-sync, or the wrong data structure being passed.  Currently that
 # random number is:
+#
+# Normally run with `make regen_invlist`.

 my $VERSION_DATA_STRUCTURE_TYPE = 148565664;

@@ -1356,7 +1358,7 @@ sub _Perl_CCC_non0_non230 {
 sub expand_column($table_size, $splits, $enums, $x) {
     print STDERR __FILE__, ": ", __LINE__, ": Entering expand_column ",
                  stack_trace(), "\n",
-                 Dumper $x, $table_size, $enums, $splits if DEBUG;
+                 Dumper $x, $table_size, $enums, $splits if DEBUG > 1;

     # Expand a row or column denoted by $x into its constituents.  $x may be
     # one of:
@@ -1449,7 +1451,7 @@ sub expand_column($table_size, $splits, $enums, $x) {
     }

     print STDERR __FILE__, ": ", __LINE__, ": expanded column returning ",
-                 Dumper \@list if DEBUG;
+                 Dumper \@list if DEBUG > 1;
     return \@list;
 }

@@ -1490,7 +1492,7 @@ sub get_cell_list($table_size, $splits, $enums, $x, $y, $me_too = undef) {

     # It's a lot easier to work with under debugging if the list is sorted.
     @list = sort { $a->[0] <=> $b->[0] or $a->[1] <=> $b->[1] } @list
-                                                                    if DEBUG;
+                                                            if DEBUG;

     return \@list;
 }
@@ -1501,7 +1503,7 @@ sub set_cells($table, $table_size, $splits, $enums, $x, $y, $value, $rule,
     print STDERR __FILE__, ": ", __LINE__, ": Entering set_cells",
                  stack_trace(), "\n",
                  Dumper $x, $y, $value, $rule, $has_unused, $me_too, $enums
-                                                                if DEBUG;
+                                                            if DEBUG > 1;
     # Set cells given by ($x,$y) in $table (whose size is $table_size) to
     # $value. $x and/or $y may expand to multiple cells.  All are set to
     # $value.  $splits, $enums, and $me_too give data to help in performing
@@ -1676,7 +1678,8 @@ sub set_cells($table, $table_size, $splits, $enums, $x, $y, $value, $rule,
         }

         print STDERR __FILE__, ": ", __LINE__,
-          ": Just set \$table->[$x][$y] = ", Dumper $table->[$x][$y] if DEBUG;
+          ": Just set \$table->[$x][$y] = ", Dumper $table->[$x][$y]
+                                                              if DEBUG > 1;
     }
 }

diff --git a/regen/regcharclass.pl b/regen/regcharclass.pl
index 1c04878f42..6ed4882549 100755
--- a/regen/regcharclass.pl
+++ b/regen/regcharclass.pl
@@ -21,6 +21,7 @@ CharClass::Matcher -- Generate C macros that match character classes efficiently
 =head1 SYNOPSIS

     perl regen/regcharclass.pl
+    make regen_charclass

 =head1 DESCRIPTION

diff --git a/regen/regen_lib.pl b/regen/regen_lib.pl
index a14ec4e01f..06e8d54fc2 100644
--- a/regen/regen_lib.pl
+++ b/regen/regen_lib.pl
@@ -10,7 +10,8 @@ use Text::Wrap();

 our $Needs_Write = $^O eq 'cygwin' || $^O eq 'os2' || $^O eq 'MSWin32';

-our $Verbose = 0;
+# REGEN_VERBOSE=1 has the same effect as passing -v.
+our $Verbose = $ENV{REGEN_VERBOSE} ? 1 : 0;
 @ARGV = grep { not($_ eq '-q' and $Verbose = -1) }
   grep { not($_ eq '--tap' and $TAP = 1) }
   grep { not($_ eq '-v' and $Verbose = 1) } @ARGV;
diff --git a/regen/tidy_embed.pl b/regen/tidy_embed.pl
index 8cbfd9bf5d..f62b396e1d 100644
--- a/regen/tidy_embed.pl
+++ b/regen/tidy_embed.pl
@@ -31,8 +31,9 @@ my $parser= HeaderParser->new(
             delete $_->{sort} for @$group_ary;
         },
     );
+my $verbose = $ENV{REGEN_VERBOSE} ? 1 : 0;
 if (@ARGV and $ARGV[0] eq "-v") {
-    # ignore
+    $verbose = 1;
     shift @ARGV;
 }
 my $tap;
@@ -65,7 +66,7 @@ my $grouped_content_txt= $parser->lines_as_str(
 if ($grouped_content_txt ne $parser->{orig_content}) {
     if ($tap) {
         print "not ok - $0 $file\n";
-    } elsif (-t) {
+    } elsif ($verbose || -t) {
         print "Updating $file\n";
     }
     open my $fh,">",$new
@@ -80,4 +81,6 @@ if ($grouped_content_txt ne $parser->{orig_content}) {
         or die "Couldn't move embed.fnc.new to embed.fnc: $!";
 } elsif ($tap) {
     print "ok - $0 $file\n";
+} elsif ($verbose) {
+    print "No changes to $file\n";
 }
diff --git a/regen_perly.pl b/regen_perly.pl
index ee8b3aaf6b..cebf6a5d95 100644
--- a/regen_perly.pl
+++ b/regen_perly.pl
@@ -28,6 +28,8 @@
 # Note also that this script is intended to be run on a UNIX system;
 # it may work elsewhere but no specific attempt has been made to make it
 # portable.
+#
+# Normally run with `make regen_perly`.  This requires a modern Bison.

 use v5.12;
 use warnings;
diff --git a/regexp_constants.h b/regexp_constants.h
index cb89a59673..7db3824671 100644
--- a/regexp_constants.h
+++ b/regexp_constants.h
@@ -87,5 +87,5 @@
  * a0079d7556b20c2de1fdc3d492797a91b8ec8a06006f94460006185cb6380962 lib/unicore/version
  * 0a6b5ab33bb1026531f816efe81aea1a8ffcd34a27cbea37dd6a70a63d73c844 regen/charset_translations.pl
  * 6bbb462516a4ea79e28d58cf387f0b4b63ba83c7d381cd61bdda0b188e148082 regen/mk_PL_charclass.pl
- * e0db8fe02138f978cc88968bd89e4f8e5d9fffe540499ba788dead2a5ecf5e37 regen/mk_invlists.pl
+ * 40e5b8500d364b2adc31055248fc92e05e86fedc487abe5b303be24f38d30b18 regen/mk_invlists.pl
  * ex: set ro ft=c: */
diff --git a/t/porting/regen.t b/t/porting/regen.t
index b870fa0f87..7b2491d05e 100644
--- a/t/porting/regen.t
+++ b/t/porting/regen.t
@@ -37,11 +37,21 @@ my %skip = ("regen_perly.pl"    => [qw(perly.act perly.h perly.tab)],

 my %other_requirement = (
     "regen_perly.pl"        => "requires bison",
-    "regen/keywords.pl"     => "requires Devel::Tokenizer::C",
+    "regen/keywords.pl"     => "requires Devel::Tokenizer::C 0.05 or newer in the installed Perl",
     "regen/mk_invlists.pl"  => "needs the Perl you've just built",
     "regen/regcharclass.pl" => "needs the Perl you've just built",
 );

+my %regen_target = (
+    "regen_perly.pl"        => "make regen_perly",
+    "regen/keywords.pl"     => "make regen_keywords",
+    "regen/mk_invlists.pl"  => "make regen_invlist",
+    "regen/regcharclass.pl" => "make regen_charclass",
+    "regen.pl"              => "make regen",
+    "Porting/makemeta -j"   => "make regen_meta",
+    "Porting/makemeta -y"   => "make regen_meta",
+);
+
 my %skippable_script_for_target;
 for my $script (keys %other_requirement) {
     $skippable_script_for_target{$_} = $script
@@ -120,7 +130,9 @@ OUTER: foreach my $file (@files) {
     is("@bad", '', "generated $file is up to date");
     if (@bad && (my $skippable_script = $skippable_script_for_target{$file})) {
         my $reason = delete $other_requirement{$skippable_script};
-        diag("Note: $skippable_script must be run manually, because it $reason")
+        my $target = $regen_target{$skippable_script}
+                  // "./perl -Ilib $skippable_script";
+        diag("Note: run '$target' to update $file, because it $reason")
             if $reason;
     }
 }
@@ -132,9 +144,7 @@ foreach my $prog (@progs) {
     my $command = qq["$^X" $args];
     if (system $command) { # if it exits with an error...
         $command=~s/\s*--tap//;
-        push @errors, $prog eq "regen.pl"
-                          ? "make regen"
-                          : $command;
+        push @errors, $regen_target{$prog} // $command;
     }
 }
 if ( @errors ) {
@@ -142,5 +152,7 @@ if ( @errors ) {
     die "\n\nERROR. There are generated files which are NOT up to date.\n",
         "You should run the following commands to update these files:\n\n",
         $commands, "\n\n",
+        "Alternatively, run 'make regen-all'.  On Unix-like systems this includes\n",
+        "'make regen_perly' and requires a modern version of Bison.\n\n",
         "Once they are regenerated you should commit the changes.\n\n";
 }
diff --git a/uni_keywords.h b/uni_keywords.h
index be637c50af..06c03dc8f6 100644
--- a/uni_keywords.h
+++ b/uni_keywords.h
@@ -8287,6 +8287,6 @@ match_uniprop( const unsigned char * const key, const U16 key_len ) {
  * a0079d7556b20c2de1fdc3d492797a91b8ec8a06006f94460006185cb6380962 lib/unicore/version
  * 0a6b5ab33bb1026531f816efe81aea1a8ffcd34a27cbea37dd6a70a63d73c844 regen/charset_translations.pl
  * 6bbb462516a4ea79e28d58cf387f0b4b63ba83c7d381cd61bdda0b188e148082 regen/mk_PL_charclass.pl
- * e0db8fe02138f978cc88968bd89e4f8e5d9fffe540499ba788dead2a5ecf5e37 regen/mk_invlists.pl
+ * 40e5b8500d364b2adc31055248fc92e05e86fedc487abe5b303be24f38d30b18 regen/mk_invlists.pl
  * a6ce8aefad005c081d4e04523e1f1f1a5a1bed5414ca4a421b5b16b73bfce6a4 regen/mph.pl
  * ex: set ro ft=c: */
diff --git a/vms/descrip_mms.template b/vms/descrip_mms.template
index fffedcab24..e9fc0ad944 100644
--- a/vms/descrip_mms.template
+++ b/vms/descrip_mms.template
@@ -526,9 +526,40 @@ printconfig :
 regen :
 	$(INSTPERL) regen.pl

-regen_headers :
+regen_headers regen-headers :
 	$(INSTPERL) regen.pl -v

+# Requires Devel::Tokenizer::C 0.05 or newer in the installed Perl.
+regen_keywords regen-keywords :
+	$(INSTPERL) [.regen]keywords.pl
+
+regen_invlist regen-invlist :
+	$(PERL) [.regen]mk_invlists.pl
+
+regen_charclass regen-charclass :
+	$(PERL) [.regen]regcharclass.pl
+
+regen_meta regen-meta :
+	$(PERL) Porting/makemeta -y
+	$(PERL) Porting/makemeta -j
+
+# regen_perly is omitted here.  It depends on tools only known to be
+# available on Unix-like systems.
+regen_all regen-all :
+	@ write sys$output "If this fails, run the regeneration steps one at a time:"
+	@ write sys$output "  $(MMS) regen"
+	@ write sys$output "  $(MMS) regen_keywords"
+	@ write sys$output "  $(MMS) regen_invlist"
+	@ write sys$output "  $(MMS) regen_charclass"
+	@ write sys$output "  $(MMS) regen_meta"
+	$(MAKE)
+	$(MAKE) regen
+	$(MAKE) regen_keywords
+	$(MAKE) regen_invlist
+	$(MAKE) regen_charclass
+	$(MAKE) regen_meta
+	$(MAKE)
+
 .ifdef LINK_ONLY
 .else
 perly$(O) : perly.c, perly.h, $(h)
diff --git a/win32/GNUmakefile b/win32/GNUmakefile
index d47c28776f..6730bd2eff 100644
--- a/win32/GNUmakefile
+++ b/win32/GNUmakefile
@@ -1847,9 +1847,48 @@ test-reonly : reonly utils
 	$(XCOPY) $(GLOBEXE) ..\t\$(NULL)
 	cd ..\t && perl.exe harness $(OPT) -re \bpat\\/ $(EXTRA)

+.PHONY: regen regen-headers \
+	regen_keywords regen-keywords regen_invlist regen-invlist \
+	regen_charclass regen-charclass \
+	regen_meta regen-meta regen_all regen-all
+
 regen :
 	cd .. && regen.pl

+regen_headers regen-headers :
+	cd .. && regen.pl -v
+
+# Requires Devel::Tokenizer::C 0.05 or newer in the installed Perl.
+regen_keywords regen-keywords :
+	cd .. && perl regen\keywords.pl
+
+regen_invlist regen-invlist :
+	cd .. && perl.exe -Ilib regen\mk_invlists.pl
+
+regen_charclass regen-charclass :
+	cd .. && perl.exe -Ilib regen\regcharclass.pl
+
+regen_meta regen-meta :
+	cd .. && perl.exe -Ilib Porting\makemeta -y
+	cd .. && perl.exe -Ilib Porting\makemeta -j
+
+# regen_perly is omitted here.  It depends on tools only known to be
+# available on Unix-like systems.
+regen_all regen-all :
+	@echo If this fails, run the regeneration steps one at a time:
+	@echo   gmake regen
+	@echo   gmake regen_keywords
+	@echo   gmake regen_invlist
+	@echo   gmake regen_charclass
+	@echo   gmake regen_meta
+	$(PLMAKE)
+	$(PLMAKE) regen
+	$(PLMAKE) regen_keywords
+	$(PLMAKE) regen_invlist
+	$(PLMAKE) regen_charclass
+	$(PLMAKE) regen_meta
+	$(PLMAKE)
+
 test-notty : test-prep
 	set PERL_STATIC_EXT=$(STATIC_EXT) && \
 	    set PERL_SKIP_TTY_TEST=1 && \
diff --git a/win32/Makefile b/win32/Makefile
index 38d43fa22a..40adb564f8 100644
--- a/win32/Makefile
+++ b/win32/Makefile
@@ -1363,6 +1363,40 @@ regen :
 	regen.pl
 	cd win32

+regen_headers regen-headers :
+	cd .. && regen.pl -v
+
+# Requires Devel::Tokenizer::C 0.05 or newer in the installed Perl.
+regen_keywords regen-keywords :
+	cd .. && perl regen\keywords.pl
+
+regen_invlist regen-invlist :
+	cd .. && perl.exe -Ilib regen\mk_invlists.pl
+
+regen_charclass regen-charclass :
+	cd .. && perl.exe -Ilib regen\regcharclass.pl
+
+regen_meta regen-meta :
+	cd .. && perl.exe -Ilib Porting\makemeta -y
+	cd .. && perl.exe -Ilib Porting\makemeta -j
+
+# regen_perly is omitted here.  It depends on tools only known to be
+# available on Unix-like systems.
+regen_all regen-all :
+	@echo If this fails, run the regeneration steps one at a time:
+	@echo   nmake regen
+	@echo   nmake regen_keywords
+	@echo   nmake regen_invlist
+	@echo   nmake regen_charclass
+	@echo   nmake regen_meta
+	$(MAKE)
+	$(MAKE) regen
+	$(MAKE) regen_keywords
+	$(MAKE) regen_invlist
+	$(MAKE) regen_charclass
+	$(MAKE) regen_meta
+	$(MAKE)
+
 test-notty : test-prep
 	set PERL_SKIP_TTY_TEST=1
 	cd ..\t