This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
|| instead of "or" (perl#78708)
[perl5.git] / utils / h2xs.PL
index ceac64e..ee4079f 100644 (file)
@@ -66,6 +66,9 @@ the library path determined by Configure.  That path can be augmented
 by including arguments of the form B<-L/another/library/path> in the
 extra-libraries argument.
 
+In spite of its name, I<h2xs> may also be used to create a skeleton pure
+Perl module. See the B<-X> option.
+
 =head1 OPTIONS
 
 =over 5
@@ -105,8 +108,8 @@ Omit the autogenerated stub POD section.
 
 =item B<-X>, B<--omit-XS>
 
-Omit the XS portion.  Used to generate templates for a module which is not
-XS-based.  C<-c> and C<-f> are implicitly enabled.
+Omit the XS portion. Used to generate a skeleton pure Perl module.
+C<-c> and C<-f> are implicitly enabled.
 
 =item B<-a>, B<--gen-accessors>
 
@@ -231,7 +234,7 @@ of C<h2xs> may gain the ability to make educated guesses.
 
 When B<--compat-version> (B<-b>) is present the generated tests will use
 C<Test::More> rather than C<Test> which is the default for versions before
-5.7.2 .   C<Test::More> will be added to PREREQ_PM in the generated
+5.6.2.  C<Test::More> will be added to PREREQ_PM in the generated
 C<Makefile.PL>.
 
 =item B<--use-old-tests>
@@ -306,6 +309,9 @@ also the section on L<LIMITATIONS of B<-x>>.
     # Extension is ONC::RPC.
     h2xs -cfn ONC::RPC
 
+    # Extension is a pure Perl module with no XS code.
+    h2xs -X My::Module
+
     # Extension is Lib::Foo which works at least with Perl5.005_03.
     # Constants are created for all #defines and enums h2xs can find
     # in foo.h.
@@ -352,7 +358,7 @@ also the section on L<LIMITATIONS of B<-x>>.
 
 Suppose that you have some C files implementing some functionality,
 and the corresponding header files.  How to create an extension which
-makes this functionality accessable in Perl?  The example below
+makes this functionality accessible in Perl?  The example below
 assumes that the header files are F<interface_simple.h> and
 I<interface_hairy.h>, and you want the perl module be named as
 C<Ext::Ension>.  If you need some preprocessor directives and/or
@@ -524,7 +530,7 @@ OPTIONS:
     -X, --omit-XS         Omit the XS portion (implies both -c and -f).
     -a, --gen-accessors   Generate get/set accessors for struct and union members
                           (used with -x).
-    -b, --compat-version  Specify a perl version to be backwards compatibile with.
+    -b, --compat-version  Specify a perl version to be backwards compatible with.
     -c, --omit-constant   Omit the constant() function and specialised AUTOLOAD
                           from the XS file.
     -d, --debugging       Turn on debugging messages.
@@ -554,6 +560,8 @@ OPTIONS:
         --skip-warnings   Do not use the pragma C<warnings>.
     -v, --version         Specify a version number for this extension.
     -x, --autogen-xsubs   Autogenerate XSUBs using C::Scan.
+        --use-xsloader    Use XSLoader in backward compatible modules (ignored
+                          when used with -X).
 
 extra_libraries
          are any libraries that might be needed for loading the
@@ -593,6 +601,7 @@ my ($opt_A,
     $skip_autoloader,
     $skip_strict,
     $skip_warnings,
+    $use_xsloader
    );
 
 Getopt::Long::Configure('bundling');
@@ -631,6 +640,7 @@ my %options = (
                 'skip-autoloader'    => \$skip_autoloader,
                 'skip-warnings'      => \$skip_warnings,
                 'skip-strict'        => \$skip_strict,
+                'use-xsloader'       => \$use_xsloader,
               );
 
 GetOptions(%options) || usage;
@@ -639,18 +649,16 @@ usage if $opt_h;
 
 if( $opt_b ){
     usage "You cannot use -b and -m at the same time.\n" if ($opt_b && $opt_m);
-    $opt_b =~ /^\d+\.\d+\.\d+/ ||
+    $opt_b =~ /^v?(\d+)\.(\d+)\.(\d+)/ ||
     usage "You must provide the backwards compatibility version in X.Y.Z form. "
           .  "(i.e. 5.5.0)\n";
-    my ($maj,$min,$sub) = split(/\./,$opt_b,3);
+    my ($maj,$min,$sub) = ($1,$2,$3);
     if ($maj < 5 || ($maj == 5 && $min < 6)) {
         $compat_version =
            $sub ? sprintf("%d.%03d%02d",$maj,$min,$sub) :
                   sprintf("%d.%03d",    $maj,$min);
     } else {
-        $compat_version =
-           $sub ? sprintf("%d.%03d%03d",$maj,$min,$sub) :
-                  sprintf("%d.%03d",    $maj,$min);
+        $compat_version = sprintf("%d.%03d%03d",$maj,$min,$sub);
     }
 } else {
     my ($maj,$min,$sub) = $compat_version =~ /(\d+)\.(\d\d\d)(\d*)/;
@@ -781,7 +789,7 @@ if( @path_h ){
     }
     else {
       @paths = (File::Spec->curdir(), $Config{usrinc},
-               (split ' ', $Config{locincpth}), '/usr/include');
+               (split / +/, $Config{locincpth} // ""), '/usr/include');
     }
     foreach my $path_h (@path_h) {
         $name ||= $path_h;
@@ -885,7 +893,7 @@ if( @path_h ){
       }
       else {
        # Work from miniperl too - on "normal" systems
-        my $SEEK_SET = eval 'use Fcntl qw/SEEK_SET/; SEEK_SET' or 0;
+        my $SEEK_SET = eval 'use Fcntl qw/SEEK_SET/; SEEK_SET' || 0;
         seek CH, 0, $SEEK_SET;
         my $src = do { local $/; <CH> };
         close CH;
@@ -893,18 +901,19 @@ if( @path_h ){
 
         # Remove C and C++ comments
         $src =~ s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#$2#gs;
+        $src =~ s#//.*$##gm;
 
-        while ($src =~ /(\benum\s*([\w_]*)\s*\{\s([\s\w=,]+)\})/gsc) {
-            my ($enum_name, $enum_body) =
-                $1 =~ /enum\s*([\w_]*)\s*\{\s([\s\w=,]+)\}/gs;
+       while ($src =~ /\benum\s*([\w_]*)\s*\{\s([^}]+)\}/gsc) {
+           my ($enum_name, $enum_body) = ($1, $2);
             # skip enums matching $opt_e
             next if $opt_e && $enum_name =~ /$opt_e/;
             my $val = 0;
             for my $item (split /,/, $enum_body) {
-                my ($key, $declared_val) = $item =~ /(\w+)\s*=\s*(.*)/;
-                $val = length($declared_val) ? $declared_val : 1 + $val;
-                $seen_define{$key} = $declared_val;
-                $const_names{$key}++;
+                next if $item =~ /\A\s*\Z/;
+                my ($key, $declared_val) = $item =~ /(\w+)\s*(?:=\s*(.*))?/;
+                $val = defined($declared_val) && length($declared_val) ? $declared_val : 1 + $val;
+                $seen_define{$key} = $val;
+                $const_names{$key} = { name => $key, macro => 1 };
             }
         } # while (...)
       } # if (!defined $opt_e or $opt_e)
@@ -1068,7 +1077,14 @@ if( ! $opt_X ){  # use XS, unless it was disabled
     }
   }
 }
-my @const_names = sort keys %const_names;
+my (@const_specs, @const_names);
+
+for (sort(keys(%const_names))) {
+    my $v = $const_names{$_};
+    
+    push(@const_specs, ref($v) ? $v : $_);
+    push(@const_names, $_);
+}
 
 -d $modpmdir || mkpath([$modpmdir], 0, 0775);
 open(PM, ">$modpmname") || die "Can't create $ext$modpname/$modpmname: $!\n";
@@ -1101,7 +1117,7 @@ print PM <<'END' unless $skip_exporter;
 require Exporter;
 END
 
-my $use_Dyna = (not $opt_X and $compat_version < 5.006);
+my $use_Dyna = (not $opt_X and $compat_version < 5.006 and not $use_xsloader);
 print PM <<"END" if $use_Dyna;  # use DynaLoader, unless XS was disabled
 require DynaLoader;
 END
@@ -1236,6 +1252,7 @@ eval {
        }
      };
 
+$author =~ s/'/\\'/g if defined $author;
 $author ||= "A. U. Thor";
 $email  ||= 'a.u.thor@a.galaxy.far.far.away';
 
@@ -1456,7 +1473,7 @@ if( ! $opt_c ) {
                    XS_FILE =>      $xsfallback,
                    DEFAULT_TYPE => $opt_t,
                    NAME =>         $module,
-                   NAMES =>        \@const_names,
+                   NAMES =>        \@const_specs,
                  );
   print XS "#include \"$constscfname\"\n";
 }
@@ -1707,7 +1724,7 @@ sub accessor_docs {
 #  my \$buffer = $name->new();
 #  my \$obj = \$buffer->_to_ptr();
 #
-#This exersizes the following two methods, and an additional class
+#This exercises the following two methods, and an additional class
 #C<$name>, the internal representation of which is a reference to a
 #packed string with the C structure.  Keep in mind that \$buffer should
 #better survive longer than \$obj.
@@ -1784,7 +1801,7 @@ sub get_typemap {
 sub normalize_type {           # Second arg: do not strip const's before \*
   my $type = shift;
   my $do_keep_deep_const = shift;
-  # If $do_keep_deep_const this is heuristical only
+  # If $do_keep_deep_const this is heuristic only
   my $keep_deep_const = ($do_keep_deep_const ? '\b(?![^(,)]*\*)' : '');
   my $ignore_mods
     = "(?:\\b(?:(?:__const__|const)$keep_deep_const|static|inline|__inline__)\\b\\s*)*";
@@ -1884,15 +1901,20 @@ EOP
 warn "Writing $ext$modpname/Makefile.PL\n";
 open(PL, ">Makefile.PL") || die "Can't create $ext$modpname/Makefile.PL: $!\n";
 
-my $prereq_pm;
+my $prereq_pm = '';
 
-if ( $compat_version < 5.00702 and $new_test )
+if ( $compat_version < 5.006002 and $new_test )
 {
-  $prereq_pm = q%'Test::More'  =>  0%;
+  $prereq_pm .= q%'Test::More'  =>  0, %;
 }
-else
+elsif ( $compat_version < 5.006002 )
+{
+  $prereq_pm .= q%'Test'        =>  0, %;
+}
+
+if ( $compat_version < 5.006 and !$opt_X and $use_xsloader)
 {
-  $prereq_pm = '';
+  $prereq_pm .= q%'XSLoader'    =>  0, %;
 }
 
 print PL <<"END";
@@ -1940,7 +1962,7 @@ if (!$opt_c) {
                            XS_FILE =>      $constsxsfname,
                            DEFAULT_TYPE => $opt_t,
                            NAME =>         $module,
-                           NAMES =>        \@const_names,
+                           NAMES =>        \@const_specs,
                  );
   print PL <<"END";
 if  (eval {require ExtUtils::Constant; 1}) {
@@ -1999,7 +2021,7 @@ EOM
 close(PL) || die "Can't close $ext$modpname/Makefile.PL: $!\n";
 
 # Create a simple README since this is a CPAN requirement
-# and it doesnt hurt to have one
+# and it doesn't hurt to have one
 warn "Writing $ext$modpname/README\n";
 open(RM, ">README") || die "Can't create $ext$modpname/README:$!\n";
 my $thisyear = (gmtime)[5] + 1900;
@@ -2008,13 +2030,17 @@ my $rmheadeq = "=" x length($rmhead);
 
 my $rm_prereq;
 
-if ( $compat_version < 5.00702 and $new_test )
+if ( $compat_version < 5.006002 and $new_test )
+{
+  $rm_prereq = 'Test::More';
+}
+elsif ( $compat_version < 5.006002 )
 {
-   $rm_prereq = 'Test::More';
+  $rm_prereq = 'Test';
 }
 else
 {
-   $rm_prereq = 'blah blah blah';
+  $rm_prereq = 'blah blah blah';
 }
 
 print RM <<_RMEND_;
@@ -2067,18 +2093,21 @@ my $tests = @const_names ? 2 : 1;
 open EX, ">$testfile" or die "Can't create $ext$modpname/$testfile: $!\n";
 
 print EX <<_END_;
-# Before `make install' is performed this script should be runnable with
-# `make test'. After `make install' it should work as `perl $modpname.t'
+# Before 'make install' is performed this script should be runnable with
+# 'make test'. After 'make install' it should work as 'perl $modpname.t'
 
 #########################
 
 # change 'tests => $tests' to 'tests => last_test_to_print';
 
+use strict;
+use warnings;
+
 _END_
 
 my $test_mod = 'Test::More';
 
-if ( $old_test or ($compat_version < 5.007 and not $new_test ))
+if ( $old_test or ($compat_version < 5.006002 and not $new_test ))
 {
   my $test_mod = 'Test';