diff options
author | 2008-09-29 17:17:50 +0000 | |
---|---|---|
committer | 2008-09-29 17:17:50 +0000 | |
commit | 850e275390052b330d93020bf619a739a3c277ac (patch) | |
tree | db372d287586cf504a5ead4801f6c6cf7eb31449 /gnu/usr.bin/perl/lib/ExtUtils | |
parent | more updates on which args do and do not mix (doc only, this time): (diff) | |
download | wireguard-openbsd-850e275390052b330d93020bf619a739a3c277ac.tar.xz wireguard-openbsd-850e275390052b330d93020bf619a739a3c277ac.zip |
import perl 5.10.0 from CPAN
Diffstat (limited to 'gnu/usr.bin/perl/lib/ExtUtils')
72 files changed, 7097 insertions, 408 deletions
diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder.pm new file mode 100644 index 00000000000..fae01b116dd --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder.pm @@ -0,0 +1,318 @@ +package ExtUtils::CBuilder; + +use File::Spec (); +use File::Path (); +use File::Basename (); + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +$VERSION = eval $VERSION; + +# Okay, this is the brute-force method of finding out what kind of +# platform we're on. I don't know of a systematic way. These values +# came from the latest (bleadperl) perlport.pod. + +my %OSTYPES = qw( + aix Unix + bsdos Unix + dgux Unix + dynixptx Unix + freebsd Unix + linux Unix + hpux Unix + irix Unix + darwin Unix + machten Unix + next Unix + openbsd Unix + netbsd Unix + dec_osf Unix + svr4 Unix + svr5 Unix + sco_sv Unix + unicos Unix + unicosmk Unix + solaris Unix + sunos Unix + cygwin Unix + os2 Unix + + dos Windows + MSWin32 Windows + + os390 EBCDIC + os400 EBCDIC + posix-bc EBCDIC + vmesa EBCDIC + + MacOS MacOS + VMS VMS + VOS VOS + riscos RiscOS + amigaos Amiga + mpeix MPEiX + ); + +# We only use this once - don't waste a symbol table entry on it. +# More importantly, don't make it an inheritable method. +my $load = sub { + my $mod = shift; + eval "use $mod"; + die $@ if $@; + @ISA = ($mod); +}; + +{ + my @package = split /::/, __PACKAGE__; + + if (grep {-e File::Spec->catfile($_, @package, 'Platform', $^O) . '.pm'} @INC) { + $load->(__PACKAGE__ . "::Platform::$^O"); + + } elsif (exists $OSTYPES{$^O} and + grep {-e File::Spec->catfile($_, @package, 'Platform', $OSTYPES{$^O}) . '.pm'} @INC) { + $load->(__PACKAGE__ . "::Platform::$OSTYPES{$^O}"); + + } else { + $load->(__PACKAGE__ . "::Base"); + } +} + +sub os_type { $OSTYPES{$^O} } + +1; +__END__ + +=head1 NAME + +ExtUtils::CBuilder - Compile and link C code for Perl modules + +=head1 SYNOPSIS + + use ExtUtils::CBuilder; + + my $b = ExtUtils::CBuilder->new(%options); + $obj_file = $b->compile(source => 'MyModule.c'); + $lib_file = $b->link(objects => $obj_file); + +=head1 DESCRIPTION + +This module can build the C portions of Perl modules by invoking the +appropriate compilers and linkers in a cross-platform manner. It was +motivated by the C<Module::Build> project, but may be useful for other +purposes as well. However, it is I<not> intended as a general +cross-platform interface to all your C building needs. That would +have been a much more ambitious goal! + +=head1 METHODS + +=over 4 + +=item new + +Returns a new C<ExtUtils::CBuilder> object. A C<config> parameter +lets you override C<Config.pm> settings for all operations performed +by the object, as in the following example: + + # Use a different compiler than Config.pm says + my $b = ExtUtils::CBuilder->new( config => + { ld => 'gcc' } ); + +A C<quiet> parameter tells C<CBuilder> to not print its C<system()> +commands before executing them: + + # Be quieter than normal + my $b = ExtUtils::CBuilder->new( quiet => 1 ); + +=item have_compiler + +Returns true if the current system has a working C compiler and +linker, false otherwise. To determine this, we actually compile and +link a sample C library. + +=item compile + +Compiles a C source file and produces an object file. The name of the +object file is returned. The source file is specified in a C<source> +parameter, which is required; the other parameters listed below are +optional. + +=over 4 + +=item C<object_file> + +Specifies the name of the output file to create. Otherwise the +C<object_file()> method will be consulted, passing it the name of the +C<source> file. + +=item C<include_dirs> + +Specifies any additional directories in which to search for header +files. May be given as a string indicating a single directory, or as +a list reference indicating multiple directories. + +=item C<extra_compiler_flags> + +Specifies any additional arguments to pass to the compiler. Should be +given as a list reference containing the arguments individually, or if +this is not possible, as a string containing all the arguments +together. + +=back + +The operation of this method is also affected by the +C<archlibexp>, C<cccdlflags>, C<ccflags>, C<optimize>, and C<cc> +entries in C<Config.pm>. + +=item link + +Invokes the linker to produce a library file from object files. In +scalar context, the name of the library file is returned. In list +context, the library file and any temporary files created are +returned. A required C<objects> parameter contains the name of the +object files to process, either in a string (for one object file) or +list reference (for one or more files). The following parameters are +optional: + + +=over 4 + +=item lib_file + +Specifies the name of the output library file to create. Otherwise +the C<lib_file()> method will be consulted, passing it the name of +the first entry in C<objects>. + +=item module_name + +Specifies the name of the Perl module that will be created by linking. +On platforms that need to do prelinking (Win32, OS/2, etc.) this is a +required parameter. + +=item extra_linker_flags + +Any additional flags you wish to pass to the linker. + +=back + +On platforms where C<need_prelink()> returns true, C<prelink()> +will be called automatically. + +The operation of this method is also affected by the C<lddlflags>, +C<shrpenv>, and C<ld> entries in C<Config.pm>. + +=item link_executable + +Invokes the linker to produce an executable file from object files. In +scalar context, the name of the executable file is returned. In list +context, the executable file and any temporary files created are +returned. A required C<objects> parameter contains the name of the +object files to process, either in a string (for one object file) or +list reference (for one or more files). The optional parameters are +the same as C<link> with exception for + + +=over 4 + +=item exe_file + +Specifies the name of the output executable file to create. Otherwise +the C<exe_file()> method will be consulted, passing it the name of the +first entry in C<objects>. + +=back + +=item object_file + + my $object_file = $b->object_file($source_file); + +Converts the name of a C source file to the most natural name of an +output object file to create from it. For instance, on Unix the +source file F<foo.c> would result in the object file F<foo.o>. + +=item lib_file + + my $lib_file = $b->lib_file($object_file); + +Converts the name of an object file to the most natural name of a +output library file to create from it. For instance, on Mac OS X the +object file F<foo.o> would result in the library file F<foo.bundle>. + +=item exe_file + + my $exe_file = $b->exe_file($object_file); + +Converts the name of an object file to the most natural name of an +executable file to create from it. For instance, on Mac OS X the +object file F<foo.o> would result in the executable file F<foo>, and +on Windows it would result in F<foo.exe>. + + +=item prelink + +On certain platforms like Win32, OS/2, VMS, and AIX, it is necessary +to perform some actions before invoking the linker. The +C<ExtUtils::Mksymlists> module does this, writing files used by the +linker during the creation of shared libraries for dynamic extensions. +The names of any files written will be returned as a list. + +Several parameters correspond to C<ExtUtils::Mksymlists::Mksymlists()> +options, as follows: + + Mksymlists() prelink() type + -------------|-------------------|------------------- + NAME | dl_name | string (required) + DLBASE | dl_base | string + FILE | dl_file | string + DL_VARS | dl_vars | array reference + DL_FUNCS | dl_funcs | hash reference + FUNCLIST | dl_func_list | array reference + IMPORTS | dl_imports | hash reference + VERSION | dl_version | string + +Please see the documentation for C<ExtUtils::Mksymlists> for the +details of what these parameters do. + +=item need_prelink + +Returns true on platforms where C<prelink()> should be called +during linking, and false otherwise. + +=item extra_link_args_after_prelink + +Returns list of extra arguments to give to the link command; the arguments +are the same as for prelink(), with addition of array reference to the +results of prelink(); this reference is indexed by key C<prelink_res>. + +=back + +=head1 TO DO + +Currently this has only been tested on Unix and doesn't contain any of +the Windows-specific code from the C<Module::Build> project. I'll do +that next. + +=head1 HISTORY + +This module is an outgrowth of the C<Module::Build> project, to which +there have been many contributors. Notably, Randy W. Sims submitted +lots of code to support 3 compilers on Windows and helped with various +other platform-specific issues. Ilya Zakharevich has contributed +fixes for OS/2; John E. Malmberg and Peter Prymmer have done likewise +for VMS. + +=head1 AUTHOR + +Ken Williams, kwilliams@cpan.org + +=head1 COPYRIGHT + +Copyright (c) 2003-2005 Ken Williams. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +perl(1), Module::Build(3) + +=cut diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Base.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Base.pm new file mode 100644 index 00000000000..0c08ab71b73 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Base.pm @@ -0,0 +1,279 @@ +package ExtUtils::CBuilder::Base; + +use strict; +use File::Spec; +use File::Basename; +use Cwd (); +use Config; +use Text::ParseWords; + +use vars qw($VERSION); +$VERSION = '0.21'; + +sub new { + my $class = shift; + my $self = bless {@_}, $class; + + $self->{properties}{perl} = $class->find_perl_interpreter + or warn "Warning: Can't locate your perl binary"; + + while (my ($k,$v) = each %Config) { + $self->{config}{$k} = $v unless exists $self->{config}{$k}; + } + return $self; +} + +sub find_perl_interpreter { + my $perl; + File::Spec->file_name_is_absolute($perl = $^X) + or -f ($perl = $Config::Config{perlpath}) + or ($perl = $^X); + return $perl; +} + +sub add_to_cleanup { + my $self = shift; + foreach (@_) { + $self->{files_to_clean}{$_} = 1; + } +} + +sub cleanup { + my $self = shift; + foreach my $file (keys %{$self->{files_to_clean}}) { + unlink $file; + } +} + +sub object_file { + my ($self, $filename) = @_; + + # File name, minus the suffix + (my $file_base = $filename) =~ s/\.[^.]+$//; + return "$file_base$self->{config}{obj_ext}"; +} + +sub arg_include_dirs { + my $self = shift; + return map {"-I$_"} @_; +} + +sub arg_nolink { '-c' } + +sub arg_object_file { + my ($self, $file) = @_; + return ('-o', $file); +} + +sub arg_share_object_file { + my ($self, $file) = @_; + return ($self->split_like_shell($self->{config}{lddlflags}), '-o', $file); +} + +sub arg_exec_file { + my ($self, $file) = @_; + return ('-o', $file); +} + +sub arg_defines { + my ($self, %args) = @_; + return map "-D$_=$args{$_}", keys %args; +} + +sub compile { + my ($self, %args) = @_; + die "Missing 'source' argument to compile()" unless defined $args{source}; + + my $cf = $self->{config}; # For convenience + + $args{object_file} ||= $self->object_file($args{source}); + + my @include_dirs = $self->arg_include_dirs + (@{$args{include_dirs} || []}, + $self->perl_inc()); + + my @defines = $self->arg_defines( %{$args{defines} || {}} ); + + my @extra_compiler_flags = $self->split_like_shell($args{extra_compiler_flags}); + my @cccdlflags = $self->split_like_shell($cf->{cccdlflags}); + my @ccflags = $self->split_like_shell($cf->{ccflags}); + my @optimize = $self->split_like_shell($cf->{optimize}); + my @flags = (@include_dirs, @defines, @cccdlflags, @extra_compiler_flags, + $self->arg_nolink, + @ccflags, @optimize, + $self->arg_object_file($args{object_file}), + ); + + my @cc = $self->split_like_shell($cf->{cc}); + + $self->do_system(@cc, @flags, $args{source}) + or die "error building $args{object_file} from '$args{source}'"; + + return $args{object_file}; +} + +sub have_compiler { + my ($self) = @_; + return $self->{have_compiler} if defined $self->{have_compiler}; + + my $tmpfile = File::Spec->catfile(File::Spec->tmpdir, 'compilet.c'); + { + local *FH; + open FH, "> $tmpfile" or die "Can't create $tmpfile: $!"; + print FH "int boot_compilet() { return 1; }\n"; + close FH; + } + + my ($obj_file, @lib_files); + eval { + $obj_file = $self->compile(source => $tmpfile); + @lib_files = $self->link(objects => $obj_file, module_name => 'compilet'); + }; + warn $@ if $@; + my $result = $self->{have_compiler} = $@ ? 0 : 1; + + foreach (grep defined, $tmpfile, $obj_file, @lib_files) { + 1 while unlink; + } + return $result; +} + +sub lib_file { + my ($self, $dl_file) = @_; + $dl_file =~ s/\.[^.]+$//; + $dl_file =~ tr/"//d; + return "$dl_file.$self->{config}{dlext}"; +} + + +sub exe_file { + my ($self, $dl_file) = @_; + $dl_file =~ s/\.[^.]+$//; + $dl_file =~ tr/"//d; + return "$dl_file$self->{config}{_exe}"; +} + +sub need_prelink { 0 } + +sub extra_link_args_after_prelink { return } + +sub prelink { + my ($self, %args) = @_; + + ($args{dl_file} = $args{dl_name}) =~ s/.*::// unless $args{dl_file}; + + require ExtUtils::Mksymlists; + ExtUtils::Mksymlists::Mksymlists( # dl. abbrev for dynamic library + DL_VARS => $args{dl_vars} || [], + DL_FUNCS => $args{dl_funcs} || {}, + FUNCLIST => $args{dl_func_list} || [], + IMPORTS => $args{dl_imports} || {}, + NAME => $args{dl_name}, # Name of the Perl module + DLBASE => $args{dl_base}, # Basename of DLL file + FILE => $args{dl_file}, # Dir + Basename of symlist file + VERSION => (defined $args{dl_version} ? $args{dl_version} : '0.0'), + ); + + # Mksymlists will create one of these files + return grep -e, map "$args{dl_file}.$_", qw(ext def opt); +} + +sub link { + my ($self, %args) = @_; + return $self->_do_link('lib_file', lddl => 1, %args); +} + +sub link_executable { + my ($self, %args) = @_; + return $self->_do_link('exe_file', lddl => 0, %args); +} + +sub _do_link { + my ($self, $type, %args) = @_; + + my $cf = $self->{config}; # For convenience + + my $objects = delete $args{objects}; + $objects = [$objects] unless ref $objects; + my $out = $args{$type} || $self->$type($objects->[0]); + + my @temp_files; + @temp_files = + $self->prelink(%args, + dl_name => $args{module_name}) if $args{lddl} && $self->need_prelink; + + my @linker_flags = ($self->split_like_shell($args{extra_linker_flags}), + $self->extra_link_args_after_prelink(%args, dl_name => $args{module_name}, + prelink_res => \@temp_files)); + + my @output = $args{lddl} ? $self->arg_share_object_file($out) : $self->arg_exec_file($out); + my @shrp = $self->split_like_shell($cf->{shrpenv}); + my @ld = $self->split_like_shell($cf->{ld}); + + $self->do_system(@shrp, @ld, @output, @$objects, @linker_flags) + or die "error building $out from @$objects"; + + return wantarray ? ($out, @temp_files) : $out; +} + + +sub do_system { + my ($self, @cmd) = @_; + print "@cmd\n" if !$self->{quiet}; + return !system(@cmd); +} + +sub split_like_shell { + my ($self, $string) = @_; + + return () unless defined($string); + return @$string if UNIVERSAL::isa($string, 'ARRAY'); + $string =~ s/^\s+|\s+$//g; + return () unless length($string); + + return Text::ParseWords::shellwords($string); +} + +# if building perl, perl's main source directory +sub perl_src { + # N.B. makemaker actually searches regardless of PERL_CORE, but + # only squawks at not finding it if PERL_CORE is set + + return unless $ENV{PERL_CORE}; + + my $Updir = File::Spec->updir; + my $dir = File::Spec->curdir; + + # Try up to 5 levels upwards + for (0..10) { + if ( + -f File::Spec->catfile($dir,"config_h.SH") + && + -f File::Spec->catfile($dir,"perl.h") + && + -f File::Spec->catfile($dir,"lib","Exporter.pm") + ) { + return Cwd::realpath( $dir ); + } + + $dir = File::Spec->catdir($dir, $Updir); + } + + warn "PERL_CORE is set but I can't find your perl source!\n"; + return ''; # return empty string if $ENV{PERL_CORE} but can't find dir ??? +} + +# directory of perl's include files +sub perl_inc { + my $self = shift; + + $self->perl_src() || File::Spec->catdir($self->{config}{archlibexp},"CORE"); +} + +sub DESTROY { + my $self = shift; + local($., $@, $!, $^E, $?); + $self->cleanup(); +} + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Changes b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Changes new file mode 100644 index 00000000000..fbf6f4a1200 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Changes @@ -0,0 +1,207 @@ +Revision history for Perl extension ExtUtils::CBuilder. + + - Clean up perl_src path using Cwd::realpath(). Only affects usage + as part of the perl core. + + - Protect $., $@, $!, $^E, and $? from any clobbering that might + occur in our DESTROY method. [Zefram] + + - From bleadperl, a patch to clean up debug symbol files (.pdb for + VC++, .tds for BCC) when running have_compiler(). [Steve Hay & + Steve Peters] + +0.19 - Sun May 13 14:29:18 2007 + + - When building as part of the perl core (so this is irrelevant for + people downloading from CPAN) we now try a little harder to find + the perl sources. [Jos Boumans] + + - Fixed a part of the manifest thingy that got broken on 64-bit + Windows platforms in version 0.18. [Steve Hay, Jan Dubois] + +0.18 - Mon Mar 26 21:29:09 2007 + + - Various OS/2 fixes: + + Put .LIB file near .DEF file + + Got library-file building working better + + Handled libperl_overrides better + [Ilya Zakharevich] + + - On Windows: embed manifest files in DLLs built with Module-Build + when using VC8. [Steve Hay] + + - Added a workaround for a config error on dec_osf: the linker is + $Config{cc}, not $Config{ld}. [Jarkko Hietaniemi] + + - Borland's compiler "response files" will not pass through macro + definitions that contain quotes. The quotes get stripped and there + seems to be no way to escape them. So we leave macros on the + command line. [Randy W. Sims] + +0.18 Sat Mar 25 13:35:47 CST 2006 + + - Yet more fixes for arg_defines() on VMS. [Craig A. Berry and John + E. Malmberg] + +0.17 Wed Mar 15 22:46:15 CST 2006 + + - When we're being run from an uninstalled perl distribution + (e.g. one that's in the process of being built and tested), we + search for perl first in the current working directory. [Randy + Sims] + + - More fixing of the arg_defines() method on VMS. [Craig A. Berry and + John E. Malmberg] + +0.16 Mon Mar 13 17:08:21 CST 2006 + + - Fix quoting of command line arguments on Windows. [Yitzchak + Scott-Thoennes] + + - Provided a custom arg_defines() on VMS that does essentially the + same thing for /define that version 0.14 did for /include. [Craig + A. Berry] + + - Documented the existing 'quiet' parameter, which silences the + printing of system() commands. [Suggested by Yitzchak + Scott-Thoennes] + +0.15 Mon Oct 3 17:10:32 CDT 2005 + + - Several OS/2 fixes have been made, including: 1) adding the + necessary version string to DLLs, 2) passing the executable's name + to 'ldopts' without the .exe extension, 3) avoiding calling 'env' + via the 'shrpenv' thingy, since it triggers a fork() bug. [Ilya + Zakharevich] + + - Integrate a couple cleanup-related changes from bleadperl that + somehow never got into this copy. [Steve Hay] + + - Added a new 'defines' parameter to compile(), which gives a + platform-independant way to specify various -Dfoo=bar (or the + equivalent) compiler defines. [Randy W. Sims] + +0.14 Mon Sep 19 13:40:37 CDT 2005 + + - Several fixes have been made for VMS, including: 1) there can only + be one /include qualifier, so merge multiple /includes into one; 2) + make sure the executable is named the same way that dynaloader will + look for it; 3) make sure the option files for the exported symbols + and the PERLSHR image are passed properly to the linker. [John + E. Malmberg] + +0.13 Wed Aug 24 20:05:59 CDT 2005 + + - Several temporary files weren't being cleaned up during testing, + because the 'cleanup' mechanism was never properly implemented. + This is now fixed. [Steve Hay] + +0.12 Mon May 30 16:40:10 CDT 2005 + + - In order to integrate into the perl core, patches were contributed + that a) put a $VERSION variable in each .pm file, b) add a 'quiet' + parameter to new() to shut up some of the command-echoing, c) + checks for the perl source headers in the CORE/ directory in the + perl source tree, not in the post-installation location, and d) + adjusts the CWD when running the regression tests under the perl + core. [Yitzchak Scott-Thoennes] + + - Various parts of the code were looking for the CORE/ directory in + $Config{archlib}, $Config{installarchlib}, and $Config{archlibexp}. + Only the latter is correct, so we use that everywhere now. + [Curt Tilmes] + + - For Unix-ish platforms, link_executable() will now prefer + $Config{cc} to $Config{ld}, because that typically works + better. [Jarkko Hietaniemi and H.Merijn Brand] + + - Prelinking (invoking ExtUtils::Mksymlists to create options-files) + is now only done when we're building dynamic libraries. [Yitzchak + Scott-Thoennes] + +0.11 Tue Apr 5 20:58:41 CDT 2005 + + - Added a licensing statement to CBuilder.pm. [Spotted by Chip + Salzenberg] + +0.10 Mon Mar 14 20:18:19 CST 2005 + + - Split out a few simple routines that format how compile switches + are formatted, so that we can override them for platforms like VMS + where they're very different. + + - Fix compile() and link() on VMS. [Help from Michael Schwern and + Peter Prymmer] + +0.09 Tue Feb 8 17:57:41 CST 2005 + + - Fixed a broken link_executable() method on cygwin - it now uses + 'gcc' instead of $Config{ld} for the linking, because the latter is + actually a shell script which calls a perl script which calls gcc + in a way that only works for creating shared libraries, not + executables. + +0.08 Tue Jan 18 21:54:11 CST 2005 + + - Fixed a testing error in which I had the prototype wrong for the + main() function. [Jose Pedro Oliveira] + +0.07 Wed Jan 12 21:50:34 CST 2005 + + - Added the link_executable() method, which provides the ability to + create standalone executables. This is NOT yet implemented on + Windows, and therefore the tests for it are skipped on Win32. + [Alberto Manuel Brandao Simoes] + + - Integrated the latest split_like_shell() for Windows from + Module::Build (really need to find a better home for this code...), + which now does a much better job of handling quotes and backslashes + and so on. [Randy Sims] + + - Fixed a couple of Windows problems related to the output-file name + in link(), and some clobbering of the 'include_dirs' parameter to + compile(). [Randy Sims] + +0.06 Mon Dec 27 22:51:36 CST 2004 + + - Fixed a bug on Unix environments in which our work-around for + shell-commands like "FOO=BAR cc" (which is supposed to be turned + into "env FOO=BAR cc" to actually work) wasn't being called. + +0.05 Wed Oct 13 23:09:09 CDT 2004 + + - Fixed a bug in split_like_shell() in which leading whitespace was + creating an empty word, manifesting as something like "gcc - no + such file or directory" during tests. [Spotted by Warren L. Dodge] + + - Incorporate another split_like_shell() fix from Module::Build. + +0.04 Sun Oct 10 00:31:08 CDT 2004 + + - Changed the split_like_shell() method to use the shellwords() + function from Text::ParseWords (a core module since 5.0), which + does a much better job than the split() we were using. + + +0.03 Fri May 14 23:12:23 CDT 2004 + + - Fixed minor problems with the Build.PL file, the module names + should be quoted. + + - The VMS module declared itself with the wrong package name. + + +0.02 Fri Feb 20 10:17:40 CST 2004 + + - Fixed a bug in .../Platform/Windows.pm, in which compile() was + ignoring an 'include_dirs' argument. [Randy Sims] + + - Fixed a bug in .../Platform/Windows.pm, in which output files were + being created in the root directory \ when they should be created + in the current directory. [Randy Sims] + + +0.01 Mon Jan 12 08:12:35 CST 2004 + + - Original release, taken from Module::Build's C-building code, with + patching help from Randy Sims. diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/Unix.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/Unix.pm new file mode 100644 index 00000000000..3fa73788c0c --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/Unix.pm @@ -0,0 +1,37 @@ +package ExtUtils::CBuilder::Platform::Unix; + +use strict; +use ExtUtils::CBuilder::Base; + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +@ISA = qw(ExtUtils::CBuilder::Base); + +sub link_executable { + my $self = shift; + # $Config{cc} is usually a better bet for linking executables than $Config{ld} + local $self->{config}{ld} = + $self->{config}{cc} . " " . $self->{config}{ldflags}; + return $self->SUPER::link_executable(@_); +} + +sub link { + my $self = shift; + my $cf = $self->{config}; + + # Some platforms (notably Mac OS X 10.3, but some others too) expect + # the syntax "FOO=BAR /bin/command arg arg" to work in %Config + # (notably $Config{ld}). It usually works in system(SCALAR), but we + # use system(LIST). We fix it up here with 'env'. + + local $cf->{ld} = $cf->{ld}; + if (ref $cf->{ld}) { + unshift @{$cf->{ld}}, 'env' if $cf->{ld}[0] =~ /^\s*\w+=/; + } else { + $cf->{ld} =~ s/^(\s*\w+=)/env $1/; + } + + return $self->SUPER::link(@_); +} + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/VMS.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/VMS.pm new file mode 100644 index 00000000000..ab22cb23acc --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/VMS.pm @@ -0,0 +1,294 @@ +package ExtUtils::CBuilder::Platform::VMS; + +use strict; +use ExtUtils::CBuilder::Base; + +use vars qw($VERSION @ISA); +$VERSION = '0.22'; +@ISA = qw(ExtUtils::CBuilder::Base); + +use File::Spec::Functions qw(catfile catdir); + +# We do prelink, but don't want the parent to redo it. + +sub need_prelink { 0 } + +sub arg_defines { + my ($self, %args) = @_; + + s/"/""/g foreach values %args; + + my @config_defines; + + # VMS can only have one define qualifier; add the one from config, if any. + if ($self->{config}{ccflags} =~ s{/ def[^=]+ =+ \(? ([^\/\)]*) } {}ix) { + push @config_defines, $1; + } + + return '' unless keys(%args) || @config_defines; + + return ('/define=(' + . join(',', + @config_defines, + map "\"$_" . ( length($args{$_}) ? "=$args{$_}" : '') . "\"", + keys %args) + . ')'); +} + +sub arg_include_dirs { + my ($self, @dirs) = @_; + + # VMS can only have one include list, add the one from config. + if ($self->{config}{ccflags} =~ s{/inc[^=]+(?:=)+(?:\()?([^\/\)]*)} {}i) { + unshift @dirs, $1; + } + return unless @dirs; + + return ('/include=(' . join(',', @dirs) . ')'); +} + +sub _do_link { + my ($self, $type, %args) = @_; + + my $objects = delete $args{objects}; + $objects = [$objects] unless ref $objects; + + if ($args{lddl}) { + + # prelink will call Mksymlists, which creates the extension-specific + # linker options file and populates it with the boot symbol. + + my @temp_files = $self->prelink(%args, dl_name => $args{module_name}); + + # We now add the rest of what we need to the linker options file. We + # should replicate the functionality of C<ExtUtils::MM_VMS::dlsyms>, + # but there is as yet no infrastructure for handling object libraries, + # so for now we depend on object files being listed individually on the + # command line, which should work for simple cases. We do bring in our + # own version of C<ExtUtils::Liblist::Kid::ext> so that any additional + # libraries (including PERLSHR) can be added to the options file. + + my @optlibs = $self->_liblist_ext( $args{'libs'} ); + + my $optfile = 'sys$disk:[]' . $temp_files[0]; + open my $opt_fh, '>>', $optfile + or die "_do_link: Unable to open $optfile: $!"; + for my $lib (@optlibs) {print $opt_fh "$lib\n" if length $lib } + close $opt_fh; + + $objects->[-1] .= ','; + push @$objects, $optfile . '/OPTIONS,'; + + # This one not needed for DEC C, but leave for completeness. + push @$objects, $self->perl_inc() . 'perlshr_attr.opt/OPTIONS'; + } + + return $self->SUPER::_do_link($type, %args, objects => $objects); +} + +sub arg_nolink { return; } + +sub arg_object_file { + my ($self, $file) = @_; + return "/obj=$file"; +} + +sub arg_exec_file { + my ($self, $file) = @_; + return ("/exe=$file"); +} + +sub arg_share_object_file { + my ($self, $file) = @_; + return ("$self->{config}{lddlflags}=$file"); +} + + +sub lib_file { + my ($self, $dl_file) = @_; + $dl_file =~ s/\.[^.]+$//; + $dl_file =~ tr/"//d; + $dl_file = $dl_file .= '.' . $self->{config}{dlext}; + + # Need to create with the same name as DynaLoader will load with. + if (defined &DynaLoader::mod2fname) { + my ($dev,$dir,$file) = File::Spec->splitpath($dl_file); + $file = DynaLoader::mod2fname([$file]); + $dl_file = File::Spec->catpath($dev,$dir,$file); + } + return $dl_file; +} + +# The following is reproduced almost verbatim from ExtUtils::Liblist::Kid::_vms_ext. +# We can't just call that because it's tied up with the MakeMaker object hierarchy. + +sub _liblist_ext { + my($self, $potential_libs,$verbose,$give_libs) = @_; + $verbose ||= 0; + + my(@crtls,$crtlstr); + @crtls = ( ($self->{'config'}{'ldflags'} =~ m-/Debug-i ? $self->{'config'}{'dbgprefix'} : '') + . 'PerlShr/Share' ); + push(@crtls, grep { not /\(/ } split /\s+/, $self->{'config'}{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $self->{'config'}{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and + # a library spec could be resolved via a logical name, we go to some trouble + # to insure that the copy in the local tree is used, rather than one to + # which a system-wide logical may point. + if ($self->perl_src) { + my($lib,$locspec,$type); + foreach $lib (@crtls) { + if (($locspec,$type) = $lib =~ m{^([\w\$-]+)(/\w+)?} and $locspec =~ /perl/i) { + if (lc $type eq '/share') { $locspec .= $self->{'config'}{'exe_ext'}; } + elsif (lc $type eq '/library') { $locspec .= $self->{'config'}{'lib_ext'}; } + else { $locspec .= $self->{'config'}{'obj_ext'}; } + $locspec = catfile($self->perl_src, $locspec); + $lib = "$locspec$type" if -e $locspec; + } + } + } + $crtlstr = @crtls ? join(' ',@crtls) : ''; + + unless ($potential_libs) { + warn "Result:\n\tEXTRALIBS: \n\tLDLOADLIBS: $crtlstr\n" if $verbose; + return ('', '', $crtlstr, '', ($give_libs ? [] : ())); + } + + my(@dirs,@libs,$dir,$lib,%found,@fndlibs,$ldlib); + my $cwd = cwd(); + my($so,$lib_ext,$obj_ext) = @{$self->{'config'}}{'so','lib_ext','obj_ext'}; + # List of common Unix library names and their VMS equivalents + # (VMS equivalent of '' indicates that the library is automatically + # searched by the linker, and should be skipped here.) + my(@flibs, %libs_seen); + my %libmap = ( 'm' => '', 'f77' => '', 'F77' => '', 'V77' => '', 'c' => '', + 'malloc' => '', 'crypt' => '', 'resolv' => '', 'c_s' => '', + 'socket' => '', 'X11' => 'DECW$XLIBSHR', + 'Xt' => 'DECW$XTSHR', 'Xm' => 'DECW$XMLIBSHR', + 'Xmu' => 'DECW$XMULIBSHR'); + if ($self->{'config'}{'vms_cc_type'} ne 'decc') { $libmap{'curses'} = 'VAXCCURSE'; } + + warn "Potential libraries are '$potential_libs'\n" if $verbose; + + # First, sort out directories and library names in the input + foreach $lib (split ' ',$potential_libs) { + push(@dirs,$1), next if $lib =~ /^-L(.*)/; + push(@dirs,$lib), next if $lib =~ /[:>\]]$/; + push(@dirs,$lib), next if -d $lib; + push(@libs,$1), next if $lib =~ /^-l(.*)/; + push(@libs,$lib); + } + push(@dirs,split(' ',$self->{'config'}{'libpth'})); + + # Now make sure we've got VMS-syntax absolute directory specs + # (We don't, however, check whether someone's hidden a relative + # path in a logical name.) + foreach $dir (@dirs) { + unless (-d $dir) { + warn "Skipping nonexistent Directory $dir\n" if $verbose > 1; + $dir = ''; + next; + } + warn "Resolving directory $dir\n" if $verbose; + if (!File::Spec->file_name_is_absolute($dir)) { + $dir = catdir($cwd,$dir); + } + } + @dirs = grep { length($_) } @dirs; + unshift(@dirs,''); # Check each $lib without additions first + + LIB: foreach $lib (@libs) { + if (exists $libmap{$lib}) { + next unless length $libmap{$lib}; + $lib = $libmap{$lib}; + } + + my(@variants,$variant,$cand); + my($ctype) = ''; + + # If we don't have a file type, consider it a possibly abbreviated name and + # check for common variants. We try these first to grab libraries before + # a like-named executable image (e.g. -lperl resolves to perlshr.exe + # before perl.exe). + if ($lib !~ /\.[^:>\]]*$/) { + push(@variants,"${lib}shr","${lib}rtl","${lib}lib"); + push(@variants,"lib$lib") if $lib !~ /[:>\]]/; + } + push(@variants,$lib); + warn "Looking for $lib\n" if $verbose; + foreach $variant (@variants) { + my($fullname, $name); + + foreach $dir (@dirs) { + my($type); + + $name = "$dir$variant"; + warn "\tChecking $name\n" if $verbose > 2; + $fullname = VMS::Filespec::rmsexpand($name); + if (defined $fullname and -f $fullname) { + # It's got its own suffix, so we'll have to figure out the type + if ($fullname =~ /(?:$so|exe)$/i) { $type = 'SHR'; } + elsif ($fullname =~ /(?:$lib_ext|olb)$/i) { $type = 'OLB'; } + elsif ($fullname =~ /(?:$obj_ext|obj)$/i) { + warn "Note (probably harmless): " + ."Plain object file $fullname found in library list\n"; + $type = 'OBJ'; + } + else { + warn "Note (probably harmless): " + ."Unknown library type for $fullname; assuming shared\n"; + $type = 'SHR'; + } + } + elsif (-f ($fullname = VMS::Filespec::rmsexpand($name,$so)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.exe'))) { + $type = 'SHR'; + $name = $fullname unless $fullname =~ /exe;?\d*$/i; + } + elsif (not length($ctype) and # If we've got a lib already, + # don't bother + ( -f ($fullname = VMS::Filespec::rmsexpand($name,$lib_ext)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.olb')))) { + $type = 'OLB'; + $name = $fullname unless $fullname =~ /olb;?\d*$/i; + } + elsif (not length($ctype) and # If we've got a lib already, + # don't bother + ( -f ($fullname = VMS::Filespec::rmsexpand($name,$obj_ext)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.obj')))) { + warn "Note (probably harmless): " + ."Plain object file $fullname found in library list\n"; + $type = 'OBJ'; + $name = $fullname unless $fullname =~ /obj;?\d*$/i; + } + if (defined $type) { + $ctype = $type; $cand = $name; + last if $ctype eq 'SHR'; + } + } + if ($ctype) { + # This has to precede any other CRTLs, so just make it first + if ($cand eq 'VAXCCURSE') { unshift @{$found{$ctype}}, $cand; } + else { push @{$found{$ctype}}, $cand; } + warn "\tFound as $cand (really $fullname), type $ctype\n" + if $verbose > 1; + push @flibs, $name unless $libs_seen{$fullname}++; + next LIB; + } + } + warn "Note (probably harmless): " + ."No library found for $lib\n"; + } + + push @fndlibs, @{$found{OBJ}} if exists $found{OBJ}; + push @fndlibs, map { "$_/Library" } @{$found{OLB}} if exists $found{OLB}; + push @fndlibs, map { "$_/Share" } @{$found{SHR}} if exists $found{SHR}; + $lib = join(' ',@fndlibs); + + $ldlib = $crtlstr ? "$lib $crtlstr" : $lib; + warn "Result:\n\tEXTRALIBS: $lib\n\tLDLOADLIBS: $ldlib\n" if $verbose; + wantarray ? ($lib, '', $ldlib, '', ($give_libs ? \@flibs : ())) : $lib; +} + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/Windows.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/Windows.pm new file mode 100644 index 00000000000..7b74ae0d99a --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/Windows.pm @@ -0,0 +1,732 @@ +package ExtUtils::CBuilder::Platform::Windows; + +use strict; +use warnings; + +use File::Basename; +use File::Spec; + +use ExtUtils::CBuilder::Base; + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +@ISA = qw(ExtUtils::CBuilder::Base); + +sub new { + my $class = shift; + my $self = $class->SUPER::new(@_); + my $cf = $self->{config}; + + # Inherit from an appropriate compiler driver class + unshift @ISA, "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type; + + return $self; +} + +sub _compiler_type { + my $self = shift; + my $cc = $self->{config}{cc}; + + return ( $cc =~ /cl(\.exe)?$/ ? 'MSVC' + : $cc =~ /bcc32(\.exe)?$/ ? 'BCC' + : 'GCC'); +} + +sub split_like_shell { + # As it turns out, Windows command-parsing is very different from + # Unix command-parsing. Double-quotes mean different things, + # backslashes don't necessarily mean escapes, and so on. So we + # can't use Text::ParseWords::shellwords() to break a command string + # into words. The algorithm below was bashed out by Randy and Ken + # (mostly Randy), and there are a lot of regression tests, so we + # should feel free to adjust if desired. + + (my $self, local $_) = @_; + + return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY'); + + my @argv; + return @argv unless defined() && length(); + + my $arg = ''; + my( $i, $quote_mode ) = ( 0, 0 ); + + while ( $i < length() ) { + + my $ch = substr( $_, $i , 1 ); + my $next_ch = substr( $_, $i+1, 1 ); + + if ( $ch eq '\\' && $next_ch eq '"' ) { + $arg .= '"'; + $i++; + } elsif ( $ch eq '\\' && $next_ch eq '\\' ) { + $arg .= '\\'; + $i++; + } elsif ( $ch eq '"' && $next_ch eq '"' && $quote_mode ) { + $quote_mode = !$quote_mode; + $arg .= '"'; + $i++; + } elsif ( $ch eq '"' && $next_ch eq '"' && !$quote_mode && + ( $i + 2 == length() || + substr( $_, $i + 2, 1 ) eq ' ' ) + ) { # for cases like: a"" => [ 'a' ] + push( @argv, $arg ); + $arg = ''; + $i += 2; + } elsif ( $ch eq '"' ) { + $quote_mode = !$quote_mode; + } elsif ( $ch eq ' ' && !$quote_mode ) { + push( @argv, $arg ) if $arg; + $arg = ''; + ++$i while substr( $_, $i + 1, 1 ) eq ' '; + } else { + $arg .= $ch; + } + + $i++; + } + + push( @argv, $arg ) if defined( $arg ) && length( $arg ); + return @argv; +} + +sub arg_defines { + my ($self, %args) = @_; + s/"/\\"/g foreach values %args; + return map qq{"-D$_=$args{$_}"}, keys %args; +} + +sub compile { + my ($self, %args) = @_; + my $cf = $self->{config}; + + die "Missing 'source' argument to compile()" unless defined $args{source}; + + my ($basename, $srcdir) = + ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1]; + + $srcdir ||= File::Spec->curdir(); + + my @defines = $self->arg_defines( %{ $args{defines} || {} } ); + + my %spec = ( + srcdir => $srcdir, + builddir => $srcdir, + basename => $basename, + source => $args{source}, + output => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext}, + cc => $cf->{cc}, + cflags => [ + $self->split_like_shell($cf->{ccflags}), + $self->split_like_shell($cf->{cccdlflags}), + $self->split_like_shell($cf->{extra_compiler_flags}), + ], + optimize => [ $self->split_like_shell($cf->{optimize}) ], + defines => \@defines, + includes => [ @{$args{include_dirs} || []} ], + perlinc => [ + $self->perl_inc(), + $self->split_like_shell($cf->{incpath}), + ], + use_scripts => 1, # XXX provide user option to change this??? + ); + + $self->normalize_filespecs( + \$spec{source}, + \$spec{output}, + $spec{includes}, + $spec{perlinc}, + ); + + my @cmds = $self->format_compiler_cmd(%spec); + while ( my $cmd = shift @cmds ) { + $self->do_system( @$cmd ) + or die "error building $cf->{dlext} file from '$args{source}'"; + } + + (my $out = $spec{output}) =~ tr/'"//d; + return $out; +} + +sub need_prelink { 1 } + +sub link { + my ($self, %args) = @_; + my $cf = $self->{config}; + + my @objects = ( ref $args{objects} eq 'ARRAY' ? @{$args{objects}} : $args{objects} ); + my $to = join '', (File::Spec->splitpath($objects[0]))[0,1]; + $to ||= File::Spec->curdir(); + + (my $file_base = $args{module_name}) =~ s/.*:://; + my $output = $args{lib_file} || + File::Spec->catfile($to, "$file_base.$cf->{dlext}"); + + # if running in perl source tree, look for libs there, not installed + my $lddlflags = $cf->{lddlflags}; + my $perl_src = $self->perl_src(); + $lddlflags =~ s/\Q$cf->{archlibexp}\E[\\\/]CORE/$perl_src/ if $perl_src; + + my %spec = ( + srcdir => $to, + builddir => $to, + startup => [ ], + objects => \@objects, + libs => [ ], + output => $output, + ld => $cf->{ld}, + libperl => $cf->{libperl}, + perllibs => [ $self->split_like_shell($cf->{perllibs}) ], + libpath => [ $self->split_like_shell($cf->{libpth}) ], + lddlflags => [ $self->split_like_shell($lddlflags) ], + other_ldflags => [ $self->split_like_shell($args{extra_linker_flags} || '') ], + use_scripts => 1, # XXX provide user option to change this??? + ); + + unless ( $spec{basename} ) { + ($spec{basename} = $args{module_name}) =~ s/.*:://; + } + + $spec{srcdir} = File::Spec->canonpath( $spec{srcdir} ); + $spec{builddir} = File::Spec->canonpath( $spec{builddir} ); + + $spec{output} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.'.$cf->{dlext} ); + $spec{manifest} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.'.$cf->{dlext}.'.manifest'); + $spec{implib} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . $cf->{lib_ext} ); + $spec{explib} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.exp' ); + if ($cf->{cc} eq 'cl') { + $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.pdb' ); + } + elsif ($cf->{cc} eq 'bcc32') { + $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.tds' ); + } + $spec{def_file} ||= File::Spec->catfile( $spec{srcdir} , + $spec{basename} . '.def' ); + $spec{base_file} ||= File::Spec->catfile( $spec{srcdir} , + $spec{basename} . '.base' ); + + $self->add_to_cleanup( + grep defined, + @{[ @spec{qw(manifest implib explib dbg_file def_file base_file map_file)} ]} + ); + + foreach my $opt ( qw(output manifest implib explib dbg_file def_file map_file base_file) ) { + $self->normalize_filespecs( \$spec{$opt} ); + } + + foreach my $opt ( qw(libpath startup objects) ) { + $self->normalize_filespecs( $spec{$opt} ); + } + + (my $def_base = $spec{def_file}) =~ tr/'"//d; + $def_base =~ s/\.def$//; + $self->prelink( dl_name => $args{module_name}, + dl_file => $def_base, + dl_base => $spec{basename} ); + + my @cmds = $self->format_linker_cmd(%spec); + while ( my $cmd = shift @cmds ) { + $self->do_system( @$cmd ); + } + + $spec{output} =~ tr/'"//d; + return wantarray + ? grep defined, @spec{qw[output manifest implib explib dbg_file def_file map_file base_file]} + : $spec{output}; +} + +# canonize & quote paths +sub normalize_filespecs { + my ($self, @specs) = @_; + foreach my $spec ( grep defined, @specs ) { + if ( ref $spec eq 'ARRAY') { + $self->normalize_filespecs( map {\$_} grep defined, @$spec ) + } elsif ( ref $spec eq 'SCALAR' ) { + $$spec =~ tr/"//d if $$spec; + next unless $$spec; + $$spec = '"' . File::Spec->canonpath($$spec) . '"'; + } elsif ( ref $spec eq '' ) { + $spec = '"' . File::Spec->canonpath($spec) . '"'; + } else { + die "Don't know how to normalize " . (ref $spec || $spec) . "\n"; + } + } +} + +# directory of perl's include files +sub perl_inc { + my $self = shift; + + my $perl_src = $self->perl_src(); + + if ($perl_src) { + File::Spec->catdir($perl_src, "lib", "CORE"); + } else { + File::Spec->catdir($self->{config}{archlibexp},"CORE"); + } +} + +1; + +######################################################################## + +=begin comment + +The packages below implement functions for generating properly +formatted commandlines for the compiler being used. Each package +defines two primary functions 'format_linker_cmd()' & +'format_compiler_cmd()' that accepts a list of named arguments (a +hash) and returns a list of formatted options suitable for invoking the +compiler. By default, if the compiler supports scripting of its +operation then a script file is built containing the options while +those options are removed from the commandline, and a reference to the +script is pushed onto the commandline in their place. Scripting the +compiler in this way helps to avoid the problems associated with long +commandlines under some shells. + +=end comment + +=cut + +######################################################################## +package ExtUtils::CBuilder::Platform::Windows::MSVC; + +sub format_compiler_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{ $spec{includes} || [] }, + @{ $spec{perlinc} || [] } ) { + $path = '-I' . $path; + } + + %spec = $self->write_compiler_script(%spec) + if $spec{use_scripts}; + + return [ grep {defined && length} ( + $spec{cc},'-nologo','-c', + @{$spec{includes}} , + @{$spec{cflags}} , + @{$spec{optimize}} , + @{$spec{defines}} , + @{$spec{perlinc}} , + "-Fo$spec{output}" , + $spec{source} , + ) ]; +} + +sub write_compiler_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.ccs' ); + + $self->add_to_cleanup($script); + print "Generating script '$script'\n" if !$self->{quiet}; + + open( SCRIPT, ">$script" ) + or die( "Could not create script '$script': $!" ); + + print SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(includes cflags optimize defines perlinc) } ) + ); + + close SCRIPT; + + push @{$spec{includes}}, '@"' . $script . '"'; + + return %spec; +} + +sub format_linker_cmd { + my ($self, %spec) = @_; + my $cf = $self->{config}; + + foreach my $path ( @{$spec{libpath}} ) { + $path = "-libpath:$path"; + } + + my $output = $spec{output}; + + $spec{def_file} &&= '-def:' . $spec{def_file}; + $spec{output} &&= '-out:' . $spec{output}; + $spec{manifest} &&= '-manifest ' . $spec{manifest}; + $spec{implib} &&= '-implib:' . $spec{implib}; + $spec{map_file} &&= '-map:' . $spec{map_file}; + + %spec = $self->write_linker_script(%spec) + if $spec{use_scripts}; + + my @cmds; # Stores the series of commands needed to build the module. + + push @cmds, [ grep {defined && length} ( + $spec{ld} , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{other_ldflags}} , + @{$spec{startup}} , + @{$spec{objects}} , + $spec{map_file} , + $spec{libperl} , + @{$spec{perllibs}} , + $spec{def_file} , + $spec{implib} , + $spec{output} , + ) ]; + + # Embed the manifest file for VC 2005 (aka VC 8) or higher, but not for the 64-bit Platform SDK compiler + if ($cf->{ivsize} == 4 && $cf->{cc} eq 'cl' and $cf->{ccversion} =~ /^(\d+)/ and $1 >= 14) { + push @cmds, [ + 'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2" + ]; + } + + return @cmds; +} + +sub write_linker_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lds' ); + + $self->add_to_cleanup($script); + + print "Generating script '$script'\n" if !$self->{quiet}; + + open( SCRIPT, ">$script" ) + or die( "Could not create script '$script': $!" ); + + print SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(lddlflags libpath other_ldflags + startup objects libperl perllibs + def_file implib map_file) } ) + ); + + close SCRIPT; + + push @{$spec{lddlflags}}, '@"' . $script . '"'; + + return %spec; +} + +1; + +######################################################################## +package ExtUtils::CBuilder::Platform::Windows::BCC; + +sub format_compiler_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{ $spec{includes} || [] }, + @{ $spec{perlinc} || [] } ) { + $path = '-I' . $path; + } + + %spec = $self->write_compiler_script(%spec) + if $spec{use_scripts}; + + return [ grep {defined && length} ( + $spec{cc}, '-c' , + @{$spec{includes}} , + @{$spec{cflags}} , + @{$spec{optimize}} , + @{$spec{defines}} , + @{$spec{perlinc}} , + "-o$spec{output}" , + $spec{source} , + ) ]; +} + +sub write_compiler_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.ccs' ); + + $self->add_to_cleanup($script); + + print "Generating script '$script'\n" if !$self->{quiet}; + + open( SCRIPT, ">$script" ) + or die( "Could not create script '$script': $!" ); + + # XXX Borland "response files" seem to be unable to accept macro + # definitions containing quoted strings. Escaping strings with + # backslash doesn't work, and any level of quotes are stripped. The + # result is is a floating point number in the source file where a + # string is expected. So we leave the macros on the command line. + print SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(includes cflags optimize perlinc) } ) + ); + + close SCRIPT; + + push @{$spec{includes}}, '@"' . $script . '"'; + + return %spec; +} + +sub format_linker_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{$spec{libpath}} ) { + $path = "-L$path"; + } + + push( @{$spec{startup}}, 'c0d32.obj' ) + unless ( $spec{starup} && @{$spec{startup}} ); + + %spec = $self->write_linker_script(%spec) + if $spec{use_scripts}; + + return [ grep {defined && length} ( + $spec{ld} , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{other_ldflags}} , + @{$spec{startup}} , + @{$spec{objects}} , ',', + $spec{output} , ',', + $spec{map_file} , ',', + $spec{libperl} , + @{$spec{perllibs}} , ',', + $spec{def_file} + ) ]; +} + +sub write_linker_script { + my ($self, %spec) = @_; + + # To work around Borlands "unique" commandline syntax, + # two scripts are used: + + my $ld_script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lds' ); + my $ld_libs = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lbs' ); + + $self->add_to_cleanup($ld_script, $ld_libs); + + print "Generating scripts '$ld_script' and '$ld_libs'.\n" if !$self->{quiet}; + + # Script 1: contains options & names of object files. + open( LD_SCRIPT, ">$ld_script" ) + or die( "Could not create linker script '$ld_script': $!" ); + + print LD_SCRIPT join( " +\n", + map { @{$_} } + grep defined, + delete( + @spec{ qw(lddlflags libpath other_ldflags startup objects) } ) + ); + + close LD_SCRIPT; + + # Script 2: contains name of libs to link against. + open( LD_LIBS, ">$ld_libs" ) + or die( "Could not create linker script '$ld_libs': $!" ); + + print LD_LIBS join( " +\n", + (delete $spec{libperl} || ''), + @{delete $spec{perllibs} || []}, + ); + + close LD_LIBS; + + push @{$spec{lddlflags}}, '@"' . $ld_script . '"'; + push @{$spec{perllibs}}, '@"' . $ld_libs . '"'; + + return %spec; +} + +1; + +######################################################################## +package ExtUtils::CBuilder::Platform::Windows::GCC; + +sub format_compiler_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{ $spec{includes} || [] }, + @{ $spec{perlinc} || [] } ) { + $path = '-I' . $path; + } + + # split off any -arguments included in cc + my @cc = split / (?=-)/, $spec{cc}; + + return [ grep {defined && length} ( + @cc, '-c' , + @{$spec{includes}} , + @{$spec{cflags}} , + @{$spec{optimize}} , + @{$spec{defines}} , + @{$spec{perlinc}} , + '-o', $spec{output} , + $spec{source} , + ) ]; +} + +sub format_linker_cmd { + my ($self, %spec) = @_; + + # The Config.pm variable 'libperl' is hardcoded to the full name + # of the perl import library (i.e. 'libperl56.a'). GCC will not + # find it unless the 'lib' prefix & the extension are stripped. + $spec{libperl} =~ s/^(?:lib)?([^.]+).*$/-l$1/; + + unshift( @{$spec{other_ldflags}}, '-nostartfiles' ) + if ( $spec{startup} && @{$spec{startup}} ); + + # From ExtUtils::MM_Win32: + # + ## one thing for GCC/Mingw32: + ## we try to overcome non-relocateable-DLL problems by generating + ## a (hopefully unique) image-base from the dll's name + ## -- BKS, 10-19-1999 + File::Basename::basename( $spec{output} ) =~ /(....)(.{0,4})/; + $spec{image_base} = sprintf( "0x%x0000", unpack('n', $1 ^ $2) ); + + %spec = $self->write_linker_script(%spec) + if $spec{use_scripts}; + + foreach my $path ( @{$spec{libpath}} ) { + $path = "-L$path"; + } + + my @cmds; # Stores the series of commands needed to build the module. + + push @cmds, [ + 'dlltool', '--def' , $spec{def_file}, + '--output-exp' , $spec{explib} + ]; + + # split off any -arguments included in ld + my @ld = split / (?=-)/, $spec{ld}; + + push @cmds, [ grep {defined && length} ( + @ld , + '-o', $spec{output} , + "-Wl,--base-file,$spec{base_file}" , + "-Wl,--image-base,$spec{image_base}" , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{startup}} , + @{$spec{objects}} , + @{$spec{other_ldflags}} , + $spec{libperl} , + @{$spec{perllibs}} , + $spec{explib} , + $spec{map_file} ? ('-Map', $spec{map_file}) : '' + ) ]; + + push @cmds, [ + 'dlltool', '--def' , $spec{def_file}, + '--output-exp' , $spec{explib}, + '--base-file' , $spec{base_file} + ]; + + push @cmds, [ grep {defined && length} ( + @ld , + '-o', $spec{output} , + "-Wl,--image-base,$spec{image_base}" , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{startup}} , + @{$spec{objects}} , + @{$spec{other_ldflags}} , + $spec{libperl} , + @{$spec{perllibs}} , + $spec{explib} , + $spec{map_file} ? ('-Map', $spec{map_file}) : '' + ) ]; + + return @cmds; +} + +sub write_linker_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lds' ); + + $self->add_to_cleanup($script); + + print "Generating script '$script'\n" if !$self->{quiet}; + + open( SCRIPT, ">$script" ) + or die( "Could not create script '$script': $!" ); + + print( SCRIPT 'SEARCH_DIR(' . $_ . ")\n" ) + for @{delete $spec{libpath} || []}; + + # gcc takes only one startup file, so the first object in startup is + # specified as the startup file and any others are shifted into the + # beginning of the list of objects. + if ( $spec{startup} && @{$spec{startup}} ) { + print SCRIPT 'STARTUP(' . shift( @{$spec{startup}} ) . ")\n"; + unshift @{$spec{objects}}, + @{delete $spec{startup} || []}; + } + + print SCRIPT 'INPUT(' . join( ',', + @{delete $spec{objects} || []} + ) . ")\n"; + + print SCRIPT 'INPUT(' . join( ' ', + (delete $spec{libperl} || ''), + @{delete $spec{perllibs} || []}, + ) . ")\n"; + + close SCRIPT; + + push @{$spec{other_ldflags}}, '"' . $script . '"'; + + return %spec; +} + +1; + +__END__ + +=head1 NAME + +ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms + +=head1 DESCRIPTION + +This module implements the Windows-specific parts of ExtUtils::CBuilder. +Most of the Windows-specific stuff has to do with compiling and +linking C code. Currently we support the 3 compilers perl itself +supports: MSVC, BCC, and GCC. + +This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality +not implemented here will be implemented there. The interfaces are +defined by the L<ExtUtils::CBuilder> documentation. + +=head1 AUTHOR + +Ken Williams <ken@mathforum.org> + +Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>. + +=head1 SEE ALSO + +perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3) + +=cut diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/aix.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/aix.pm new file mode 100644 index 00000000000..6ad2a6842f0 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/aix.pm @@ -0,0 +1,31 @@ +package ExtUtils::CBuilder::Platform::aix; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; +use File::Spec; + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub need_prelink { 1 } + +sub link { + my ($self, %args) = @_; + my $cf = $self->{config}; + + (my $baseext = $args{module_name}) =~ s/.*:://; + my $perl_inc = $self->perl_inc(); + + # Massage some very naughty bits in %Config + local $cf->{lddlflags} = $cf->{lddlflags}; + for ($cf->{lddlflags}) { + s/\Q$(BASEEXT)\E/$baseext/; + s/\Q$(PERL_INC)\E/$perl_inc/; + } + + return $self->SUPER::link(%args); +} + + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/cygwin.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/cygwin.pm new file mode 100644 index 00000000000..623fe0a30c2 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/cygwin.pm @@ -0,0 +1,30 @@ +package ExtUtils::CBuilder::Platform::cygwin; + +use strict; +use File::Spec; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub link_executable { + my $self = shift; + # $Config{ld} is set up as a special script for building + # perl-linkable libraries. We don't want that here. + local $self->{config}{ld} = 'gcc'; + return $self->SUPER::link_executable(@_); +} + +sub link { + my ($self, %args) = @_; + + $args{extra_linker_flags} = [ + File::Spec->catdir($self->perl_inc(), 'libperl.dll.a'), + $self->split_like_shell($args{extra_linker_flags}) + ]; + + return $self->SUPER::link(%args); +} + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/darwin.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/darwin.pm new file mode 100644 index 00000000000..3b0cfb4c596 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/darwin.pm @@ -0,0 +1,22 @@ +package ExtUtils::CBuilder::Platform::darwin; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub compile { + my $self = shift; + my $cf = $self->{config}; + + # -flat_namespace isn't a compile flag, it's a linker flag. But + # it's mistakenly in Config.pm as both. Make the correction here. + local $cf->{ccflags} = $cf->{ccflags}; + $cf->{ccflags} =~ s/-flat_namespace//; + $self->SUPER::compile(@_); +} + + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/dec_osf.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/dec_osf.pm new file mode 100644 index 00000000000..cb7a9e3da5d --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/dec_osf.pm @@ -0,0 +1,18 @@ +package ExtUtils::CBuilder::Platform::dec_osf; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; +use File::Spec; + +use vars qw($VERSION @ISA); +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); +$VERSION = '0.21'; + +sub link_executable { + my $self = shift; + # $Config{ld} is 'ld' but that won't work: use the cc instead. + local $self->{config}{ld} = $self->{config}{cc}; + return $self->SUPER::link_executable(@_); +} + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/os2.pm b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/os2.pm new file mode 100644 index 00000000000..4657c593ab2 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/Platform/os2.pm @@ -0,0 +1,80 @@ +package ExtUtils::CBuilder::Platform::os2; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.21'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub need_prelink { 1 } + +sub prelink { + # Generate import libraries (XXXX currently near .DEF; should be near DLL!) + my $self = shift; + my %args = @_; + + my @res = $self->SUPER::prelink(%args); + die "Unexpected number of DEF files" unless @res == 1; + die "Can't find DEF file in the output" + unless $res[0] =~ m,^(.*)\.def$,si; + my $libname = "$1$self->{config}{lib_ext}"; # Put .LIB file near .DEF file + $self->do_system('emximp', '-o', $libname, $res[0]) or die "emxexp: res=$?"; + return (@res, $libname); +} + +sub _do_link { + my $self = shift; + my ($how, %args) = @_; + if ($how eq 'lib_file' + and (defined $args{module_name} and length $args{module_name})) { + + # DynaLoader::mod2fname() is a builtin func + my $lib = DynaLoader::mod2fname([split /::/, $args{module_name}]); + + # Now know the basename, find directory parts via lib_file, or objects + my $objs = ( (ref $args{objects}) ? $args{objects} : [$args{objects}] ); + my $near_obj = $self->lib_file(@$objs); + my $ref_file = ( defined $args{lib_file} ? $args{lib_file} : $near_obj ); + my $lib_dir = ($ref_file =~ m,(.*)[/\\],s ? "$1/" : '' ); + my $exp_dir = ($near_obj =~ m,(.*)[/\\],s ? "$1/" : '' ); + + $args{dl_file} = $1 if $near_obj =~ m,(.*)\.,s; # put ExportList near OBJ + $args{lib_file} = "$lib_dir$lib.$self->{config}{dlext}"; # DLL file + + # XXX _do_link does not have place to put libraries? + push @$objs, $self->perl_inc() . "/libperl$self->{config}{lib_ext}"; + $args{objects} = $objs; + } + # Some 'env' do exec(), thus return too early when run from ksh; + # To avoid 'env', remove (useless) shrpenv + local $self->{config}{shrpenv} = ''; + return $self->SUPER::_do_link($how, %args); +} + +sub extra_link_args_after_prelink { + # Add .DEF file to the link line + my ($self, %args) = @_; + + my @DEF = grep /\.def$/i, @{$args{prelink_res}}; + die "More than one .def files created by `prelink' stage" if @DEF > 1; + # XXXX No "$how" argument here, so how to test for dynamic link? + die "No .def file created by `prelink' stage" + unless @DEF or not @{$args{prelink_res}}; + + my @after_libs = ($OS2::is_aout ? () + : $self->perl_inc() . "/libperl_override$self->{config}{lib_ext}"); + # , "-L", "-lperl" + (@after_libs, @DEF); +} + +sub link_executable { + # ldflags is not expecting .exe extension given on command line; remove -Zexe + my $self = shift; + local $self->{config}{ldflags} = $self->{config}{ldflags}; + $self->{config}{ldflags} =~ s/(?<!\S)-Zexe(?!\S)//; + return $self->SUPER::link_executable(@_); +} + + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/t/01-basic.t b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/t/01-basic.t new file mode 100644 index 00000000000..9f14e8f0a7d --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/t/01-basic.t @@ -0,0 +1,58 @@ +#! perl -w + +BEGIN { + if ($ENV{PERL_CORE}) { + chdir 't' if -d 't'; + chdir '../lib/ExtUtils/CBuilder' + or die "Can't chdir to lib/ExtUtils/CBuilder: $!"; + @INC = qw(../..); + } +} + +use strict; +use Test; +BEGIN { plan tests => 11 } + +use ExtUtils::CBuilder; +use File::Spec; +ok 1; + +# TEST doesn't like extraneous output +my $quiet = $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE}; + +my $b = ExtUtils::CBuilder->new(quiet => $quiet); +ok $b; + +ok $b->have_compiler; + +my $source_file = File::Spec->catfile('t', 'compilet.c'); +{ + local *FH; + open FH, "> $source_file" or die "Can't create $source_file: $!"; + print FH "int boot_compilet(void) { return 1; }\n"; + close FH; +} +ok -e $source_file; + +my $object_file = $b->object_file($source_file); +ok 1; + +ok $object_file, $b->compile(source => $source_file); + +my $lib_file = $b->lib_file($object_file); +ok 1; + +my ($lib, @temps) = $b->link(objects => $object_file, + module_name => 'compilet'); +$lib =~ tr/"'//d; +ok $lib_file, $lib; + +for ($source_file, $object_file, $lib_file) { + tr/"'//d; + 1 while unlink; +} + +my @words = $b->split_like_shell(' foo bar'); +ok @words, 2; +ok $words[0], 'foo'; +ok $words[1], 'bar'; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/t/02-link.t b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/t/02-link.t new file mode 100644 index 00000000000..30ecbe5d3b2 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/CBuilder/t/02-link.t @@ -0,0 +1,77 @@ +#! perl -w + +BEGIN { + if ($ENV{PERL_CORE}) { + chdir 't' if -d 't'; + chdir '../lib/ExtUtils/CBuilder' + or die "Can't chdir to lib/ExtUtils/CBuilder: $!"; + @INC = qw(../..); + } +} + +use strict; +use Test; +BEGIN { + if ($^O eq 'MSWin32') { + print "1..0 # Skipped: link_executable() is not implemented yet on Win32\n"; + exit; + } + if ($^O eq 'VMS') { + # So we can get the return value of system() + require vmsish; + import vmsish; + } + plan tests => 5; +} + +use ExtUtils::CBuilder; +use File::Spec; + +# TEST doesn't like extraneous output +my $quiet = $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE}; + +my $b = ExtUtils::CBuilder->new(quiet => $quiet); +ok $b; + +my $source_file = File::Spec->catfile('t', 'compilet.c'); +{ + local *FH; + open FH, "> $source_file" or die "Can't create $source_file: $!"; + print FH "int main(void) { return 11; }\n"; + close FH; +} +ok -e $source_file; + +# Compile +my $object_file; +ok $object_file = $b->compile(source => $source_file); + +# Link +my ($exe_file, @temps); +($exe_file, @temps) = $b->link_executable(objects => $object_file); +ok $exe_file; + +if ($^O eq 'os2') { # Analogue of LDLOADPATH... + # Actually, not needed now, since we do not link with the generated DLL + my $old = OS2::extLibpath(); # [builtin function] + $old = ";$old" if defined $old and length $old; + # To pass the sanity check, components must have backslashes... + OS2::extLibpath_set(".\\$old"); +} + +# Try the executable +ok my_system($exe_file), 11; + +# Clean up +for ($source_file, $object_file, $exe_file) { + tr/"'//d; + 1 while unlink; +} + +sub my_system { + my $cmd = shift; + if ($^O eq 'VMS') { + return system("mcr $cmd"); + } + return system($cmd) >> 8; +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Changes b/gnu/usr.bin/perl/lib/ExtUtils/Changes index af4b84c5212..c4c37c80a39 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Changes +++ b/gnu/usr.bin/perl/lib/ExtUtils/Changes @@ -1,3 +1,226 @@ +6.42 Fri Dec 7 17:00:14 PST 2007 + Bug Fixes + - 6.33 moved PREREQ_FATAL to happen after CONFIGURE. This meant if + your CONFIGURE use a prereq it would fail and no PREREQ_FATAL + message would be displayed. + - Put the "nicetext" functionality back, VMS needs it to deal with + other people's custom make. But rename it to the more + accurate maketext_filter(), test it and fix a bug where it would + stop processing if it saw a macro declaration. + +6.40 Thu Dec 6 03:00:47 PST 2007 + Bug Fixes + - Remove the dubious nicetext() Makefile formatting hack to account for + a lack of space between the target and colon needed on VMS. This + interfered with META.yml creation on VMS and possibly other output. + - Fix the remaining targets which don't have a space between the target + and the colon. + +6.38 Wed Nov 28 16:01:12 PST 2007 + Releasing 6.37_03 as 6.38. + +6.37_03 Mon Nov 26 14:15:34 PST 2007 + Tests + - parse_version.t had wrong test count when version.pm isn't installed. + - Fixed some warnings in the XS module we're using for testing. + - "our $VERSION" test in parse_version.t was never running + - Quoting uses of 1.2.3 style versions in parse_version.t to protect + older perls. + + Portability + - Moved the minimum required version up to 5.6.0. + +6.37_02 Sun Nov 25 23:33:14 PST 2007 + Test Improvements + - Added a test for a basic XS build. + + Bug Fixes + - A refactoring in 6.37_01 broke XS compilation. + +6.37_01 Sun Nov 25 17:05:53 PST 2007 + Improvements + - Upgraded the META.yml to version 1.3 of the spec (which really + doesn't change anything). Thanks bdfoy. + - MakeMaker now always includes the required 'author' field in + the META.yml even if it's undef to comply with the META.yml spec. + - Updated ExtUtils-Install to latest version (1.44) + - Unified the version numbers of all modules. + + Test Fixes + - cd() test on VMS used non-native paths. [bleadperl 31534] + - Removed uses of "no_plan" in tests to remain compatible with + old versions of Test::Harness. + - writemakefile_args.t had the wrong test count if version.pm isn't + installed. + + Bug Fixes + - $VERSION detection code would be confused by "sub version" + [rt.cpan.org 30747] + - LINKTYPE=static will now be propagated to child builds. + [bleadperl 31761] + + Portability Fixes + - Add "dragonfly" to the list of BSDish operating systems + - BSD detection code would not pick up bsdos or internix + - Fix detection of shared libperl on NetBSD [bleadperl 31526] + + +6.36 Tue Jul 3 01:06:40 PDT 2007 + Test Fixes + - version.pm prior to 0.7203 caused Foo->VERSION to reformat + $Foo::VERSION. This caused prereq.t to fail. + +6.35 Sun Jul 1 20:53:38 PDT 2007 + New Features + * MakeMaker will now try to "use version" before parsing $VERSION. + This allows "$VERSION = qv(1.2.3)" to work. + + Test Fixes + - writemakefile_args.t now works with older versions of version.pm + +6.34 Sat Jun 30 11:06:54 CDT 2007 + Test Fixes + - Accidentally hard coded the version of strict.pm [rt.cpan.org 27838] + +6.33 Fri Jun 29 17:15:34 CDT 2007 + New Features + * VERSION now accepts version objects without warning. + [rt.cpan.org 26075] + + Bug Fixes + - Properly not installing MANIFEST.SKIP when ExtUtils::Manifest is not + being installed. [rt.cpan.org 21318] + - fixin() no longer clobbers $/ [rt.cpan.org 26234] + - Fixed bug finding cross-compiled perls [bleadperl 31404] + - Looking up to 8 levels up to find uninstalled perls + [bleadperl 30932] + * A test failure in a sub-project would not cause "make test" to + fail. [rt.cpan.org 27804] + + Windows + - Embed manifest files in EXEs and DLLs when building with VC++ 8.x + [bleadperl #29266] [rt.cpan.org 26208] + - Improved the subdir command code so DIR can do more than one level + down. [rt.cpan.org 25180] + - Fix static builds on Win32 by using -DPERLDLL [bleadperl 31229] + + VMS + - Use linker flags rather than compiler flags to determine if the + perl sharable image was linked debug. This keeps OPTIMIZE from + confusing things. [rt.cpan.org 25268] + - Accidental use of $\ in a regex. [bleadperl 30521] + + BSD + - If calling perl causes MakeMaker to emit warnings, then it + cannot find the location of its binary. [rt.cpan.org 23178] + + Doc Improvements + - Typo fixes. $(TOUNIX) -> $(TO_UNIX). [rt.cpan.org 23495] + - The example for setting $VERSION from $Revision$ in SVN was + incorrect. (Thanks to ROBERTMAY@cpan.org) [rt.cpan.org 26995] + - Document what's wrong with PREFIX and what to use instead. + [rt.cpan.org 12919] + - Improve the PREREQ_FATAL docs to make it really clear that you + do NOT want to use this! + + Misc + - Provide information during the install about whether we're using the + installed or provided dependency (ie. ExtUtils::Command). + - Updated included versions of ExtUtils::Manifest and Command. + - Add .bak and .old to veryclean [rt.cpan.org 21284] + - Improved the PREREQ_FATAL message. + +6.32 Wed Feb 21 07:59:57 PST 2007 + New Features + - WriteEmptyMakefile() is now exportable upon request. + + Bug Fixes + - Set binmode() when writing to files in Command.t for operating + systems which need that sort of thing. [bleadperl #29578] + - Fixed a minor duplication in manifypod_target(). [rt.cpan.org 22149] + + Test Fixes + - The build_man.t test would fail if your Perl is configured to not + generate man pages ($Config{installman3dir} is set to none). + + Doc Improvements + - Made the home dir install examples a little more friendly to non-Unix + folks. + + Misc + - miniperl no longer has the Win32 functions. + - Turn on "use strict" where it was missing. + +6.31 Mon Oct 9 16:54:47 PDT 2006 + - Update our META.yml to version 1.2 of the spec. + * Update the SEE ALSO to mention Module::Build, Module::Install, + ExtUtils::ModuleMaker and Module::Starter. + - Fix ARCHITECTURE tag in PPD generation for 5.8 (patch taken from + ActiveState 819). [rt.cpan.org 20566] + * Bring ExtUtils::Manifest up to 1.48 + +6.30_04 Mon Sep 11 16:14:06 EDT 2006 + - EXTRA_META has been undocumented as I don't like the way the + interface works but I don't want to hold up 6.31. It will be + replaced with something better next version. + - Added explaination of distclean behavior and instructions on how to + blow away anything not in the MANIFEST to the FAQ. + * 6.30_01 broke overrides of PM. MakeMaker would add to a user + suplied PM rather than simply accepting it. + * Document INSTALL_BASE. + * Added "How do I install a module into my home directory?" to the FAQ + * Added "How do I get MakeMaker and Module::Build to install to the + same place?" + - Moving ExtUtils::Mksymlists and ExtUtils::Mkbootstrap back into + lib/ because no independent distribution has taken them over. + +6.30_03 Fri Sep 1 17:03:11 EDT 2006 + - Minor fix to Command.t for Win32. + +6.30_02 Fri Sep 1 15:03:55 EDT 2006 + - Updated to ExtUtils::Install 1.41 + * Won't scan for and build man pages when MAN3PODS is deliberately set + empty. + - Minor VMS fixes. [bleadperl@26813] + - VMS->one_liner must quote "--" argument. [bleadperl@27613] + * Split INSTALLSCRIPT into INSTALLSCRIPT, INSTALLSITESCRIPT and + INSTALLVENDORSCRIPT so it now honors INSTALLDIRS. [bleadperl@26536] + - Minor fix to work with Pod::man 2.04. [bleadperl@26457] + - $Revision was broken. + - Updated our internal version of Test::More to catch a few warnings. + - ExtUtils::Command::test_f() test was broken. + - Clarified that test_f() exits. + +6.30_01 Tue Aug 16 23:53:27 PDT 2005 + * Fixed compiling modules using an uninstalled Perl on Win32 by using + the proper perl header location for Windows (which is different from + Unix). Looks like a very old bug. [bugs.perl.org 36128] + - $ExtUtils::MakeMaker::Revision accidentally left in a stray "Revision". + [thanks pdx.pm for noticing this] + - Fixed the $VERSION = $Revision$ example in the MakeMaker docs and the + FAQ. [thanks again, pdx.pm] + - Elaborated on the differences between CVS, SVN and others when using + $Revision$ based $VERSIONs. + * ExtUtils::Command, ExtUtils::Install, ExtUtils::Manifest, + ExtUtils::Mkbootstrap, ExtUtils::Mksymlists and ExtUtils::Packlist + are all now considered to be separate distributions. To avoid a + circular dependency, MakeMaker distributes its own versions but CPAN + should not index them and they will not overwrite a newer, installed + version. + * Added EXTRA_META option to allow module authors to append extra + text to the generated META.yml. + * Added a LICENSE field mirroring Module::Build's license. + * META.yml support updated to version 1.1. All required fields + now generated. (NOTE: 1.1 isn't yet complete but we're going with + it anyway. MakeMaker uses "author" instead of "authored_by" as its + expected the former will be used in 1.1 final). + * Non-conforming version_from and installdirs META.yml fields removed. + * META.yml distribution_type field now intelligent enough to guess at + the type rather than hard code 'module'. + * INSTALLBASE changed to INSTALL_BASE to match Module::Build. + * Added a MAKE parameter for Windows users to say if they're using + dmake or nmake. + 6.30 Fri May 20 16:05:38 PDT 2005 * PL_FILES behavior tweak again to restore old behavior. Sometimes its supposed to run before pm_to_blib, sometimes after. diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Command/MM.pm b/gnu/usr.bin/perl/lib/ExtUtils/Command/MM.pm index 046fb8b5aef..48a66cedb95 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Command/MM.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Command/MM.pm @@ -9,7 +9,7 @@ use vars qw($VERSION @ISA @EXPORT); @EXPORT = qw(test_harness pod2man perllocal_install uninstall warn_if_old_packlist); -$VERSION = '0.05'; +$VERSION = '6.42'; my $Is_VMS = $^O eq 'VMS'; @@ -117,8 +117,6 @@ sub pod2man { # compatibility. delete $options{lax}; - my $parser = Pod::Man->new(%options); - do {{ # so 'next' works my ($pod, $man) = splice(@ARGV, 0, 2); @@ -128,6 +126,7 @@ sub pod2man { print "Manifying $man\n"; + my $parser = Pod::Man->new(%options); $parser->parse_from_file($pod, $man) or do { warn("Could not install $man\n"); next }; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Constant.pm b/gnu/usr.bin/perl/lib/ExtUtils/Constant.pm index 9e2b6b832e1..c449a9b3f83 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Constant.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Constant.pm @@ -1,6 +1,6 @@ package ExtUtils::Constant; use vars qw (@ISA $VERSION @EXPORT_OK %EXPORT_TAGS); -$VERSION = 0.17; +$VERSION = 0.20; =head1 NAME @@ -243,17 +243,23 @@ EOT $xs .= ', &sv' if $params->{SV}; $xs .= ");\n"; + # If anyone is insane enough to suggest a package name containing % + my $package_sprintf_safe = $package; + $package_sprintf_safe =~ s/%/%%/g; + $xs .= << "EOT"; /* Return 1 or 2 items. First is error message, or undef if no error. Second, if present, is found value */ switch (type) { case PERL_constant_NOTFOUND: - sv = sv_2mortal(newSVpvf("%s is not a valid $package macro", s)); + sv = + sv_2mortal(newSVpvf("%s is not a valid $package_sprintf_safe macro", s)); PUSHs(sv); break; case PERL_constant_NOTDEF: sv = sv_2mortal(newSVpvf( - "Your vendor has not defined $package macro %s, used", s)); + "Your vendor has not defined $package_sprintf_safe macro %s, used", + s)); PUSHs(sv); break; EOT @@ -283,7 +289,7 @@ EOT $xs .= << "EOT"; default: sv = sv_2mortal(newSVpvf( - "Unexpected return type %d while processing $package macro %s, used", + "Unexpected return type %d while processing $package_sprintf_safe macro %s, used", type, s)); PUSHs(sv); } @@ -432,6 +438,11 @@ for each group with this number or more names in. An array of constants' names, either scalars containing names, or hashrefs as detailed in L<"C_constant">. +=item C_FH + +A filehandle to write the C code to. If not given, then I<C_FILE> is opened +for writing. + =item C_FILE The name of the file to write containing the C code. The default is @@ -440,6 +451,11 @@ mistaken for anything related to a legitimate perl package name, and not naming the file C<.c> avoids having to override Makefile.PL's C<.xs> to C<.c> rules. +=item XS_FH + +A filehandle to write the XS code to. If not given, then I<XS_FILE> is opened +for writing. + =item XS_FILE The name of the file to write containing the XS code. The default is @@ -474,42 +490,62 @@ sub WriteConstants { croak "Module name not specified" unless length $ARGS{NAME}; - my ($c_fh, $xs_fh); - if ($] <= 5.008) { - # We need these little games, rather than doing things unconditionally, - # because we're used in core Makefile.PLs before IO is available (needed - # by filehandle), but also we want to work on older perls where undefined - # scalars do not automatically turn into anonymous file handles. - require FileHandle; - $c_fh = FileHandle->new(); - $xs_fh = FileHandle->new(); + my $c_fh = $ARGS{C_FH}; + if (!$c_fh) { + if ($] <= 5.008) { + # We need these little games, rather than doing things + # unconditionally, because we're used in core Makefile.PLs before + # IO is available (needed by filehandle), but also we want to work on + # older perls where undefined scalars do not automatically turn into + # anonymous file handles. + require FileHandle; + $c_fh = FileHandle->new(); + } + open $c_fh, ">$ARGS{C_FILE}" or die "Can't open $ARGS{C_FILE}: $!"; + } + + my $xs_fh = $ARGS{XS_FH}; + if (!$xs_fh) { + if ($] <= 5.008) { + require FileHandle; + $xs_fh = FileHandle->new(); + } + open $xs_fh, ">$ARGS{XS_FILE}" or die "Can't open $ARGS{XS_FILE}: $!"; } - open $c_fh, ">$ARGS{C_FILE}" or die "Can't open $ARGS{C_FILE}: $!"; - open $xs_fh, ">$ARGS{XS_FILE}" or die "Can't open $ARGS{XS_FILE}: $!"; # As this subroutine is intended to make code that isn't edited, there's no # need for the user to specify any types that aren't found in the list of # names. - my $types = {}; - - print $c_fh constant_types(); # macro defs - print $c_fh "\n"; - - # indent is still undef. Until anyone implements indent style rules with it. - foreach (ExtUtils::Constant::XS->C_constant({package => $ARGS{NAME}, - subname => $ARGS{C_SUBNAME}, - default_type => - $ARGS{DEFAULT_TYPE}, - types => $types, - breakout => $ARGS{BREAKOUT_AT}}, - @{$ARGS{NAMES}})) { - print $c_fh $_, "\n"; # C constant subs + + if ($ARGS{PROXYSUBS}) { + require ExtUtils::Constant::ProxySubs; + $ARGS{C_FH} = $c_fh; + $ARGS{XS_FH} = $xs_fh; + ExtUtils::Constant::ProxySubs->WriteConstants(%ARGS); + } else { + my $types = {}; + + print $c_fh constant_types(); # macro defs + print $c_fh "\n"; + + # indent is still undef. Until anyone implements indent style rules with + # it. + foreach (ExtUtils::Constant::XS->C_constant({package => $ARGS{NAME}, + subname => $ARGS{C_SUBNAME}, + default_type => + $ARGS{DEFAULT_TYPE}, + types => $types, + breakout => + $ARGS{BREAKOUT_AT}}, + @{$ARGS{NAMES}})) { + print $c_fh $_, "\n"; # C constant subs + } + print $xs_fh XS_constant ($ARGS{NAME}, $types, $ARGS{XS_SUBNAME}, + $ARGS{C_SUBNAME}); } - print $xs_fh XS_constant ($ARGS{NAME}, $types, $ARGS{XS_SUBNAME}, - $ARGS{C_SUBNAME}); - close $c_fh or warn "Error closing $ARGS{C_FILE}: $!"; - close $xs_fh or warn "Error closing $ARGS{XS_FILE}: $!"; + close $c_fh or warn "Error closing $ARGS{C_FILE}: $!" unless $ARGS{C_FH}; + close $xs_fh or warn "Error closing $ARGS{XS_FILE}: $!" unless $ARGS{XS_FH}; } 1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Constant/Base.pm b/gnu/usr.bin/perl/lib/ExtUtils/Constant/Base.pm index 8a6fc6fab02..b5b79af1ea7 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Constant/Base.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Constant/Base.pm @@ -1,14 +1,13 @@ package ExtUtils::Constant::Base; use strict; -use vars qw($VERSION $is_perl56); +use vars qw($VERSION); use Carp; use Text::Wrap; use ExtUtils::Constant::Utils qw(C_stringify perl_stringify); +$VERSION = '0.04'; -$VERSION = '0.01'; - -$is_perl56 = ($] < 5.007 && $] > 5.005_50); +use constant is_perl56 => ($] < 5.007 && $] > 5.005_50); =head1 NAME @@ -69,6 +68,33 @@ sub macro_from_name { 1; } +sub macro_from_item { + 1; +} + +sub macro_to_ifdef { + my ($self, $macro) = @_; + if (ref $macro) { + return $macro->[0]; + } + if (defined $macro && $macro ne "" && $macro ne "1") { + return $macro ? "#ifdef $macro\n" : "#if 0\n"; + } + return ""; +} + +sub macro_to_endif { + my ($self, $macro) = @_; + + if (ref $macro) { + return $macro->[1]; + } + if (defined $macro && $macro ne "" && $macro ne "1") { + return "#endif\n"; + } + return ""; +} + sub name_param { 'name'; } @@ -211,7 +237,7 @@ sub dump_names { next if $_->{utf8} eq 'no'; # Copy the hashref, as we don't want to mess with the caller's hashref. $_ = {%$_}; - unless ($is_perl56) { + unless (is_perl56) { utf8::decode ($_->{name}); } else { $_->{name} = pack 'U*', unpack 'U0U*', $_->{name}; @@ -349,26 +375,18 @@ sub return_clause { my ($self, $args, $item) = @_; my $indent = $args->{indent}; - my ($name, $value, $macro, $default, $pre, $post, $def_pre, $def_post, $type) - = @$item{qw (name value macro default pre post def_pre def_post type)}; + my ($name, $value, $default, $pre, $post, $def_pre, $def_post, $type) + = @$item{qw (name value default pre post def_pre def_post type)}; $value = $name unless defined $value; - $macro = $self->macro_from_name($item) unless defined $macro; - # "#if 1" is true to a C pre-processor - $macro = 1 if !defined $macro or $macro eq ''; + my $macro = $self->macro_from_item($item); $indent = ' ' x ($indent || 6); unless (defined $type) { # use Data::Dumper; print STDERR Dumper ($item); confess "undef \$type"; } - my $clause; - ##ifdef thingy - if (ref $macro) { - $clause = $macro->[0]; - } elsif ($macro ne "1") { - $clause = "#ifdef $macro\n"; - } + my $clause = $self->macro_to_ifdef($macro); # *iv_return = thingy; # return PERL_constant_ISIV; @@ -376,7 +394,7 @@ sub return_clause { .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre, post=>$post, item=>$item}, ref $value ? @$value : $value); - if (ref $macro or $macro ne "1") { + if (defined $macro && $macro ne "" && $macro ne "1") { ##else $clause .= "#else\n"; @@ -390,14 +408,10 @@ sub return_clause { $clause .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre, post=>$post, item=>$item}, @default); } - - ##endif - if (ref $macro) { - $clause .= $macro->[1]; - } else { - $clause .= "#endif\n"; - } } + ##endif + $clause .= $self->macro_to_endif($macro); + return $clause; } @@ -501,7 +515,7 @@ sub switch_clause { foreach my $i ($namelen - 1, 0 .. ($namelen - 2)) { my ($min, $max) = (~0, 0); my %spread; - if ($is_perl56) { + if (is_perl56) { # Need proper Unicode preserving hash keys for bytes in range 128-255 # here too, for some reason. grr 5.6.1 yet again. tie %spread, 'ExtUtils::Constant::Aaargh56Hash'; @@ -643,6 +657,98 @@ sub dogfood { '' } +=item normalise_items args, default_type, seen_types, seen_items, ITEM... + +Convert the items to a normalised form. For 8 bit and Unicode values converts +the item to an array of 1 or 2 items, both 8 bit and UTF-8 encoded. + +=cut + +sub normalise_items +{ + my $self = shift; + my $args = shift; + my $default_type = shift; + my $what = shift; + my $items = shift; + my @new_items; + foreach my $orig (@_) { + my ($name, $item); + if (ref $orig) { + # Make a copy which is a normalised version of the ref passed in. + $name = $orig->{name}; + my ($type, $macro, $value) = @$orig{qw (type macro value)}; + $type ||= $default_type; + $what->{$type} = 1; + $item = {name=>$name, type=>$type}; + + undef $macro if defined $macro and $macro eq $name; + $item->{macro} = $macro if defined $macro; + undef $value if defined $value and $value eq $name; + $item->{value} = $value if defined $value; + foreach my $key (qw(default pre post def_pre def_post weight + not_constant)) { + my $value = $orig->{$key}; + $item->{$key} = $value if defined $value; + # warn "$key $value"; + } + } else { + $name = $orig; + $item = {name=>$name, type=>$default_type}; + $what->{$default_type} = 1; + } + warn +(ref ($self) || $self) + . "doesn't know how to handle values of type $_ used in macro $name" + unless $self->valid_type ($item->{type}); + # tr///c is broken on 5.6.1 for utf8, so my original tr/\0-\177//c + # doesn't work. Upgrade to 5.8 + # if ($name !~ tr/\0-\177//c || $] < 5.005_50) { + if ($name =~ tr/\0-\177// == length $name || $] < 5.005_50 + || $args->{disable_utf8_duplication}) { + # No characters outside 7 bit ASCII. + if (exists $items->{$name}) { + die "Multiple definitions for macro $name"; + } + $items->{$name} = $item; + } else { + # No characters outside 8 bit. This is hardest. + if (exists $items->{$name} and ref $items->{$name} ne 'ARRAY') { + confess "Unexpected ASCII definition for macro $name"; + } + # Again, 5.6.1 tr broken, so s/5\.6.*/5\.8\.0/; + # if ($name !~ tr/\0-\377//c) { + if ($name =~ tr/\0-\377// == length $name) { +# if ($] < 5.007) { +# $name = pack "C*", unpack "U*", $name; +# } + $item->{utf8} = 'no'; + $items->{$name}[1] = $item; + push @new_items, $item; + # Copy item, to create the utf8 variant. + $item = {%$item}; + } + # Encode the name as utf8 bytes. + unless (is_perl56) { + utf8::encode($name); + } else { +# warn "Was >$name< " . length ${name}; + $name = pack 'C*', unpack 'C*', $name . pack 'U*'; +# warn "Now '${name}' " . length ${name}; + } + if ($items->{$name}[0]) { + die "Multiple definitions for macro $name"; + } + $item->{utf8} = 'yes'; + $item->{name} = $name; + $items->{$name}[0] = $item; + # We have need for the utf8 flag. + $what->{''} = 1; + } + push @new_items, $item; + } + @new_items; +} + =item C_constant arg_hashref, ITEM... A function that returns a B<list> of C subroutine definitions that return @@ -779,10 +885,10 @@ sub C_constant { # be a hashref, and pinch %$items from our parent to save recalculation. ($namelen, $items) = @$breakout; } else { - if ($is_perl56) { + $items = {}; + if (is_perl56) { # Need proper Unicode preserving hash keys. require ExtUtils::Constant::Aaargh56Hash; - $items = {}; tie %$items, 'ExtUtils::Constant::Aaargh56Hash'; } $breakout ||= 3; @@ -793,80 +899,7 @@ sub C_constant { # Figure out what types we're dealing with, and assign all unknowns to the # default type } - my @new_items; - foreach my $orig (@items) { - my ($name, $item); - if (ref $orig) { - # Make a copy which is a normalised version of the ref passed in. - $name = $orig->{name}; - my ($type, $macro, $value) = @$orig{qw (type macro value)}; - $type ||= $default_type; - $what->{$type} = 1; - $item = {name=>$name, type=>$type}; - - undef $macro if defined $macro and $macro eq $name; - $item->{macro} = $macro if defined $macro; - undef $value if defined $value and $value eq $name; - $item->{value} = $value if defined $value; - foreach my $key (qw(default pre post def_pre def_post weight)) { - my $value = $orig->{$key}; - $item->{$key} = $value if defined $value; - # warn "$key $value"; - } - } else { - $name = $orig; - $item = {name=>$name, type=>$default_type}; - $what->{$default_type} = 1; - } - warn +(ref ($self) || $self) - . "doesn't know how to handle values of type $_ used in macro $name" - unless $self->valid_type ($item->{type}); - # tr///c is broken on 5.6.1 for utf8, so my original tr/\0-\177//c - # doesn't work. Upgrade to 5.8 - # if ($name !~ tr/\0-\177//c || $] < 5.005_50) { - if ($name =~ tr/\0-\177// == length $name || $] < 5.005_50) { - # No characters outside 7 bit ASCII. - if (exists $items->{$name}) { - die "Multiple definitions for macro $name"; - } - $items->{$name} = $item; - } else { - # No characters outside 8 bit. This is hardest. - if (exists $items->{$name} and ref $items->{$name} ne 'ARRAY') { - confess "Unexpected ASCII definition for macro $name"; - } - # Again, 5.6.1 tr broken, so s/5\.6.*/5\.8\.0/; - # if ($name !~ tr/\0-\377//c) { - if ($name =~ tr/\0-\377// == length $name) { -# if ($] < 5.007) { -# $name = pack "C*", unpack "U*", $name; -# } - $item->{utf8} = 'no'; - $items->{$name}[1] = $item; - push @new_items, $item; - # Copy item, to create the utf8 variant. - $item = {%$item}; - } - # Encode the name as utf8 bytes. - unless ($is_perl56) { - utf8::encode($name); - } else { -# warn "Was >$name< " . length ${name}; - $name = pack 'C*', unpack 'C*', $name . pack 'U*'; -# warn "Now '${name}' " . length ${name}; - } - if ($items->{$name}[0]) { - die "Multiple definitions for macro $name"; - } - $item->{utf8} = 'yes'; - $item->{name} = $name; - $items->{$name}[0] = $item; - # We have need for the utf8 flag. - $what->{''} = 1; - } - push @new_items, $item; - } - @items = @new_items; + @items = $self->normalise_items ({}, $default_type, $what, $items, @items); # use Data::Dumper; print Dumper @items; } my $params = $self->params ($what); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Constant/ProxySubs.pm b/gnu/usr.bin/perl/lib/ExtUtils/Constant/ProxySubs.pm new file mode 100644 index 00000000000..af8c458b634 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/Constant/ProxySubs.pm @@ -0,0 +1,524 @@ +package ExtUtils::Constant::ProxySubs; + +use strict; +use vars qw($VERSION @ISA %type_to_struct %type_from_struct %type_to_sv + %type_to_C_value %type_is_a_problem %type_num_args + %type_temporary); +use Carp; +require ExtUtils::Constant::XS; +use ExtUtils::Constant::Utils qw(C_stringify); +use ExtUtils::Constant::XS qw(%XS_TypeSet); + +$VERSION = '0.05'; +@ISA = 'ExtUtils::Constant::XS'; + +%type_to_struct = + ( + IV => '{const char *name; I32 namelen; IV value;}', + NV => '{const char *name; I32 namelen; NV value;}', + UV => '{const char *name; I32 namelen; UV value;}', + PV => '{const char *name; I32 namelen; const char *value;}', + PVN => '{const char *name; I32 namelen; const char *value; STRLEN len;}', + YES => '{const char *name; I32 namelen;}', + NO => '{const char *name; I32 namelen;}', + UNDEF => '{const char *name; I32 namelen;}', + '' => '{const char *name; I32 namelen;} ', + ); + +%type_from_struct = + ( + IV => sub { $_[0] . '->value' }, + NV => sub { $_[0] . '->value' }, + UV => sub { $_[0] . '->value' }, + PV => sub { $_[0] . '->value' }, + PVN => sub { $_[0] . '->value', $_[0] . '->len' }, + YES => sub {}, + NO => sub {}, + UNDEF => sub {}, + '' => sub {}, + ); + +%type_to_sv = + ( + IV => sub { "newSViv($_[0])" }, + NV => sub { "newSVnv($_[0])" }, + UV => sub { "newSVuv($_[0])" }, + PV => sub { "newSVpv($_[0], 0)" }, + PVN => sub { "newSVpvn($_[0], $_[1])" }, + YES => sub { '&PL_sv_yes' }, + NO => sub { '&PL_sv_no' }, + UNDEF => sub { '&PL_sv_undef' }, + '' => sub { '&PL_sv_yes' }, + SV => sub {"SvREFCNT_inc($_[0])"}, + ); + +%type_to_C_value = + ( + YES => sub {}, + NO => sub {}, + UNDEF => sub {}, + '' => sub {}, + ); + +sub type_to_C_value { + my ($self, $type) = @_; + return $type_to_C_value{$type} || sub {return map {ref $_ ? @$_ : $_} @_}; +} + +# TODO - figure out if there is a clean way for the type_to_sv code to +# attempt s/sv_2mortal// and if it succeeds tell type_to_sv not to add +# SvREFCNT_inc +%type_is_a_problem = + ( + # The documentation says *mortal SV*, but we now need a non-mortal copy. + SV => 1, + ); + +%type_temporary = + ( + SV => ['SV *'], + PV => ['const char *'], + PVN => ['const char *', 'STRLEN'], + ); +$type_temporary{$_} = [$_] foreach qw(IV UV NV); + +while (my ($type, $value) = each %XS_TypeSet) { + $type_num_args{$type} + = defined $value ? ref $value ? scalar @$value : 1 : 0; +} +$type_num_args{''} = 0; + +sub partition_names { + my ($self, $default_type, @items) = @_; + my (%found, @notfound, @trouble); + + while (my $item = shift @items) { + my $default = delete $item->{default}; + if ($default) { + # If we find a default value, convert it into a regular item and + # append it to the queue of items to process + my $default_item = {%$item}; + $default_item->{invert_macro} = 1; + $default_item->{pre} = delete $item->{def_pre}; + $default_item->{post} = delete $item->{def_post}; + $default_item->{type} = shift @$default; + $default_item->{value} = $default; + push @items, $default_item; + } else { + # It can be "not found" unless it's the default (invert the macro) + # or the "macro" is an empty string (ie no macro) + push @notfound, $item unless $item->{invert_macro} + or !$self->macro_to_ifdef($self->macro_from_item($item)); + } + + if ($item->{pre} or $item->{post} or $item->{not_constant} + or $type_is_a_problem{$item->{type}}) { + push @trouble, $item; + } else { + push @{$found{$item->{type}}}, $item; + } + } + # use Data::Dumper; print Dumper \%found; + (\%found, \@notfound, \@trouble); +} + +sub boottime_iterator { + my ($self, $type, $iterator, $hash, $subname) = @_; + my $extractor = $type_from_struct{$type}; + die "Can't find extractor code for type $type" + unless defined $extractor; + my $generator = $type_to_sv{$type}; + die "Can't find generator code for type $type" + unless defined $generator; + + my $athx = $self->C_constant_prefix_param(); + + return sprintf <<"EOBOOT", &$generator(&$extractor($iterator)); + while ($iterator->name) { + $subname($athx $hash, $iterator->name, + $iterator->namelen, %s); + ++$iterator; + } +EOBOOT +} + +sub name_len_value_macro { + my ($self, $item) = @_; + my $name = $item->{name}; + my $value = $item->{value}; + $value = $item->{name} unless defined $value; + + my $namelen = length $name; + if ($name =~ tr/\0-\377// != $namelen) { + # the hash API signals UTF-8 by passing the length negated. + utf8::encode($name); + $namelen = -length $name; + } + $name = C_stringify($name); + + my $macro = $self->macro_from_item($item); + ($name, $namelen, $value, $macro); +} + +sub WriteConstants { + my $self = shift; + my $ARGS = {@_}; + + my ($c_fh, $xs_fh, $c_subname, $xs_subname, $default_type, $package) + = @{$ARGS}{qw(C_FH XS_FH C_SUBNAME XS_SUBNAME DEFAULT_TYPE NAME)}; + + my $options = $ARGS->{PROXYSUBS}; + $options = {} unless ref $options; + my $explosives = $options->{croak_on_read}; + + $xs_subname ||= 'constant'; + + # If anyone is insane enough to suggest a package name containing % + my $package_sprintf_safe = $package; + $package_sprintf_safe =~ s/%/%%/g; + + # All the types we see + my $what = {}; + # A hash to lookup items with. + my $items = {}; + + my @items = $self->normalise_items ({disable_utf8_duplication => 1}, + $default_type, $what, $items, + @{$ARGS->{NAMES}}); + + # Partition the values by type. Also include any defaults in here + # Everything that doesn't have a default needs alternative code for + # "I'm missing" + # And everything that has pre or post code ends up in a private block + my ($found, $notfound, $trouble) + = $self->partition_names($default_type, @items); + + my $pthx = $self->C_constant_prefix_param_defintion(); + my $athx = $self->C_constant_prefix_param(); + my $symbol_table = C_stringify($package) . '::'; + + print $c_fh $self->header(), <<"EOADD"; +static void +${c_subname}_add_symbol($pthx HV *hash, const char *name, I32 namelen, SV *value) { + SV **sv = hv_fetch(hash, name, namelen, TRUE); + if (!sv) { + Perl_croak($athx "Couldn't add key '%s' to %%$package_sprintf_safe\::", + name); + } + if (SvOK(*sv) || SvTYPE(*sv) == SVt_PVGV) { + /* Someone has been here before us - have to make a real sub. */ + newCONSTSUB(hash, name, value); + } else { + SvUPGRADE(*sv, SVt_RV); + SvRV_set(*sv, value); + SvROK_on(*sv); + SvREADONLY_on(value); + } +} + +EOADD + + print $c_fh $explosives ? <<"EXPLODE" : "\n"; + +static int +Im_sorry_Dave(pTHX_ SV *sv, MAGIC *mg) +{ + PERL_UNUSED_ARG(mg); + Perl_croak(aTHX_ + "Your vendor has not defined $package_sprintf_safe macro %"SVf + " used", sv); + NORETURN_FUNCTION_END; +} + +static MGVTBL not_defined_vtbl = { + Im_sorry_Dave, /* get - I'm afraid I can't do that */ + Im_sorry_Dave, /* set */ + 0, /* len */ + 0, /* clear */ + 0, /* free */ + 0, /* copy */ + 0, /* dup */ +}; + +EXPLODE + +{ + my $key = $symbol_table; + # Just seems tidier (and slightly more space efficient) not to have keys + # such as Fcntl:: + $key =~ s/::$//; + my $key_len = length $key; + + print $c_fh <<"MISSING"; + +#ifndef SYMBIAN + +/* Store a hash of all symbols missing from the package. To avoid trampling on + the package namespace (uninvited) put each package's hash in our namespace. + To avoid creating lots of typeblogs and symbol tables for sub-packages, put + each package's hash into one hash in our namespace. */ + +static HV * +get_missing_hash(pTHX) { + HV *const parent + = get_hv("ExtUtils::Constant::ProxySubs::Missing", GVf_MULTI); + /* We could make a hash of hashes directly, but this would confuse anything + at Perl space that looks at us, and as we're visible in Perl space, + best to play nice. */ + SV *const *const ref + = hv_fetch(parent, "$key", $key_len, TRUE); + HV *new_hv; + + if (!ref) + return NULL; + + if (SvROK(*ref)) + return (HV*) SvRV(*ref); + + new_hv = newHV(); + SvUPGRADE(*ref, SVt_RV); + SvRV_set(*ref, (SV *)new_hv); + SvROK_on(*ref); + return new_hv; +} + +#endif + +MISSING + +} + + print $xs_fh <<"EOBOOT"; +BOOT: + { +#ifdef dTHX + dTHX; +#endif + HV *symbol_table = get_hv("$symbol_table", TRUE); +#ifndef SYMBIAN + HV *${c_subname}_missing; +#endif +EOBOOT + + my %iterator; + + $found->{''} + = [map {{%$_, type=>'', invert_macro => 1}} @$notfound]; + + foreach my $type (sort keys %$found) { + my $struct = $type_to_struct{$type}; + my $type_to_value = $self->type_to_C_value($type); + my $number_of_args = $type_num_args{$type}; + die "Can't find structure definition for type $type" + unless defined $struct; + + my $struct_type = $type ? lc($type) . '_s' : 'notfound_s'; + print $c_fh "struct $struct_type $struct;\n"; + + my $array_name = 'values_for_' . ($type ? lc $type : 'notfound'); + print $xs_fh <<"EOBOOT"; + + static const struct $struct_type $array_name\[] = + { +EOBOOT + + + foreach my $item (@{$found->{$type}}) { + my ($name, $namelen, $value, $macro) + = $self->name_len_value_macro($item); + + my $ifdef = $self->macro_to_ifdef($macro); + if (!$ifdef && $item->{invert_macro}) { + carp("Attempting to supply a default for '$name' which has no conditional macro"); + next; + } + print $xs_fh $ifdef; + if ($item->{invert_macro}) { + print $xs_fh + " /* This is the default value: */\n" if $type; + print $xs_fh "#else\n"; + } + print $xs_fh " { ", join (', ', "\"$name\"", $namelen, + &$type_to_value($value)), " },\n", + $self->macro_to_endif($macro); + } + + + # Terminate the list with a NULL + print $xs_fh " { NULL, 0", (", 0" x $number_of_args), " } };\n"; + + $iterator{$type} = "value_for_" . ($type ? lc $type : 'notfound'); + + print $xs_fh <<"EOBOOT"; + const struct $struct_type *$iterator{$type} = $array_name; +EOBOOT + } + + delete $found->{''}; + + print $xs_fh <<"EOBOOT"; +#ifndef SYMBIAN + ${c_subname}_missing = get_missing_hash(aTHX); +#endif +EOBOOT + + my $add_symbol_subname = $c_subname . '_add_symbol'; + foreach my $type (sort keys %$found) { + print $xs_fh $self->boottime_iterator($type, $iterator{$type}, + 'symbol_table', + $add_symbol_subname); + } + + print $xs_fh <<"EOBOOT"; + while (value_for_notfound->name) { +EOBOOT + + print $xs_fh $explosives ? <<"EXPLODE" : << "DONT"; + SV *tripwire = newSV(0); + + sv_magicext(tripwire, 0, PERL_MAGIC_ext, ¬_defined_vtbl, 0, 0); + SvPV_set(tripwire, (char *)value_for_notfound->name); + if(value_for_notfound->namelen >= 0) { + SvCUR_set(tripwire, value_for_notfound->namelen); + } else { + SvCUR_set(tripwire, -value_for_notfound->namelen); + SvUTF8_on(tripwire); + } + SvPOKp_on(tripwire); + SvREADONLY_on(tripwire); + assert(SvLEN(tripwire) == 0); + + $add_symbol_subname($athx symbol_table, value_for_notfound->name, + value_for_notfound->namelen, tripwire); +EXPLODE + + /* Need to add prototypes, else parsing will vary by platform. */ + SV **sv = hv_fetch(symbol_table, value_for_notfound->name, + value_for_notfound->namelen, TRUE); + if (!sv) { + Perl_croak($athx + "Couldn't add key '%s' to %%$package_sprintf_safe\::", + value_for_notfound->name); + } + if (!SvOK(*sv) && SvTYPE(*sv) != SVt_PVGV) { + /* Nothing was here before, so mark a prototype of "" */ + sv_setpvn(*sv, "", 0); + } else if (SvPOK(*sv) && SvCUR(*sv) == 0) { + /* There is already a prototype of "" - do nothing */ + } else { + /* Someone has been here before us - have to make a real + typeglob. */ + /* It turns out to be incredibly hard to deal with all the + corner cases of sub foo (); and reporting errors correctly, + so lets cheat a bit. Start with a constant subroutine */ + CV *cv = newCONSTSUB(symbol_table, value_for_notfound->name, + &PL_sv_yes); + /* and then turn it into a non constant declaration only. */ + SvREFCNT_dec(CvXSUBANY(cv).any_ptr); + CvCONST_off(cv); + CvXSUB(cv) = NULL; + CvXSUBANY(cv).any_ptr = NULL; + } +#ifndef SYMBIAN + if (!hv_store(${c_subname}_missing, value_for_notfound->name, + value_for_notfound->namelen, &PL_sv_yes, 0)) + Perl_croak($athx "Couldn't add key '%s' to missing_hash", + value_for_notfound->name); +#endif +DONT + + print $xs_fh <<"EOBOOT"; + + ++value_for_notfound; + } +EOBOOT + + foreach my $item (@$trouble) { + my ($name, $namelen, $value, $macro) + = $self->name_len_value_macro($item); + my $ifdef = $self->macro_to_ifdef($macro); + my $type = $item->{type}; + my $type_to_value = $self->type_to_C_value($type); + + print $xs_fh $ifdef; + if ($item->{invert_macro}) { + print $xs_fh + " /* This is the default value: */\n" if $type; + print $xs_fh "#else\n"; + } + my $generator = $type_to_sv{$type}; + die "Can't find generator code for type $type" + unless defined $generator; + + print $xs_fh " {\n"; + # We need to use a temporary value because some really troublesome + # items use C pre processor directives in their values, and in turn + # these don't fit nicely in the macro-ised generator functions + my $counter = 0; + printf $xs_fh " %s temp%d;\n", $_, $counter++ + foreach @{$type_temporary{$type}}; + + print $xs_fh " $item->{pre}\n" if $item->{pre}; + + # And because the code in pre might be both declarations and + # statements, we can't declare and assign to the temporaries in one. + $counter = 0; + printf $xs_fh " temp%d = %s;\n", $counter++, $_ + foreach &$type_to_value($value); + + my @tempvarnames = map {sprintf 'temp%d', $_} 0 .. $counter - 1; + printf $xs_fh <<"EOBOOT", $name, &$generator(@tempvarnames); + ${c_subname}_add_symbol($athx symbol_table, "%s", + $namelen, %s); +EOBOOT + print $xs_fh " $item->{post}\n" if $item->{post}; + print $xs_fh " }\n"; + + print $xs_fh $self->macro_to_endif($macro); + } + + print $xs_fh <<EOBOOT; + /* As we've been creating subroutines, we better invalidate any cached + methods */ + ++PL_sub_generation; + } +EOBOOT + + print $xs_fh $explosives ? <<"EXPLODE" : <<"DONT"; + +void +$xs_subname(sv) + INPUT: + SV * sv; + PPCODE: + sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf + ", used", sv); + PUSHs(sv_2mortal(sv)); +EXPLODE + +void +$xs_subname(sv) + PREINIT: + STRLEN len; + INPUT: + SV * sv; + const char * s = SvPV(sv, len); + PPCODE: +#ifdef SYMBIAN + sv = newSVpvf("%"SVf" is not a valid $package_sprintf_safe macro", sv); +#else + HV *${c_subname}_missing = get_missing_hash(aTHX); + if (hv_exists(${c_subname}_missing, s, SvUTF8(sv) ? -(I32)len : (I32)len)) { + sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf + ", used", sv); + } else { + sv = newSVpvf("%"SVf" is not a valid $package_sprintf_safe macro", + sv); + } +#endif + PUSHs(sv_2mortal(sv)); +DONT + +} + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Constant/Utils.pm b/gnu/usr.bin/perl/lib/ExtUtils/Constant/Utils.pm index 3ef2228c871..067170157e3 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Constant/Utils.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Constant/Utils.pm @@ -54,7 +54,11 @@ sub C_stringify { s/\t/\\t/g; s/\f/\\f/g; s/\a/\\a/g; - s/([^\0-\177])/sprintf "\\%03o", ord $1/ge; + if (ord('A') == 193) { # EBCDIC has no ^\0-\177 workalike. + s/([[:^print:]])/sprintf "\\%03o", ord $1/ge; + } else { + s/([^\0-\177])/sprintf "\\%03o", ord $1/ge; + } unless ($] < 5.006) { # This will elicit a warning on 5.005_03 about [: :] being reserved unless # I cheat @@ -87,7 +91,11 @@ sub perl_stringify { s/\a/\\a/g; unless ($] < 5.006) { if ($] > 5.007) { - s/([^\0-\177])/sprintf "\\x{%X}", ord $1/ge; + if (ord('A') == 193) { # EBCDIC has no ^\0-\177 workalike. + s/([[:^print:]])/sprintf "\\x{%X}", ord $1/ge; + } else { + s/([^\0-\177])/sprintf "\\x{%X}", ord $1/ge; + } } else { # Grr 5.6.1. And I don't think I can use utf8; to force the regexp # because 5.005_03 will fail. diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Constant/XS.pm b/gnu/usr.bin/perl/lib/ExtUtils/Constant/XS.pm index 51244f6b2bf..010dfbd48f6 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Constant/XS.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Constant/XS.pm @@ -10,7 +10,7 @@ require ExtUtils::Constant::Base; @ISA = qw(ExtUtils::Constant::Base Exporter); @EXPORT_OK = qw(%XS_Constant %XS_TypeSet); -$VERSION = '0.01'; +$VERSION = '0.02'; $is_perl56 = ($] < 5.007 && $] > 5.005_50); @@ -143,6 +143,13 @@ sub macro_from_name { $macro; } +sub macro_from_item { + my ($self, $item) = @_; + my $macro = $item->{macro}; + $macro = $self->macro_from_name($item) unless defined $macro; + $macro; +} + # Keep to the traditional perl source macro sub memEQ { "memEQ"; @@ -221,7 +228,7 @@ EOT @items); $result .= <<'EOT'; -print constant_types(); # macro defs +print constant_types(), "\n"; # macro defs EOT $package = perl_stringify($package); $result .= @@ -239,7 +246,7 @@ EOT $result .= ", $breakout" . ', @names) ) { print $_, "\n"; # C constant subs } -print "#### XS Section:\n"; +print "\n#### XS Section:\n"; print XS_constant ("' . $package . '", $types); __END__ */ diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Installed.pm b/gnu/usr.bin/perl/lib/ExtUtils/Installed.pm index 8b0c53c4811..8e6513998bb 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Installed.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Installed.pm @@ -16,7 +16,8 @@ my $DOSISH = ($^O =~ /^(MSWin\d\d|os2|dos|mint)$/); require VMS::Filespec if $Is_VMS; use vars qw($VERSION); -$VERSION = '0.08'; +$VERSION = '1.43'; +$VERSION = eval $VERSION; sub _is_prefix { my ($self, $path, $prefix) = @_; @@ -41,16 +42,17 @@ sub _is_prefix { return(0); } -sub _is_doc { +sub _is_doc { my ($self, $path) = @_; - my $man1dir = $Config{man1direxp}; - my $man3dir = $Config{man3direxp}; + + my $man1dir = $self->{':private:'}{Config}{man1direxp}; + my $man3dir = $self->{':private:'}{Config}{man3direxp}; return(($man1dir && $self->_is_prefix($path, $man1dir)) || ($man3dir && $self->_is_prefix($path, $man3dir)) ? 1 : 0) } - + sub _is_type { my ($self, $path, $type) = @_; return 1 if $type eq "all"; @@ -58,7 +60,7 @@ sub _is_type { return($self->_is_doc($path)) if $type eq "doc"; if ($type eq "prog") { - return($self->_is_prefix($path, $Config{prefix} || $Config{prefixexp}) + return($self->_is_prefix($path, $self->{':private:'}{Config}{prefix} || $self->{':private:'}{Config}{prefixexp}) && !($self->_is_doc($path)) ? 1 : 0); @@ -77,28 +79,67 @@ sub _is_under { } sub new { - my ($class) = @_; + my ($class) = shift(@_); $class = ref($class) || $class; - my $self = {}; - my $archlib = $Config{archlibexp}; - my $sitearch = $Config{sitearchexp}; + my %args = @_; + + my $self = {}; + if ($args{config_override}) { + eval { + $self->{':private:'}{Config} = { %{$args{config_override}} }; + } or Carp::croak( + "The 'config_override' parameter must be a hash reference." + ); + } + else { + $self->{':private:'}{Config} = \%Config; + } + + for my $tuple ([inc_override => INC => [ @INC ] ], + [ extra_libs => EXTRA => [] ]) + { + my ($arg,$key,$val)=@$tuple; + if ( $args{$arg} ) { + eval { + $self->{':private:'}{$key} = [ @{$args{$arg}} ]; + } or Carp::croak( + "The '$arg' parameter must be an array reference." + ); + } + elsif ($val) { + $self->{':private:'}{$key} = $val; + } + } + { + my %dupe; + @{$self->{':private:'}{INC}} = grep { -e $_ && !$dupe{$_}++ } + @{$self->{':private:'}{INC}}, @{$self->{':private:'}{EXTRA}}; + } + my $perl5lib = defined $ENV{PERL5LIB} ? $ENV{PERL5LIB} : ""; + + my @dirs = ( $self->{':private:'}{Config}{archlibexp}, + $self->{':private:'}{Config}{sitearchexp}, + split(/\Q$Config{path_sep}\E/, $perl5lib), + @{$self->{':private:'}{EXTRA}}, + ); + # File::Find does not know how to deal with VMS filepaths. if( $Is_VMS ) { - $archlib = VMS::Filespec::unixify($archlib); - $sitearch = VMS::Filespec::unixify($sitearch); + $_ = VMS::Filespec::unixify($_) + for @dirs; } if ($DOSISH) { - $archlib =~ s|\\|/|g; - $sitearch =~ s|\\|/|g; + s|\\|/|g for @dirs; } - + my $archlib = $dirs[0]; + # Read the core packlist $self->{Perl}{packlist} = ExtUtils::Packlist->new( File::Spec->catfile($archlib, '.packlist') ); - $self->{Perl}{version} = $Config{version}; + $self->{Perl}{version} = $self->{':private:'}{Config}{version}; # Read the module packlists my $sub = sub { @@ -107,31 +148,38 @@ sub new { # Hack of the leading bits of the paths & convert to a module name my $module = $File::Find::name; - - $module =~ s!\Q$archlib\E/?auto/(.*)/.packlist!$1!s or - $module =~ s!\Q$sitearch\E/?auto/(.*)/.packlist!$1!s; + my $found; + for (@dirs) { + $found = $module =~ s!\Q$_\E/?auto/(.*)/.packlist!$1!s + and last; + } + unless ($found) { + # warn "Woah! \$_=$_\n\$module=$module\n\$File::Find::dir=$File::Find::dir\n", + # join ("\n",@dirs); + return; + } my $modfile = "$module.pm"; $module =~ s!/!::!g; # Find the top-level module file in @INC $self->{$module}{version} = ''; - foreach my $dir (@INC) { + foreach my $dir (@{$self->{':private:'}{INC}}) { my $p = File::Spec->catfile($dir, $modfile); if (-r $p) { $module = _module_name($p, $module) if $Is_VMS; - require ExtUtils::MM; $self->{$module}{version} = MM->parse_version($p); last; } } # Read the .packlist - $self->{$module}{packlist} = + $self->{$module}{packlist} = ExtUtils::Packlist->new($File::Find::name); }; - - my(@dirs) = grep { -e } ($archlib, $sitearch); + my %dupe; + @dirs= grep { -e $_ && !$dupe{$_}++ } @dirs; + $self->{':private:'}{LIBDIRS} = \@dirs; find($sub, @dirs) if @dirs; return(bless($self, $class)); @@ -171,7 +219,9 @@ sub modules { my ($self) = @_; # Bug/feature of sort in scalar context requires this. - return wantarray ? sort keys %$self : keys %$self; + return wantarray + ? sort grep { not /^:private:$/ } keys %$self + : grep { not /^:private:$/ } keys %$self; } sub files { @@ -186,7 +236,7 @@ sub files { my (@files); foreach my $file (keys(%{$self->{$module}{packlist}})) { push(@files, $file) - if ($self->_is_type($file, $type) && + if ($self->_is_type($file, $type) && $self->_is_under($file, @under)); } return(@files); @@ -268,7 +318,8 @@ information from the .packlist files. The new() function searches for all the installed .packlists on the system, and stores their contents. The .packlists can be queried with the functions -described below. +described below. Where it searches by default is determined by the settings found +in C<%Config::Config>, and what the value is of the PERL5LIB environment variable. =head1 FUNCTIONS @@ -276,8 +327,35 @@ described below. =item new() -This takes no parameters, and searches for all the installed .packlists on the -system. The packlists are read using the ExtUtils::packlist module. +This takes optional named parameters. Without parameters, this +searches for all the installed .packlists on the system using +information from C<%Config::Config> and the default module search +paths C<@INC>. The packlists are read using the +L<ExtUtils::Packlist> module. + +If the named parameter C<config_override> is specified, +it should be a reference to a hash which contains all information +usually found in C<%Config::Config>. For example, you can obtain +the configuration information for a separate perl installation and +pass that in. + + my $yoda_cfg = get_fake_config('yoda'); + my $yoda_inst = ExtUtils::Installed->new(config_override=>$yoda_cfg); + +Similarly, the parameter C<inc_override> may be a reference to an +array which is used in place of the default module search paths +from C<@INC>. + + use Config; + my @dirs = split(/\Q$Config{path_sep}\E/, $ENV{PERL5LIB}); + my $p5libs = ExtUtils::Installed->new(inc_override=>\@dirs); + +The parameter c<extra_libs> can be used to specify B<additional> paths to +search for installed modules. For instance + + my $installed = ExtUtils::Installed->new(extra_libs=>["/my/lib/path"]); + +This should only be necessary if C</my/lib/path> is not in PERL5LIB. =item modules() diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Liblist/Kid.pm b/gnu/usr.bin/perl/lib/ExtUtils/Liblist/Kid.pm index d67aa01963b..bef182b1bde 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Liblist/Kid.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Liblist/Kid.pm @@ -10,7 +10,7 @@ use 5.00503; use strict; use vars qw($VERSION); -$VERSION = 1.30; +$VERSION = 6.42; use Config; use Cwd 'cwd'; @@ -376,9 +376,7 @@ sub _vms_ext { $verbose ||= 0; my(@crtls,$crtlstr); - my($dbgqual) = $self->{OPTIMIZE} || $Config{'optimize'} || - $self->{CCFLAGS} || $Config{'ccflags'}; - @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + @crtls = ( ($Config{'ldflags'} =~ m-/Debug-i ? $Config{'dbgprefix'} : '') . 'PerlShr/Share' ); push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); @@ -390,7 +388,7 @@ sub _vms_ext { if ($self->{PERL_SRC}) { my($lib,$locspec,$type); foreach $lib (@crtls) { - if (($locspec,$type) = $lib =~ m-^([\w$\-]+)(/\w+)?- and $locspec =~ /perl/i) { + if (($locspec,$type) = $lib =~ m{^([\w\$-]+)(/\w+)?} and $locspec =~ /perl/i) { if (lc $type eq '/share') { $locspec .= $Config{'exe_ext'}; } elsif (lc $type eq '/library') { $locspec .= $Config{'lib_ext'}; } else { $locspec .= $Config{'obj_ext'}; } diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM.pm index 8aaa55f15f2..546b76dbcc1 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM.pm @@ -3,7 +3,7 @@ package ExtUtils::MM; use strict; use ExtUtils::MakeMaker::Config; use vars qw(@ISA $VERSION); -$VERSION = '0.05'; +$VERSION = '6.42'; require ExtUtils::Liblist; require ExtUtils::MakeMaker; @@ -43,12 +43,19 @@ away. sub DESTROY {} } +sub _is_win95 { + # miniperl might not have the Win32 functions available and we need + # to run in miniperl. + return defined &Win32::IsWin95 ? Win32::IsWin95() + : ! defined $ENV{SYSTEMROOT}; +} + my %Is = (); $Is{VMS} = $^O eq 'VMS'; $Is{OS2} = $^O eq 'os2'; $Is{MacOS} = $^O eq 'MacOS'; if( $^O eq 'MSWin32' ) { - Win32::IsWin95() ? $Is{Win95} = 1 : $Is{Win32} = 1; + _is_win95() ? $Is{Win95} = 1 : $Is{Win32} = 1; } $Is{UWIN} = $^O =~ /^uwin(-nt)?$/; $Is{Cygwin} = $^O eq 'cygwin'; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_AIX.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_AIX.pm index 7de7da557e0..f847303bae8 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_AIX.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_AIX.pm @@ -2,7 +2,7 @@ package ExtUtils::MM_AIX; use strict; use vars qw($VERSION @ISA); -$VERSION = '0.03'; +$VERSION = '6.42'; require ExtUtils::MM_Unix; @ISA = qw(ExtUtils::MM_Unix); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_BeOS.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_BeOS.pm index 6d93ad4c7a6..d7812b3f91e 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_BeOS.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_BeOS.pm @@ -1,5 +1,7 @@ package ExtUtils::MM_BeOS; +use strict; + =head1 NAME ExtUtils::MM_BeOS - methods to override UN*X behaviour in ExtUtils::MakeMaker @@ -16,7 +18,7 @@ the semantics. =over 4 -=cut +=cut use ExtUtils::MakeMaker::Config; use File::Spec; @@ -25,7 +27,7 @@ require ExtUtils::MM_Unix; use vars qw(@ISA $VERSION); @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); -$VERSION = '1.05'; +$VERSION = '6.42'; =item os_flavor diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_Cygwin.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_Cygwin.pm index adb8d42047a..ca4d58d9ec6 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_Cygwin.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_Cygwin.pm @@ -10,7 +10,7 @@ require ExtUtils::MM_Any; require ExtUtils::MM_Unix; @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); -$VERSION = '1.08'; +$VERSION = '6.42'; =head1 NAME diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_DOS.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_DOS.pm index b985d00ca69..f47a72d1eff 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_DOS.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_DOS.pm @@ -3,7 +3,7 @@ package ExtUtils::MM_DOS; use strict; use vars qw($VERSION @ISA); -$VERSION = 0.02; +$VERSION = 6.42; require ExtUtils::MM_Any; require ExtUtils::MM_Unix; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_MacOS.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_MacOS.pm index de578f8be3f..32d5ffed5d1 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_MacOS.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_MacOS.pm @@ -1,6 +1,9 @@ package ExtUtils::MM_MacOS; -$VERSION = 1.08; +use strict; + +use vars qw($VERSION); +$VERSION = 6.42; sub new { die <<'UNSUPPORTED'; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_NW5.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_NW5.pm index 6d9c492000f..222008a7fb8 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_NW5.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_NW5.pm @@ -23,7 +23,7 @@ use ExtUtils::MakeMaker::Config; use File::Basename; use vars qw(@ISA $VERSION); -$VERSION = '2.08'; +$VERSION = '6.42'; require ExtUtils::MM_Win32; @ISA = qw(ExtUtils::MM_Win32); @@ -34,7 +34,6 @@ $ENV{EMXSHELL} = 'sh'; # to run `commands` my $BORLAND = $Config{'cc'} =~ /^bcc/i; my $GCC = $Config{'cc'} =~ /^gcc/i; -my $DMAKE = $Config{'make'} =~ /^dmake/i; =item os_flavor diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_QNX.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_QNX.pm index d975289eee9..98009bfc3ec 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_QNX.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_QNX.pm @@ -2,7 +2,7 @@ package ExtUtils::MM_QNX; use strict; use vars qw($VERSION @ISA); -$VERSION = '0.02'; +$VERSION = '6.42'; require ExtUtils::MM_Unix; @ISA = qw(ExtUtils::MM_Unix); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_UWIN.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_UWIN.pm index 1667d552c8f..6be793010f0 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_UWIN.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_UWIN.pm @@ -2,7 +2,7 @@ package ExtUtils::MM_UWIN; use strict; use vars qw($VERSION @ISA); -$VERSION = 0.02; +$VERSION = 6.42; require ExtUtils::MM_Unix; @ISA = qw(ExtUtils::MM_Unix); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_VOS.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_VOS.pm index 82f71ca2860..171a8b727eb 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_VOS.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_VOS.pm @@ -2,7 +2,7 @@ package ExtUtils::MM_VOS; use strict; use vars qw($VERSION @ISA); -$VERSION = '0.02'; +$VERSION = '6.42'; require ExtUtils::MM_Unix; @ISA = qw(ExtUtils::MM_Unix); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MM_Win95.pm b/gnu/usr.bin/perl/lib/ExtUtils/MM_Win95.pm index d0e2cb2af32..7dbdee63324 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MM_Win95.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MM_Win95.pm @@ -1,7 +1,9 @@ package ExtUtils::MM_Win95; +use strict; + use vars qw($VERSION @ISA); -$VERSION = '0.04'; +$VERSION = '6.42'; require ExtUtils::MM_Win32; @ISA = qw(ExtUtils::MM_Win32); @@ -22,7 +24,7 @@ ExtUtils::MM_Win95 - method to customize MakeMaker for Win9X This is a subclass of ExtUtils::MM_Win32 containing changes necessary to get MakeMaker playing nice with command.com and other Win9Xisms. -=head2 Overriden methods +=head2 Overridden methods Most of these make up for limitations in the Win9x/nmake command shell. Mostly its lack of &&. diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MY.pm b/gnu/usr.bin/perl/lib/ExtUtils/MY.pm index 97ef42a15a3..d8de9aa7507 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MY.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MY.pm @@ -4,7 +4,7 @@ use strict; require ExtUtils::MM; use vars qw(@ISA $VERSION); -$VERSION = 0.01; +$VERSION = 6.42; @ISA = qw(ExtUtils::MM); { diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/Config.pm b/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/Config.pm index 52ae800f782..65f9d474750 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/Config.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/Config.pm @@ -1,6 +1,6 @@ package ExtUtils::MakeMaker::Config; -$VERSION = '0.02'; +$VERSION = '6.42'; use strict; use Config (); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/bytes.pm b/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/bytes.pm index 5a2bf75f20e..41ae2077a8d 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/bytes.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/bytes.pm @@ -1,7 +1,9 @@ package ExtUtils::MakeMaker::bytes; +use strict; + use vars qw($VERSION); -$VERSION = 0.01; +$VERSION = 6.42; my $Have_Bytes = eval q{require bytes; 1;}; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/vmsish.pm b/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/vmsish.pm index 3380956e05c..f3d0ac8cf70 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/vmsish.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/MakeMaker/vmsish.pm @@ -1,7 +1,9 @@ package ExtUtils::MakeMaker::vmsish; +use strict; + use vars qw($VERSION); -$VERSION = 0.01; +$VERSION = 6.42; my $IsVMS = $^O eq 'VMS'; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/PATCHING b/gnu/usr.bin/perl/lib/ExtUtils/PATCHING index 30cb21f0449..eed536a9945 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/PATCHING +++ b/gnu/usr.bin/perl/lib/ExtUtils/PATCHING @@ -1,3 +1,8 @@ +"The easy way is always mined. + The important things are always simple. + The simple things are always hard." + -- Some of Murphy's Laws of Combat + This is a short set of guidelines for those patching ExtUtils::MakeMaker. Its not an iron-clad set of rules, but just things which make life easier when reading and integrating a patch. @@ -101,7 +106,7 @@ Backwards Compatibility - MakeMaker must be backwards compatible to 5.5.4 (5.005_04). Avoid any obvious 5.6-isms (threads, warnings.pm, Unicode, our, v1.2.3, attributes - open my $fh, lvalue subroutines, any new core modules, etc...). + open my $fh, lvalue subroutines, qr//, any new core modules, etc...). - MakeMaker should avoid having module dependencies. Avoid using modules which didn't come with 5.5.4 and avoid using features from newer @@ -121,18 +126,26 @@ Cross-Platform Compatibility and MMK to name the most common. Keep your make code as simple as possible. -- Avoid special variables (even $@). +- Avoid special make variables (even $@). - Format targets as "target : dependency", the spacing is important. - Use $(NOECHO) instead of @. +- Use - to tell make to ignore the exit code of a command. (Unfortunately, + some make variants don't honor an $(IGNORE) macro). + - Always put a space between $(NOECHO) and the command. - Always put a space between - (ignore) and the command. - Always put $(NOECHO) and - together, no space between them. + # Right + -$(NOECHO) command + $(NOECHO) command + - command + - Often when you patch ExtUtils::MM_Unix, similar patches must be done to the other MM_* modules. If you can, please do this extra work otherwise I have to. If you can't, that's ok. We can help. diff --git a/gnu/usr.bin/perl/lib/ExtUtils/Packlist.pm b/gnu/usr.bin/perl/lib/ExtUtils/Packlist.pm index 11ab637150b..04f267a0a3d 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/Packlist.pm +++ b/gnu/usr.bin/perl/lib/ExtUtils/Packlist.pm @@ -3,12 +3,22 @@ package ExtUtils::Packlist; use 5.00503; use strict; use Carp qw(); -use vars qw($VERSION); -$VERSION = '0.04'; +use Config; +use vars qw($VERSION $Relocations); +$VERSION = '1.43'; +$VERSION = eval $VERSION; # Used for generating filehandle globs. IO::File might not be available! my $fhname = "FH1"; +=begin _undocumented + +=item mkfh() + +Make a filehandle. Same kind of idea as Symbol::gensym(). + +=cut + sub mkfh() { no strict; @@ -17,6 +27,30 @@ use strict; return($fh); } +=item __find_relocations + +Works out what absolute paths in the configuration have been located at run +time relative to $^X, and generates a regexp that matches them + +=end _undocumented + +=cut + +sub __find_relocations +{ + my %paths; + while (my ($raw_key, $raw_val) = each %Config) { + my $exp_key = $raw_key . "exp"; + next unless exists $Config{$exp_key}; + next unless $raw_val =~ m!\.\.\./!; + $paths{$Config{$exp_key}}++; + } + # Longest prefixes go first in the alternatives + my $alternations = join "|", map {quotemeta $_} + sort {length $b <=> length $a} keys %paths; + qr/^($alternations)/o; +} + sub new($$) { my ($class, $packfile) = @_; @@ -90,28 +124,24 @@ my ($line); while (defined($line = <$fh>)) { chomp $line; - my ($key, @kvs) = $line; + my ($key, $data) = $line; if ($key =~ /^(.*?)( \w+=.*)$/) { $key = $1; - @kvs = split(' ', $2); - } - $key =~ s!/\./!/!g; # Some .packlists have spurious '/./' bits in the paths - if (! @kvs) + $data = { map { split('=', $_) } split(' ', $2)}; + + if ($Config{userelocatableinc} && $data->{relocate_as}) { - $self->{data}->{$key} = undef; + require File::Spec; + require Cwd; + my ($vol, $dir) = File::Spec->splitpath($packfile); + my $newpath = File::Spec->catpath($vol, $dir, $data->{relocate_as}); + $key = Cwd::realpath($newpath); } - else - { - my ($data) = {}; - foreach my $kv (@kvs) - { - my ($k, $v) = split('=', $kv); - $data->{$k} = $v; } + $key =~ s!/\./!/!g; # Some .packlists have spurious '/./' bits in the paths $self->{data}->{$key} = $data; } - } close($fh); } @@ -126,10 +156,33 @@ my $fh = mkfh(); open($fh, ">$packfile") || Carp::croak("Can't open file $packfile: $!"); foreach my $key (sort(keys(%{$self->{data}}))) { + my $data = $self->{data}->{$key}; + if ($Config{userelocatableinc}) { + $Relocations ||= __find_relocations(); + if ($packfile =~ $Relocations) { + # We are writing into a subdirectory of a run-time relocated + # path. Figure out if the this file is also within a subdir. + my $prefix = $1; + if (File::Spec->no_upwards(File::Spec->abs2rel($key, $prefix))) + { + # The relocated path is within the found prefix + my $packfile_prefix; + (undef, $packfile_prefix) + = File::Spec->splitpath($packfile); + + my $relocate_as + = File::Spec->abs2rel($key, $packfile_prefix); + + if (!ref $data) { + $data = {}; + } + $data->{relocate_as} = $relocate_as; + } + } + } print $fh ("$key"); - if (ref($self->{data}->{$key})) + if (ref($data)) { - my $data = $self->{data}->{$key}; foreach my $k (sort(keys(%$data))) { print $fh (" $k=$data->{$k}"); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/ParseXS.pm b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS.pm new file mode 100644 index 00000000000..221d5a43b82 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS.pm @@ -0,0 +1,2052 @@ +package ExtUtils::ParseXS; + +use 5.006; # We use /??{}/ in regexes +use Cwd; +use Config; +use File::Basename; +use File::Spec; +use Symbol; + +require Exporter; + +@ISA = qw(Exporter); +@EXPORT_OK = qw(process_file); + +# use strict; # One of these days... + +my(@XSStack); # Stack of conditionals and INCLUDEs +my($XSS_work_idx, $cpp_next_tmp); + +use vars qw($VERSION); +$VERSION = '2.18_02'; + +use vars qw(%input_expr %output_expr $ProtoUsed @InitFileCode $FH $proto_re $Overload $errors $Fallback + $cplusplus $hiertype $WantPrototypes $WantVersionChk $except $WantLineNumbers + $WantOptimize $process_inout $process_argtypes @tm + $dir $filename $filepathname %IncludedFiles + %type_kind %proto_letter + %targetable $BLOCK_re $lastline $lastline_no + $Package $Prefix @line @BootCode %args_match %defaults %var_types %arg_list @proto_arg + $processing_arg_with_types %argtype_seen @outlist %in_out %lengthof + $proto_in_this_xsub $scope_in_this_xsub $interface $prepush_done $interface_macro $interface_macro_set + $ProtoThisXSUB $ScopeThisXSUB $xsreturn + @line_no $ret_type $func_header $orig_args + ); # Add these just to get compilation to happen. + + +sub process_file { + + # Allow for $package->process_file(%hash) in the future + my ($pkg, %args) = @_ % 2 ? @_ : (__PACKAGE__, @_); + + $ProtoUsed = exists $args{prototypes}; + + # Set defaults. + %args = ( + # 'C++' => 0, # Doesn't seem to *do* anything... + hiertype => 0, + except => 0, + prototypes => 0, + versioncheck => 1, + linenumbers => 1, + optimize => 1, + prototypes => 0, + inout => 1, + argtypes => 1, + typemap => [], + output => \*STDOUT, + csuffix => '.c', + %args, + ); + + # Global Constants + + my ($Is_VMS, $SymSet); + if ($^O eq 'VMS') { + $Is_VMS = 1; + # Establish set of global symbols with max length 28, since xsubpp + # will later add the 'XS_' prefix. + require ExtUtils::XSSymSet; + $SymSet = new ExtUtils::XSSymSet 28; + } + @XSStack = ({type => 'none'}); + ($XSS_work_idx, $cpp_next_tmp) = (0, "XSubPPtmpAAAA"); + @InitFileCode = (); + $FH = Symbol::gensym(); + $proto_re = "[" . quotemeta('\$%&*@;[]') . "]" ; + $Overload = 0; + $errors = 0; + $Fallback = 'PL_sv_undef'; + + # Most of the 1500 lines below uses these globals. We'll have to + # clean this up sometime, probably. For now, we just pull them out + # of %args. -Ken + + $cplusplus = $args{'C++'}; + $hiertype = $args{hiertype}; + $WantPrototypes = $args{prototypes}; + $WantVersionChk = $args{versioncheck}; + $except = $args{except} ? ' TRY' : ''; + $WantLineNumbers = $args{linenumbers}; + $WantOptimize = $args{optimize}; + $process_inout = $args{inout}; + $process_argtypes = $args{argtypes}; + @tm = ref $args{typemap} ? @{$args{typemap}} : ($args{typemap}); + + for ($args{filename}) { + die "Missing required parameter 'filename'" unless $_; + $filepathname = $_; + ($dir, $filename) = (dirname($_), basename($_)); + $filepathname =~ s/\\/\\\\/g; + $IncludedFiles{$_}++; + } + + # Open the input file + open($FH, $args{filename}) or die "cannot open $args{filename}: $!\n"; + + # Open the output file if given as a string. If they provide some + # other kind of reference, trust them that we can print to it. + if (not ref $args{output}) { + open my($fh), "> $args{output}" or die "Can't create $args{output}: $!"; + $args{outfile} = $args{output}; + $args{output} = $fh; + } + + # Really, we shouldn't have to chdir() or select() in the first + # place. For now, just save & restore. + my $orig_cwd = cwd(); + my $orig_fh = select(); + + chdir($dir); + my $pwd = cwd(); + my $csuffix = $args{csuffix}; + + if ($WantLineNumbers) { + my $cfile; + if ( $args{outfile} ) { + $cfile = $args{outfile}; + } else { + $cfile = $args{filename}; + $cfile =~ s/\.xs$/$csuffix/i or $cfile .= $csuffix; + } + tie(*PSEUDO_STDOUT, 'ExtUtils::ParseXS::CountLines', $cfile, $args{output}); + select PSEUDO_STDOUT; + } else { + select $args{output}; + } + + foreach my $typemap (@tm) { + die "Can't find $typemap in $pwd\n" unless -r $typemap; + } + + push @tm, standard_typemap_locations(); + + foreach my $typemap (@tm) { + next unless -f $typemap ; + # skip directories, binary files etc. + warn("Warning: ignoring non-text typemap file '$typemap'\n"), next + unless -T $typemap ; + open(TYPEMAP, $typemap) + or warn ("Warning: could not open typemap file '$typemap': $!\n"), next; + my $mode = 'Typemap'; + my $junk = "" ; + my $current = \$junk; + while (<TYPEMAP>) { + next if /^\s* #/; + my $line_no = $. + 1; + if (/^INPUT\s*$/) { + $mode = 'Input'; $current = \$junk; next; + } + if (/^OUTPUT\s*$/) { + $mode = 'Output'; $current = \$junk; next; + } + if (/^TYPEMAP\s*$/) { + $mode = 'Typemap'; $current = \$junk; next; + } + if ($mode eq 'Typemap') { + chomp; + my $line = $_ ; + TrimWhitespace($_) ; + # skip blank lines and comment lines + next if /^$/ or /^#/ ; + my($type,$kind, $proto) = /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or + warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next; + $type = TidyType($type) ; + $type_kind{$type} = $kind ; + # prototype defaults to '$' + $proto = "\$" unless $proto ; + warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n") + unless ValidProtoString($proto) ; + $proto_letter{$type} = C_string($proto) ; + } elsif (/^\s/) { + $$current .= $_; + } elsif ($mode eq 'Input') { + s/\s+$//; + $input_expr{$_} = ''; + $current = \$input_expr{$_}; + } else { + s/\s+$//; + $output_expr{$_} = ''; + $current = \$output_expr{$_}; + } + } + close(TYPEMAP); + } + + foreach my $value (values %input_expr) { + $value =~ s/;*\s+\z//; + # Move C pre-processor instructions to column 1 to be strictly ANSI + # conformant. Some pre-processors are fussy about this. + $value =~ s/^\s+#/#/mg; + } + foreach my $value (values %output_expr) { + # And again. + $value =~ s/^\s+#/#/mg; + } + + my ($cast, $size); + our $bal = qr[(?:(?>[^()]+)|\((??{ $bal })\))*]; # ()-balanced + $cast = qr[(?:\(\s*SV\s*\*\s*\)\s*)?]; # Optional (SV*) cast + $size = qr[,\s* (??{ $bal }) ]x; # Third arg (to setpvn) + + foreach my $key (keys %output_expr) { + BEGIN { $^H |= 0x00200000 }; # Equivalent to: use re 'eval', but hardcoded so we can compile re.xs + + my ($t, $with_size, $arg, $sarg) = + ($output_expr{$key} =~ + m[^ \s+ sv_set ( [iunp] ) v (n)? # Type, is_setpvn + \s* \( \s* $cast \$arg \s* , + \s* ( (??{ $bal }) ) # Set from + ( (??{ $size }) )? # Possible sizeof set-from + \) \s* ; \s* $ + ]x); + $targetable{$key} = [$t, $with_size, $arg, $sarg] if $t; + } + + my $END = "!End!\n\n"; # "impossible" keyword (multiple newline) + + # Match an XS keyword + $BLOCK_re= '\s*(' . join('|', qw( + REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT + CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE + SCOPE INTERFACE INTERFACE_MACRO C_ARGS POSTCALL OVERLOAD FALLBACK + )) . "|$END)\\s*:"; + + + our ($C_group_rex, $C_arg); + # Group in C (no support for comments or literals) + $C_group_rex = qr/ [({\[] + (?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )* + [)}\]] /x ; + # Chunk in C without comma at toplevel (no comments): + $C_arg = qr/ (?: (?> [^()\[\]{},"']+ ) + | (??{ $C_group_rex }) + | " (?: (?> [^\\"]+ ) + | \\. + )* " # String literal + | ' (?: (?> [^\\']+ ) | \\. )* ' # Char literal + )* /xs; + + # Identify the version of xsubpp used + print <<EOM ; +/* + * This file was generated automatically by ExtUtils::ParseXS version $VERSION from the + * contents of $filename. Do not edit this file, edit $filename instead. + * + * ANY CHANGES MADE HERE WILL BE LOST! + * + */ + +EOM + + + print("#line 1 \"$filepathname\"\n") + if $WantLineNumbers; + + firstmodule: + while (<$FH>) { + if (/^=/) { + my $podstartline = $.; + do { + if (/^=cut\s*$/) { + # We can't just write out a /* */ comment, as our embedded + # POD might itself be in a comment. We can't put a /**/ + # comment inside #if 0, as the C standard says that the source + # file is decomposed into preprocessing characters in the stage + # before preprocessing commands are executed. + # I don't want to leave the text as barewords, because the spec + # isn't clear whether macros are expanded before or after + # preprocessing commands are executed, and someone pathological + # may just have defined one of the 3 words as a macro that does + # something strange. Multiline strings are illegal in C, so + # the "" we write must be a string literal. And they aren't + # concatenated until 2 steps later, so we are safe. + # - Nicholas Clark + print("#if 0\n \"Skipped embedded POD.\"\n#endif\n"); + printf("#line %d \"$filepathname\"\n", $. + 1) + if $WantLineNumbers; + next firstmodule + } + + } while (<$FH>); + # At this point $. is at end of file so die won't state the start + # of the problem, and as we haven't yet read any lines &death won't + # show the correct line in the message either. + die ("Error: Unterminated pod in $filename, line $podstartline\n") + unless $lastline; + } + last if ($Package, $Prefix) = + /^MODULE\s*=\s*[\w:]+(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/; + + print $_; + } + unless (defined $_) { + warn "Didn't find a 'MODULE ... PACKAGE ... PREFIX' line\n"; + exit 0; # Not a fatal error for the caller process + } + + print <<"EOF"; +#ifndef PERL_UNUSED_VAR +# define PERL_UNUSED_VAR(var) if (0) var = var +#endif + +EOF + + print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $WantLineNumbers; + + $lastline = $_; + $lastline_no = $.; + + PARAGRAPH: + while (fetch_para()) { + # Print initial preprocessor statements and blank lines + while (@line && $line[0] !~ /^[^\#]/) { + my $line = shift(@line); + print $line, "\n"; + next unless $line =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/; + my $statement = $+; + if ($statement eq 'if') { + $XSS_work_idx = @XSStack; + push(@XSStack, {type => 'if'}); + } else { + death ("Error: `$statement' with no matching `if'") + if $XSStack[-1]{type} ne 'if'; + if ($XSStack[-1]{varname}) { + push(@InitFileCode, "#endif\n"); + push(@BootCode, "#endif"); + } + + my(@fns) = keys %{$XSStack[-1]{functions}}; + if ($statement ne 'endif') { + # Hide the functions defined in other #if branches, and reset. + @{$XSStack[-1]{other_functions}}{@fns} = (1) x @fns; + @{$XSStack[-1]}{qw(varname functions)} = ('', {}); + } else { + my($tmp) = pop(@XSStack); + 0 while (--$XSS_work_idx + && $XSStack[$XSS_work_idx]{type} ne 'if'); + # Keep all new defined functions + push(@fns, keys %{$tmp->{other_functions}}); + @{$XSStack[$XSS_work_idx]{functions}}{@fns} = (1) x @fns; + } + } + } + + next PARAGRAPH unless @line; + + if ($XSS_work_idx && !$XSStack[$XSS_work_idx]{varname}) { + # We are inside an #if, but have not yet #defined its xsubpp variable. + print "#define $cpp_next_tmp 1\n\n"; + push(@InitFileCode, "#if $cpp_next_tmp\n"); + push(@BootCode, "#if $cpp_next_tmp"); + $XSStack[$XSS_work_idx]{varname} = $cpp_next_tmp++; + } + + death ("Code is not inside a function" + ." (maybe last function was ended by a blank line " + ." followed by a statement on column one?)") + if $line[0] =~ /^\s/; + + my ($class, $externC, $static, $ellipsis, $wantRETVAL, $RETVAL_no_return); + my (@fake_INPUT_pre); # For length(s) generated variables + my (@fake_INPUT); + + # initialize info arrays + undef(%args_match); + undef(%var_types); + undef(%defaults); + undef(%arg_list) ; + undef(@proto_arg) ; + undef($processing_arg_with_types) ; + undef(%argtype_seen) ; + undef(@outlist) ; + undef(%in_out) ; + undef(%lengthof) ; + undef($proto_in_this_xsub) ; + undef($scope_in_this_xsub) ; + undef($interface); + undef($prepush_done); + $interface_macro = 'XSINTERFACE_FUNC' ; + $interface_macro_set = 'XSINTERFACE_FUNC_SET' ; + $ProtoThisXSUB = $WantPrototypes ; + $ScopeThisXSUB = 0; + $xsreturn = 0; + + $_ = shift(@line); + while (my $kwd = check_keyword("REQUIRE|PROTOTYPES|FALLBACK|VERSIONCHECK|INCLUDE")) { + &{"${kwd}_handler"}() ; + next PARAGRAPH unless @line ; + $_ = shift(@line); + } + + if (check_keyword("BOOT")) { + &check_cpp; + push (@BootCode, "#line $line_no[@line_no - @line] \"$filepathname\"") + if $WantLineNumbers && $line[0] !~ /^\s*#\s*line\b/; + push (@BootCode, @line, "") ; + next PARAGRAPH ; + } + + + # extract return type, function name and arguments + ($ret_type) = TidyType($_); + $RETVAL_no_return = 1 if $ret_type =~ s/^NO_OUTPUT\s+//; + + # Allow one-line ANSI-like declaration + unshift @line, $2 + if $process_argtypes + and $ret_type =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s; + + # a function definition needs at least 2 lines + blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH + unless @line ; + + $externC = 1 if $ret_type =~ s/^extern "C"\s+//; + $static = 1 if $ret_type =~ s/^static\s+//; + + $func_header = shift(@line); + blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH + unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*(;\s*)?$/s; + + ($class, $func_name, $orig_args) = ($1, $2, $3) ; + $class = "$4 $class" if $4; + ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/; + ($clean_func_name = $func_name) =~ s/^$Prefix//; + $Full_func_name = "${Packid}_$clean_func_name"; + if ($Is_VMS) { + $Full_func_name = $SymSet->addsym($Full_func_name); + } + + # Check for duplicate function definition + for my $tmp (@XSStack) { + next unless defined $tmp->{functions}{$Full_func_name}; + Warn("Warning: duplicate function definition '$clean_func_name' detected"); + last; + } + $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ; + %XsubAliases = %XsubAliasValues = %Interfaces = @Attributes = (); + $DoSetMagic = 1; + + $orig_args =~ s/\\\s*/ /g; # process line continuations + my @args; + + my %only_C_inlist; # Not in the signature of Perl function + if ($process_argtypes and $orig_args =~ /\S/) { + my $args = "$orig_args ,"; + if ($args =~ /^( (??{ $C_arg }) , )* $ /x) { + @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg); + for ( @args ) { + s/^\s+//; + s/\s+$//; + my ($arg, $default) = / ( [^=]* ) ( (?: = .* )? ) /x; + my ($pre, $name) = ($arg =~ /(.*?) \s* + \b ( \w+ | length\( \s*\w+\s* \) ) + \s* $ /x); + next unless defined($pre) && length($pre); + my $out_type = ''; + my $inout_var; + if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//) { + my $type = $1; + $out_type = $type if $type ne 'IN'; + $arg =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//; + $pre =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//; + } + my $islength; + if ($name =~ /^length\( \s* (\w+) \s* \)\z/x) { + $name = "XSauto_length_of_$1"; + $islength = 1; + die "Default value on length() argument: `$_'" + if length $default; + } + if (length $pre or $islength) { # Has a type + if ($islength) { + push @fake_INPUT_pre, $arg; + } else { + push @fake_INPUT, $arg; + } + # warn "pushing '$arg'\n"; + $argtype_seen{$name}++; + $_ = "$name$default"; # Assigns to @args + } + $only_C_inlist{$_} = 1 if $out_type eq "OUTLIST" or $islength; + push @outlist, $name if $out_type =~ /OUTLIST$/; + $in_out{$name} = $out_type if $out_type; + } + } else { + @args = split(/\s*,\s*/, $orig_args); + Warn("Warning: cannot parse argument list '$orig_args', fallback to split"); + } + } else { + @args = split(/\s*,\s*/, $orig_args); + for (@args) { + if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|IN_OUT|OUT)\s+//) { + my $out_type = $1; + next if $out_type eq 'IN'; + $only_C_inlist{$_} = 1 if $out_type eq "OUTLIST"; + push @outlist, $name if $out_type =~ /OUTLIST$/; + $in_out{$_} = $out_type; + } + } + } + if (defined($class)) { + my $arg0 = ((defined($static) or $func_name eq 'new') + ? "CLASS" : "THIS"); + unshift(@args, $arg0); + ($report_args = "$arg0, $report_args") =~ s/^\w+, $/$arg0/; + } + my $extra_args = 0; + @args_num = (); + $num_args = 0; + my $report_args = ''; + foreach my $i (0 .. $#args) { + if ($args[$i] =~ s/\.\.\.//) { + $ellipsis = 1; + if ($args[$i] eq '' && $i == $#args) { + $report_args .= ", ..."; + pop(@args); + last; + } + } + if ($only_C_inlist{$args[$i]}) { + push @args_num, undef; + } else { + push @args_num, ++$num_args; + $report_args .= ", $args[$i]"; + } + if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) { + $extra_args++; + $args[$i] = $1; + $defaults{$args[$i]} = $2; + $defaults{$args[$i]} =~ s/"/\\"/g; + } + $proto_arg[$i+1] = '$' ; + } + $min_args = $num_args - $extra_args; + $report_args =~ s/"/\\"/g; + $report_args =~ s/^,\s+//; + my @func_args = @args; + shift @func_args if defined($class); + + for (@func_args) { + s/^/&/ if $in_out{$_}; + } + $func_args = join(", ", @func_args); + @args_match{@args} = @args_num; + + $PPCODE = grep(/^\s*PPCODE\s*:/, @line); + $CODE = grep(/^\s*CODE\s*:/, @line); + # Detect CODE: blocks which use ST(n)= or XST_m*(n,v) + # to set explicit return values. + $EXPLICIT_RETURN = ($CODE && + ("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x )); + $ALIAS = grep(/^\s*ALIAS\s*:/, @line); + $INTERFACE = grep(/^\s*INTERFACE\s*:/, @line); + + $xsreturn = 1 if $EXPLICIT_RETURN; + + $externC = $externC ? qq[extern "C"] : ""; + + # print function header + print Q(<<"EOF"); +#$externC +#XS(XS_${Full_func_name}); /* prototype to pass -Wmissing-prototypes */ +#XS(XS_${Full_func_name}) +#[[ +##ifdef dVAR +# dVAR; dXSARGS; +##else +# dXSARGS; +##endif +EOF + print Q(<<"EOF") if $ALIAS ; +# dXSI32; +EOF + print Q(<<"EOF") if $INTERFACE ; +# dXSFUNCTION($ret_type); +EOF + if ($ellipsis) { + $cond = ($min_args ? qq(items < $min_args) : 0); + } elsif ($min_args == $num_args) { + $cond = qq(items != $min_args); + } else { + $cond = qq(items < $min_args || items > $num_args); + } + + print Q(<<"EOF") if $except; +# char errbuf[1024]; +# *errbuf = '\0'; +EOF + + if ($ALIAS) + { print Q(<<"EOF") if $cond } +# if ($cond) +# Perl_croak(aTHX_ "Usage: %s(%s)", GvNAME(CvGV(cv)), "$report_args"); +EOF + else + { print Q(<<"EOF") if $cond } +# if ($cond) +# Perl_croak(aTHX_ "Usage: %s(%s)", "$pname", "$report_args"); +EOF + + # cv doesn't seem to be used, in most cases unless we go in + # the if of this else + print Q(<<"EOF"); +# PERL_UNUSED_VAR(cv); /* -W */ +EOF + + #gcc -Wall: if an xsub has PPCODE is used + #it is possible none of ST, XSRETURN or XSprePUSH macros are used + #hence `ax' (setup by dXSARGS) is unused + #XXX: could breakup the dXSARGS; into dSP;dMARK;dITEMS + #but such a move could break third-party extensions + print Q(<<"EOF") if $PPCODE; +# PERL_UNUSED_VAR(ax); /* -Wall */ +EOF + + print Q(<<"EOF") if $PPCODE; +# SP -= items; +EOF + + # Now do a block of some sort. + + $condnum = 0; + $cond = ''; # last CASE: condidional + push(@line, "$END:"); + push(@line_no, $line_no[-1]); + $_ = ''; + &check_cpp; + while (@line) { + &CASE_handler if check_keyword("CASE"); + print Q(<<"EOF"); +# $except [[ +EOF + + # do initialization of input variables + $thisdone = 0; + $retvaldone = 0; + $deferred = ""; + %arg_list = () ; + $gotRETVAL = 0; + + INPUT_handler() ; + process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE|OVERLOAD") ; + + print Q(<<"EOF") if $ScopeThisXSUB; +# ENTER; +# [[ +EOF + + if (!$thisdone && defined($class)) { + if (defined($static) or $func_name eq 'new') { + print "\tchar *"; + $var_types{"CLASS"} = "char *"; + &generate_init("char *", 1, "CLASS"); + } + else { + print "\t$class *"; + $var_types{"THIS"} = "$class *"; + &generate_init("$class *", 1, "THIS"); + } + } + + # do code + if (/^\s*NOT_IMPLEMENTED_YET/) { + print "\n\tPerl_croak(aTHX_ \"$pname: not implemented yet\");\n"; + $_ = '' ; + } else { + if ($ret_type ne "void") { + print "\t" . &map_type($ret_type, 'RETVAL') . ";\n" + if !$retvaldone; + $args_match{"RETVAL"} = 0; + $var_types{"RETVAL"} = $ret_type; + print "\tdXSTARG;\n" + if $WantOptimize and $targetable{$type_kind{$ret_type}}; + } + + if (@fake_INPUT or @fake_INPUT_pre) { + unshift @line, @fake_INPUT_pre, @fake_INPUT, $_; + $_ = ""; + $processing_arg_with_types = 1; + INPUT_handler() ; + } + print $deferred; + + process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS|OVERLOAD") ; + + if (check_keyword("PPCODE")) { + print_section(); + death ("PPCODE must be last thing") if @line; + print "\tLEAVE;\n" if $ScopeThisXSUB; + print "\tPUTBACK;\n\treturn;\n"; + } elsif (check_keyword("CODE")) { + print_section() ; + } elsif (defined($class) and $func_name eq "DESTROY") { + print "\n\t"; + print "delete THIS;\n"; + } else { + print "\n\t"; + if ($ret_type ne "void") { + print "RETVAL = "; + $wantRETVAL = 1; + } + if (defined($static)) { + if ($func_name eq 'new') { + $func_name = "$class"; + } else { + print "${class}::"; + } + } elsif (defined($class)) { + if ($func_name eq 'new') { + $func_name .= " $class"; + } else { + print "THIS->"; + } + } + $func_name =~ s/^\Q$args{'s'}// + if exists $args{'s'}; + $func_name = 'XSFUNCTION' if $interface; + print "$func_name($func_args);\n"; + } + } + + # do output variables + $gotRETVAL = 0; # 1 if RETVAL seen in OUTPUT section; + undef $RETVAL_code ; # code to set RETVAL (from OUTPUT section); + # $wantRETVAL set if 'RETVAL =' autogenerated + ($wantRETVAL, $ret_type) = (0, 'void') if $RETVAL_no_return; + undef %outargs ; + process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE|OVERLOAD"); + + &generate_output($var_types{$_}, $args_match{$_}, $_, $DoSetMagic) + for grep $in_out{$_} =~ /OUT$/, keys %in_out; + + # all OUTPUT done, so now push the return value on the stack + if ($gotRETVAL && $RETVAL_code) { + print "\t$RETVAL_code\n"; + } elsif ($gotRETVAL || $wantRETVAL) { + my $t = $WantOptimize && $targetable{$type_kind{$ret_type}}; + my $var = 'RETVAL'; + my $type = $ret_type; + + # 0: type, 1: with_size, 2: how, 3: how_size + if ($t and not $t->[1] and $t->[0] eq 'p') { + # PUSHp corresponds to setpvn. Treate setpv directly + my $what = eval qq("$t->[2]"); + warn $@ if $@; + + print "\tsv_setpv(TARG, $what); XSprePUSH; PUSHTARG;\n"; + $prepush_done = 1; + } + elsif ($t) { + my $what = eval qq("$t->[2]"); + warn $@ if $@; + + my $size = $t->[3]; + $size = '' unless defined $size; + $size = eval qq("$size"); + warn $@ if $@; + print "\tXSprePUSH; PUSH$t->[0]($what$size);\n"; + $prepush_done = 1; + } + else { + # RETVAL almost never needs SvSETMAGIC() + &generate_output($ret_type, 0, 'RETVAL', 0); + } + } + + $xsreturn = 1 if $ret_type ne "void"; + my $num = $xsreturn; + my $c = @outlist; + print "\tXSprePUSH;" if $c and not $prepush_done; + print "\tEXTEND(SP,$c);\n" if $c; + $xsreturn += $c; + generate_output($var_types{$_}, $num++, $_, 0, 1) for @outlist; + + # do cleanup + process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE|OVERLOAD") ; + + print Q(<<"EOF") if $ScopeThisXSUB; +# ]] +EOF + print Q(<<"EOF") if $ScopeThisXSUB and not $PPCODE; +# LEAVE; +EOF + + # print function trailer + print Q(<<"EOF"); +# ]] +EOF + print Q(<<"EOF") if $except; +# BEGHANDLERS +# CATCHALL +# sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason); +# ENDHANDLERS +EOF + if (check_keyword("CASE")) { + blurt ("Error: No `CASE:' at top of function") + unless $condnum; + $_ = "CASE: $_"; # Restore CASE: label + next; + } + last if $_ eq "$END:"; + death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function"); + } + + print Q(<<"EOF") if $except; +# if (errbuf[0]) +# Perl_croak(aTHX_ errbuf); +EOF + + if ($xsreturn) { + print Q(<<"EOF") unless $PPCODE; +# XSRETURN($xsreturn); +EOF + } else { + print Q(<<"EOF") unless $PPCODE; +# XSRETURN_EMPTY; +EOF + } + + print Q(<<"EOF"); +#]] +# +EOF + + my $newXS = "newXS" ; + my $proto = "" ; + + # Build the prototype string for the xsub + if ($ProtoThisXSUB) { + $newXS = "newXSproto"; + + if ($ProtoThisXSUB eq 2) { + # User has specified empty prototype + } + elsif ($ProtoThisXSUB eq 1) { + my $s = ';'; + if ($min_args < $num_args) { + $s = ''; + $proto_arg[$min_args] .= ";" ; + } + push @proto_arg, "$s\@" + if $ellipsis ; + + $proto = join ("", grep defined, @proto_arg); + } + else { + # User has specified a prototype + $proto = $ProtoThisXSUB; + } + $proto = qq{, "$proto"}; + } + + if (%XsubAliases) { + $XsubAliases{$pname} = 0 + unless defined $XsubAliases{$pname} ; + while ( ($name, $value) = each %XsubAliases) { + push(@InitFileCode, Q(<<"EOF")); +# cv = newXS(\"$name\", XS_$Full_func_name, file); +# XSANY.any_i32 = $value ; +EOF + push(@InitFileCode, Q(<<"EOF")) if $proto; +# sv_setpv((SV*)cv$proto) ; +EOF + } + } + elsif (@Attributes) { + push(@InitFileCode, Q(<<"EOF")); +# cv = newXS(\"$pname\", XS_$Full_func_name, file); +# apply_attrs_string("$Package", cv, "@Attributes", 0); +EOF + } + elsif ($interface) { + while ( ($name, $value) = each %Interfaces) { + $name = "$Package\::$name" unless $name =~ /::/; + push(@InitFileCode, Q(<<"EOF")); +# cv = newXS(\"$name\", XS_$Full_func_name, file); +# $interface_macro_set(cv,$value) ; +EOF + push(@InitFileCode, Q(<<"EOF")) if $proto; +# sv_setpv((SV*)cv$proto) ; +EOF + } + } + else { + push(@InitFileCode, + " ${newXS}(\"$pname\", XS_$Full_func_name, file$proto);\n"); + } + } + + if ($Overload) # make it findable with fetchmethod + { + print Q(<<"EOF"); +#XS(XS_${Packid}_nil); /* prototype to pass -Wmissing-prototypes */ +#XS(XS_${Packid}_nil) +#{ +# XSRETURN_EMPTY; +#} +# +EOF + unshift(@InitFileCode, <<"MAKE_FETCHMETHOD_WORK"); + /* Making a sub named "${Package}::()" allows the package */ + /* to be findable via fetchmethod(), and causes */ + /* overload::Overloaded("${Package}") to return true. */ + newXS("${Package}::()", XS_${Packid}_nil, file$proto); +MAKE_FETCHMETHOD_WORK + } + + # print initialization routine + + print Q(<<"EOF"); +##ifdef __cplusplus +#extern "C" +##endif +EOF + + print Q(<<"EOF"); +#XS(boot_$Module_cname); /* prototype to pass -Wmissing-prototypes */ +#XS(boot_$Module_cname) +EOF + + print Q(<<"EOF"); +#[[ +##ifdef dVAR +# dVAR; dXSARGS; +##else +# dXSARGS; +##endif +EOF + + #-Wall: if there is no $Full_func_name there are no xsubs in this .xs + #so `file' is unused + print Q(<<"EOF") if $Full_func_name; +# char* file = __FILE__; +EOF + + print Q("#\n"); + + print Q(<<"EOF"); +# PERL_UNUSED_VAR(cv); /* -W */ +# PERL_UNUSED_VAR(items); /* -W */ +EOF + + print Q(<<"EOF") if $WantVersionChk ; +# XS_VERSION_BOOTCHECK ; +# +EOF + + print Q(<<"EOF") if defined $XsubAliases or defined $Interfaces ; +# { +# CV * cv ; +# +EOF + + print Q(<<"EOF") if ($Overload); +# /* register the overloading (type 'A') magic */ +# PL_amagic_generation++; +# /* The magic for overload gets a GV* via gv_fetchmeth as */ +# /* mentioned above, and looks in the SV* slot of it for */ +# /* the "fallback" status. */ +# sv_setsv( +# get_sv( "${Package}::()", TRUE ), +# $Fallback +# ); +EOF + + print @InitFileCode; + + print Q(<<"EOF") if defined $XsubAliases or defined $Interfaces ; +# } +EOF + + if (@BootCode) + { + print "\n /* Initialisation Section */\n\n" ; + @line = @BootCode; + print_section(); + print "\n /* End of Initialisation Section */\n\n" ; + } + + if ($] >= 5.009) { + print <<'EOF'; + if (PL_unitcheckav) + call_list(PL_scopestack_ix, PL_unitcheckav); +EOF + } + + print Q(<<"EOF"); +# XSRETURN_YES; +#]] +# +EOF + + warn("Please specify prototyping behavior for $filename (see perlxs manual)\n") + unless $ProtoUsed ; + + chdir($orig_cwd); + select($orig_fh); + untie *PSEUDO_STDOUT if tied *PSEUDO_STDOUT; + close $FH; + + return 1; +} + +sub errors { $errors } + +sub standard_typemap_locations { + # Add all the default typemap locations to the search path + my @tm = qw(typemap); + + my $updir = File::Spec->updir; + foreach my $dir (File::Spec->catdir(($updir) x 1), File::Spec->catdir(($updir) x 2), + File::Spec->catdir(($updir) x 3), File::Spec->catdir(($updir) x 4)) { + + unshift @tm, File::Spec->catfile($dir, 'typemap'); + unshift @tm, File::Spec->catfile($dir, lib => ExtUtils => 'typemap'); + } + foreach my $dir (@INC) { + my $file = File::Spec->catfile($dir, ExtUtils => 'typemap'); + unshift @tm, $file if -e $file; + } + return @tm; +} + +sub TrimWhitespace +{ + $_[0] =~ s/^\s+|\s+$//go ; +} + +sub TidyType + { + local ($_) = @_ ; + + # rationalise any '*' by joining them into bunches and removing whitespace + s#\s*(\*+)\s*#$1#g; + s#(\*+)# $1 #g ; + + # change multiple whitespace into a single space + s/\s+/ /g ; + + # trim leading & trailing whitespace + TrimWhitespace($_) ; + + $_ ; +} + +# Input: ($_, @line) == unparsed input. +# Output: ($_, @line) == (rest of line, following lines). +# Return: the matched keyword if found, otherwise 0 +sub check_keyword { + $_ = shift(@line) while !/\S/ && @line; + s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2; +} + +sub print_section { + # the "do" is required for right semantics + do { $_ = shift(@line) } while !/\S/ && @line; + + print("#line ", $line_no[@line_no - @line -1], " \"$filepathname\"\n") + if $WantLineNumbers && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/; + for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { + print "$_\n"; + } + print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $WantLineNumbers; +} + +sub merge_section { + my $in = ''; + + while (!/\S/ && @line) { + $_ = shift(@line); + } + + for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { + $in .= "$_\n"; + } + chomp $in; + return $in; + } + +sub process_keyword($) + { + my($pattern) = @_ ; + my $kwd ; + + &{"${kwd}_handler"}() + while $kwd = check_keyword($pattern) ; + } + +sub CASE_handler { + blurt ("Error: `CASE:' after unconditional `CASE:'") + if $condnum && $cond eq ''; + $cond = $_; + TrimWhitespace($cond); + print " ", ($condnum++ ? " else" : ""), ($cond ? " if ($cond)\n" : "\n"); + $_ = '' ; +} + +sub INPUT_handler { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + last if /^\s*NOT_IMPLEMENTED_YET/; + next unless /\S/; # skip blank lines + + TrimWhitespace($_) ; + my $line = $_ ; + + # remove trailing semicolon if no initialisation + s/\s*;$//g unless /[=;+].*\S/ ; + + # Process the length(foo) declarations + if (s/^([^=]*)\blength\(\s*(\w+)\s*\)\s*$/$1 XSauto_length_of_$2=NO_INIT/x) { + print "\tSTRLEN\tSTRLEN_length_of_$2;\n"; + $lengthof{$2} = $name; + # $islengthof{$name} = $1; + $deferred .= "\n\tXSauto_length_of_$2 = STRLEN_length_of_$2;"; + } + + # check for optional initialisation code + my $var_init = '' ; + $var_init = $1 if s/\s*([=;+].*)$//s ; + $var_init =~ s/"/\\"/g; + + s/\s+/ /g; + my ($var_type, $var_addr, $var_name) = /^(.*?[^&\s])\s*(\&?)\s*\b(\w+)$/s + or blurt("Error: invalid argument declaration '$line'"), next; + + # Check for duplicate definitions + blurt ("Error: duplicate definition of argument '$var_name' ignored"), next + if $arg_list{$var_name}++ + or defined $argtype_seen{$var_name} and not $processing_arg_with_types; + + $thisdone |= $var_name eq "THIS"; + $retvaldone |= $var_name eq "RETVAL"; + $var_types{$var_name} = $var_type; + # XXXX This check is a safeguard against the unfinished conversion of + # generate_init(). When generate_init() is fixed, + # one can use 2-args map_type() unconditionally. + if ($var_type =~ / \( \s* \* \s* \) /x) { + # Function pointers are not yet supported with &output_init! + print "\t" . &map_type($var_type, $var_name); + $name_printed = 1; + } else { + print "\t" . &map_type($var_type); + $name_printed = 0; + } + $var_num = $args_match{$var_name}; + + $proto_arg[$var_num] = ProtoString($var_type) + if $var_num ; + $func_args =~ s/\b($var_name)\b/&$1/ if $var_addr; + if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/ + or $in_out{$var_name} and $in_out{$var_name} =~ /^OUT/ + and $var_init !~ /\S/) { + if ($name_printed) { + print ";\n"; + } else { + print "\t$var_name;\n"; + } + } elsif ($var_init =~ /\S/) { + &output_init($var_type, $var_num, $var_name, $var_init, $name_printed); + } elsif ($var_num) { + # generate initialization code + &generate_init($var_type, $var_num, $var_name, $name_printed); + } else { + print ";\n"; + } + } +} + +sub OUTPUT_handler { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) { + $DoSetMagic = ($1 eq "ENABLE" ? 1 : 0); + next; + } + my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s ; + blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next + if $outargs{$outarg} ++ ; + if (!$gotRETVAL and $outarg eq 'RETVAL') { + # deal with RETVAL last + $RETVAL_code = $outcode ; + $gotRETVAL = 1 ; + next ; + } + blurt ("Error: OUTPUT $outarg not an argument"), next + unless defined($args_match{$outarg}); + blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next + unless defined $var_types{$outarg} ; + $var_num = $args_match{$outarg}; + if ($outcode) { + print "\t$outcode\n"; + print "\tSvSETMAGIC(ST(" , $var_num-1 , "));\n" if $DoSetMagic; + } else { + &generate_output($var_types{$outarg}, $var_num, $outarg, $DoSetMagic); + } + delete $in_out{$outarg} # No need to auto-OUTPUT + if exists $in_out{$outarg} and $in_out{$outarg} =~ /OUT$/; + } +} + +sub C_ARGS_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + $func_args = $in; +} + +sub INTERFACE_MACRO_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + if ($in =~ /\s/) { # two + ($interface_macro, $interface_macro_set) = split ' ', $in; + } else { + $interface_macro = $in; + $interface_macro_set = 'UNKNOWN_CVT'; # catch later + } + $interface = 1; # local + $Interfaces = 1; # global +} + +sub INTERFACE_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + + foreach (split /[\s,]+/, $in) { + my $name = $_; + $name =~ s/^$Prefix//; + $Interfaces{$name} = $_; + } + print Q(<<"EOF"); +# XSFUNCTION = $interface_macro($ret_type,cv,XSANY.any_dptr); +EOF + $interface = 1; # local + $Interfaces = 1; # global +} + +sub CLEANUP_handler() { print_section() } +sub PREINIT_handler() { print_section() } +sub POSTCALL_handler() { print_section() } +sub INIT_handler() { print_section() } + +sub GetAliases + { + my ($line) = @_ ; + my ($orig) = $line ; + my ($alias) ; + my ($value) ; + + # Parse alias definitions + # format is + # alias = value alias = value ... + + while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) { + $alias = $1 ; + $orig_alias = $alias ; + $value = $2 ; + + # check for optional package definition in the alias + $alias = $Packprefix . $alias if $alias !~ /::/ ; + + # check for duplicate alias name & duplicate value + Warn("Warning: Ignoring duplicate alias '$orig_alias'") + if defined $XsubAliases{$alias} ; + + Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$value}' have identical values") + if $XsubAliasValues{$value} ; + + $XsubAliases = 1; + $XsubAliases{$alias} = $value ; + $XsubAliasValues{$value} = $orig_alias ; + } + + blurt("Error: Cannot parse ALIAS definitions from '$orig'") + if $line ; + } + +sub ATTRS_handler () + { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + push @Attributes, $_; + } + } + +sub ALIAS_handler () + { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + GetAliases($_) if $_ ; + } + } + +sub OVERLOAD_handler() +{ + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + while ( s/^\s*([\w:"\\)\+\-\*\/\%\<\>\.\&\|\^\!\~\{\}\=]+)\s*//) { + $Overload = 1 unless $Overload; + my $overload = "$Package\::(".$1 ; + push(@InitFileCode, + " newXS(\"$overload\", XS_$Full_func_name, file$proto);\n"); + } + } +} + +sub FALLBACK_handler() +{ + # the rest of the current line should contain either TRUE, + # FALSE or UNDEF + + TrimWhitespace($_) ; + my %map = ( + TRUE => "PL_sv_yes", 1 => "PL_sv_yes", + FALSE => "PL_sv_no", 0 => "PL_sv_no", + UNDEF => "PL_sv_undef", + ) ; + + # check for valid FALLBACK value + death ("Error: FALLBACK: TRUE/FALSE/UNDEF") unless exists $map{uc $_} ; + + $Fallback = $map{uc $_} ; +} + + +sub REQUIRE_handler () + { + # the rest of the current line should contain a version number + my ($Ver) = $_ ; + + TrimWhitespace($Ver) ; + + death ("Error: REQUIRE expects a version number") + unless $Ver ; + + # check that the version number is of the form n.n + death ("Error: REQUIRE: expected a number, got '$Ver'") + unless $Ver =~ /^\d+(\.\d*)?/ ; + + death ("Error: xsubpp $Ver (or better) required--this is only $VERSION.") + unless $VERSION >= $Ver ; + } + +sub VERSIONCHECK_handler () + { + # the rest of the current line should contain either ENABLE or + # DISABLE + + TrimWhitespace($_) ; + + # check for ENABLE/DISABLE + death ("Error: VERSIONCHECK: ENABLE/DISABLE") + unless /^(ENABLE|DISABLE)/i ; + + $WantVersionChk = 1 if $1 eq 'ENABLE' ; + $WantVersionChk = 0 if $1 eq 'DISABLE' ; + + } + +sub PROTOTYPE_handler () + { + my $specified ; + + death("Error: Only 1 PROTOTYPE definition allowed per xsub") + if $proto_in_this_xsub ++ ; + + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + $specified = 1 ; + TrimWhitespace($_) ; + if ($_ eq 'DISABLE') { + $ProtoThisXSUB = 0 + } elsif ($_ eq 'ENABLE') { + $ProtoThisXSUB = 1 + } else { + # remove any whitespace + s/\s+//g ; + death("Error: Invalid prototype '$_'") + unless ValidProtoString($_) ; + $ProtoThisXSUB = C_string($_) ; + } + } + + # If no prototype specified, then assume empty prototype "" + $ProtoThisXSUB = 2 unless $specified ; + + $ProtoUsed = 1 ; + + } + +sub SCOPE_handler () + { + death("Error: Only 1 SCOPE declaration allowed per xsub") + if $scope_in_this_xsub ++ ; + + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + if ($_ =~ /^DISABLE/i) { + $ScopeThisXSUB = 0 + } elsif ($_ =~ /^ENABLE/i) { + $ScopeThisXSUB = 1 + } + } + + } + +sub PROTOTYPES_handler () + { + # the rest of the current line should contain either ENABLE or + # DISABLE + + TrimWhitespace($_) ; + + # check for ENABLE/DISABLE + death ("Error: PROTOTYPES: ENABLE/DISABLE") + unless /^(ENABLE|DISABLE)/i ; + + $WantPrototypes = 1 if $1 eq 'ENABLE' ; + $WantPrototypes = 0 if $1 eq 'DISABLE' ; + $ProtoUsed = 1 ; + + } + +sub INCLUDE_handler () + { + # the rest of the current line should contain a valid filename + + TrimWhitespace($_) ; + + death("INCLUDE: filename missing") + unless $_ ; + + death("INCLUDE: output pipe is illegal") + if /^\s*\|/ ; + + # simple minded recursion detector + death("INCLUDE loop detected") + if $IncludedFiles{$_} ; + + ++ $IncludedFiles{$_} unless /\|\s*$/ ; + + # Save the current file context. + push(@XSStack, { + type => 'file', + LastLine => $lastline, + LastLineNo => $lastline_no, + Line => \@line, + LineNo => \@line_no, + Filename => $filename, + Filepathname => $filepathname, + Handle => $FH, + }) ; + + $FH = Symbol::gensym(); + + # open the new file + open ($FH, "$_") or death("Cannot open '$_': $!") ; + + print Q(<<"EOF"); +# +#/* INCLUDE: Including '$_' from '$filename' */ +# +EOF + + $filepathname = $filename = $_ ; + + # Prime the pump by reading the first + # non-blank line + + # skip leading blank lines + while (<$FH>) { + last unless /^\s*$/ ; + } + + $lastline = $_ ; + $lastline_no = $. ; + + } + +sub PopFile() + { + return 0 unless $XSStack[-1]{type} eq 'file' ; + + my $data = pop @XSStack ; + my $ThisFile = $filename ; + my $isPipe = ($filename =~ /\|\s*$/) ; + + -- $IncludedFiles{$filename} + unless $isPipe ; + + close $FH ; + + $FH = $data->{Handle} ; + # $filename is the leafname, which for some reason isused for diagnostic + # messages, whereas $filepathname is the full pathname, and is used for + # #line directives. + $filename = $data->{Filename} ; + $filepathname = $data->{Filepathname} ; + $lastline = $data->{LastLine} ; + $lastline_no = $data->{LastLineNo} ; + @line = @{ $data->{Line} } ; + @line_no = @{ $data->{LineNo} } ; + + if ($isPipe and $? ) { + -- $lastline_no ; + print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n" ; + exit 1 ; + } + + print Q(<<"EOF"); +# +#/* INCLUDE: Returning to '$filename' from '$ThisFile' */ +# +EOF + + return 1 ; + } + +sub ValidProtoString ($) + { + my($string) = @_ ; + + if ( $string =~ /^$proto_re+$/ ) { + return $string ; + } + + return 0 ; + } + +sub C_string ($) + { + my($string) = @_ ; + + $string =~ s[\\][\\\\]g ; + $string ; + } + +sub ProtoString ($) + { + my ($type) = @_ ; + + $proto_letter{$type} or "\$" ; + } + +sub check_cpp { + my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line); + if (@cpp) { + my ($cpp, $cpplevel); + for $cpp (@cpp) { + if ($cpp =~ /^\#\s*if/) { + $cpplevel++; + } elsif (!$cpplevel) { + Warn("Warning: #else/elif/endif without #if in this function"); + print STDERR " (precede it with a blank line if the matching #if is outside the function)\n" + if $XSStack[-1]{type} eq 'if'; + return; + } elsif ($cpp =~ /^\#\s*endif/) { + $cpplevel--; + } + } + Warn("Warning: #if without #endif in this function") if $cpplevel; + } +} + + +sub Q { + my($text) = @_; + $text =~ s/^#//gm; + $text =~ s/\[\[/{/g; + $text =~ s/\]\]/}/g; + $text; +} + +# Read next xsub into @line from ($lastline, <$FH>). +sub fetch_para { + # parse paragraph + death ("Error: Unterminated `#if/#ifdef/#ifndef'") + if !defined $lastline && $XSStack[-1]{type} eq 'if'; + @line = (); + @line_no = () ; + return PopFile() if !defined $lastline; + + if ($lastline =~ + /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) { + $Module = $1; + $Package = defined($2) ? $2 : ''; # keep -w happy + $Prefix = defined($3) ? $3 : ''; # keep -w happy + $Prefix = quotemeta $Prefix ; + ($Module_cname = $Module) =~ s/\W/_/g; + ($Packid = $Package) =~ tr/:/_/; + $Packprefix = $Package; + $Packprefix .= "::" if $Packprefix ne ""; + $lastline = ""; + } + + for (;;) { + # Skip embedded PODs + while ($lastline =~ /^=/) { + while ($lastline = <$FH>) { + last if ($lastline =~ /^=cut\s*$/); + } + death ("Error: Unterminated pod") unless $lastline; + $lastline = <$FH>; + chomp $lastline; + $lastline =~ s/^\s+$//; + } + if ($lastline !~ /^\s*#/ || + # CPP directives: + # ANSI: if ifdef ifndef elif else endif define undef + # line error pragma + # gcc: warning include_next + # obj-c: import + # others: ident (gcc notes that some cpps have this one) + $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) { + last if $lastline =~ /^\S/ && @line && $line[-1] eq ""; + push(@line, $lastline); + push(@line_no, $lastline_no) ; + } + + # Read next line and continuation lines + last unless defined($lastline = <$FH>); + $lastline_no = $.; + my $tmp_line; + $lastline .= $tmp_line + while ($lastline =~ /\\$/ && defined($tmp_line = <$FH>)); + + chomp $lastline; + $lastline =~ s/^\s+$//; + } + pop(@line), pop(@line_no) while @line && $line[-1] eq ""; + 1; +} + +sub output_init { + local($type, $num, $var, $init, $name_printed) = @_; + local($arg) = "ST(" . ($num - 1) . ")"; + + if ( $init =~ /^=/ ) { + if ($name_printed) { + eval qq/print " $init\\n"/; + } else { + eval qq/print "\\t$var $init\\n"/; + } + warn $@ if $@; + } else { + if ( $init =~ s/^\+// && $num ) { + &generate_init($type, $num, $var, $name_printed); + } elsif ($name_printed) { + print ";\n"; + $init =~ s/^;//; + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + $init =~ s/^;//; + } + $deferred .= eval qq/"\\n\\t$init\\n"/; + warn $@ if $@; + } +} + +sub Warn + { + # work out the line number + my $line_no = $line_no[@line_no - @line -1] ; + + print STDERR "@_ in $filename, line $line_no\n" ; + } + +sub blurt + { + Warn @_ ; + $errors ++ + } + +sub death + { + Warn @_ ; + exit 1 ; + } + +sub generate_init { + local($type, $num, $var) = @_; + local($arg) = "ST(" . ($num - 1) . ")"; + local($argoff) = $num - 1; + local($ntype); + local($tk); + + $type = TidyType($type) ; + blurt("Error: '$type' not in typemap"), return + unless defined($type_kind{$type}); + + ($ntype = $type) =~ s/\s*\*/Ptr/g; + ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//; + $tk = $type_kind{$type}; + $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/; + if ($tk eq 'T_PV' and exists $lengthof{$var}) { + print "\t$var" unless $name_printed; + print " = ($type)SvPV($arg, STRLEN_length_of_$var);\n"; + die "default value not supported with length(NAME) supplied" + if defined $defaults{$var}; + return; + } + $type =~ tr/:/_/ unless $hiertype; + blurt("Error: No INPUT definition for type '$type', typekind '$type_kind{$type}' found"), return + unless defined $input_expr{$tk} ; + $expr = $input_expr{$tk}; + if ($expr =~ /DO_ARRAY_ELEM/) { + blurt("Error: '$subtype' not in typemap"), return + unless defined($type_kind{$subtype}); + blurt("Error: No INPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return + unless defined $input_expr{$type_kind{$subtype}} ; + $subexpr = $input_expr{$type_kind{$subtype}}; + $subexpr =~ s/\$type/\$subtype/g; + $subexpr =~ s/ntype/subtype/g; + $subexpr =~ s/\$arg/ST(ix_$var)/g; + $subexpr =~ s/\n\t/\n\t\t/g; + $subexpr =~ s/is not of (.*\")/[arg %d] is not of $1, ix_$var + 1/g; + $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/; + $expr =~ s/DO_ARRAY_ELEM/$subexpr/; + } + if ($expr =~ m#/\*.*scope.*\*/#i) { # "scope" in C comments + $ScopeThisXSUB = 1; + } + if (defined($defaults{$var})) { + $expr =~ s/(\t+)/$1 /g; + $expr =~ s/ /\t/g; + if ($name_printed) { + print ";\n"; + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + } + if ($defaults{$var} eq 'NO_INIT') { + $deferred .= eval qq/"\\n\\tif (items >= $num) {\\n$expr;\\n\\t}\\n"/; + } else { + $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/; + } + warn $@ if $@; + } elsif ($ScopeThisXSUB or $expr !~ /^\s*\$var =/) { + if ($name_printed) { + print ";\n"; + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + } + $deferred .= eval qq/"\\n$expr;\\n"/; + warn $@ if $@; + } else { + die "panic: do not know how to handle this branch for function pointers" + if $name_printed; + eval qq/print "$expr;\\n"/; + warn $@ if $@; + } +} + +sub generate_output { + local($type, $num, $var, $do_setmagic, $do_push) = @_; + local($arg) = "ST(" . ($num - ($num != 0)) . ")"; + local($argoff) = $num - 1; + local($ntype); + + $type = TidyType($type) ; + if ($type =~ /^array\(([^,]*),(.*)\)/) { + print "\t$arg = sv_newmortal();\n"; + print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1));\n"; + print "\tSvSETMAGIC($arg);\n" if $do_setmagic; + } else { + blurt("Error: '$type' not in typemap"), return + unless defined($type_kind{$type}); + blurt("Error: No OUTPUT definition for type '$type', typekind '$type_kind{$type}' found"), return + unless defined $output_expr{$type_kind{$type}} ; + ($ntype = $type) =~ s/\s*\*/Ptr/g; + $ntype =~ s/\(\)//g; + ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//; + $expr = $output_expr{$type_kind{$type}}; + if ($expr =~ /DO_ARRAY_ELEM/) { + blurt("Error: '$subtype' not in typemap"), return + unless defined($type_kind{$subtype}); + blurt("Error: No OUTPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return + unless defined $output_expr{$type_kind{$subtype}} ; + $subexpr = $output_expr{$type_kind{$subtype}}; + $subexpr =~ s/ntype/subtype/g; + $subexpr =~ s/\$arg/ST(ix_$var)/g; + $subexpr =~ s/\$var/${var}[ix_$var]/g; + $subexpr =~ s/\n\t/\n\t\t/g; + $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/; + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic; + } elsif ($var eq 'RETVAL') { + if ($expr =~ /^\t\$arg = new/) { + # We expect that $arg has refcnt 1, so we need to + # mortalize it. + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tsv_2mortal(ST($num));\n"; + print "\tSvSETMAGIC(ST($num));\n" if $do_setmagic; + } elsif ($expr =~ /^\s*\$arg\s*=/) { + # We expect that $arg has refcnt >=1, so we need + # to mortalize it! + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tsv_2mortal(ST(0));\n"; + print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic; + } else { + # Just hope that the entry would safely write it + # over an already mortalized value. By + # coincidence, something like $arg = &sv_undef + # works too. + print "\tST(0) = sv_newmortal();\n"; + eval "print qq\a$expr\a"; + warn $@ if $@; + # new mortals don't have set magic + } + } elsif ($do_push) { + print "\tPUSHs(sv_newmortal());\n"; + $arg = "ST($num)"; + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tSvSETMAGIC($arg);\n" if $do_setmagic; + } elsif ($arg =~ /^ST\(\d+\)$/) { + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tSvSETMAGIC($arg);\n" if $do_setmagic; + } + } +} + +sub map_type { + my($type, $varname) = @_; + + # C++ has :: in types too so skip this + $type =~ tr/:/_/ unless $hiertype; + $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s; + if ($varname) { + if ($varname && $type =~ / \( \s* \* (?= \s* \) ) /xg) { + (substr $type, pos $type, 0) = " $varname "; + } else { + $type .= "\t$varname"; + } + } + $type; +} + + +######################################################### +package + ExtUtils::ParseXS::CountLines; +use strict; +use vars qw($SECTION_END_MARKER); + +sub TIEHANDLE { + my ($class, $cfile, $fh) = @_; + $cfile =~ s/\\/\\\\/g; + $SECTION_END_MARKER = qq{#line --- "$cfile"}; + + return bless {buffer => '', + fh => $fh, + line_no => 1, + }, $class; +} + +sub PRINT { + my $self = shift; + for (@_) { + $self->{buffer} .= $_; + while ($self->{buffer} =~ s/^([^\n]*\n)//) { + my $line = $1; + ++ $self->{line_no}; + $line =~ s|^\#line\s+---(?=\s)|#line $self->{line_no}|; + print {$self->{fh}} $line; + } + } +} + +sub PRINTF { + my $self = shift; + my $fmt = shift; + $self->PRINT(sprintf($fmt, @_)); +} + +sub DESTROY { + # Not necessary if we're careful to end with a "\n" + my $self = shift; + print {$self->{fh}} $self->{buffer}; +} + +sub UNTIE { + # This sub does nothing, but is neccessary for references to be released. +} + +sub end_marker { + return $SECTION_END_MARKER; +} + + +1; +__END__ + +=head1 NAME + +ExtUtils::ParseXS - converts Perl XS code into C code + +=head1 SYNOPSIS + + use ExtUtils::ParseXS qw(process_file); + + process_file( filename => 'foo.xs' ); + + process_file( filename => 'foo.xs', + output => 'bar.c', + 'C++' => 1, + typemap => 'path/to/typemap', + hiertype => 1, + except => 1, + prototypes => 1, + versioncheck => 1, + linenumbers => 1, + optimize => 1, + prototypes => 1, + ); +=head1 DESCRIPTION + +C<ExtUtils::ParseXS> will compile XS code into C code by embedding the constructs +necessary to let C functions manipulate Perl values and creates the glue +necessary to let Perl access those functions. The compiler uses typemaps to +determine how to map C function parameters and variables to Perl values. + +The compiler will search for typemap files called I<typemap>. It will use +the following search path to find default typemaps, with the rightmost +typemap taking precedence. + + ../../../typemap:../../typemap:../typemap:typemap + +=head1 EXPORT + +None by default. C<process_file()> may be exported upon request. + + +=head1 FUNCTIONS + +=over 4 + +=item process_xs() + +This function processes an XS file and sends output to a C file. +Named parameters control how the processing is done. The following +parameters are accepted: + +=over 4 + +=item B<C++> + +Adds C<extern "C"> to the C code. Default is false. + +=item B<hiertype> + +Retains C<::> in type names so that C++ hierachical types can be +mapped. Default is false. + +=item B<except> + +Adds exception handling stubs to the C code. Default is false. + +=item B<typemap> + +Indicates that a user-supplied typemap should take precedence over the +default typemaps. A single typemap may be specified as a string, or +multiple typemaps can be specified in an array reference, with the +last typemap having the highest precedence. + +=item B<prototypes> + +Generates prototype code for all xsubs. Default is false. + +=item B<versioncheck> + +Makes sure at run time that the object file (derived from the C<.xs> +file) and the C<.pm> files have the same version number. Default is +true. + +=item B<linenumbers> + +Adds C<#line> directives to the C output so error messages will look +like they came from the original XS file. Default is true. + +=item B<optimize> + +Enables certain optimizations. The only optimization that is currently +affected is the use of I<target>s by the output C code (see L<perlguts>). +Not optimizing may significantly slow down the generated code, but this is the way +B<xsubpp> of 5.005 and earlier operated. Default is to optimize. + +=item B<inout> + +Enable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST> +declarations. Default is true. + +=item B<argtypes> + +Enable recognition of ANSI-like descriptions of function signature. +Default is true. + +=item B<s> + +I have no clue what this does. Strips function prefixes? + +=back + +=item errors() + +This function returns the number of [a certain kind of] errors +encountered during processing of the XS file. + +=back + +=head1 AUTHOR + +Based on xsubpp code, written by Larry Wall. + +Maintained by Ken Williams, <ken@mathforum.org> + +=head1 COPYRIGHT + +Copyright 2002-2003 Ken Williams. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +Based on the ExtUtils::xsubpp code by Larry Wall and the Perl 5 +Porters, which was released under the same license terms. + +=head1 SEE ALSO + +L<perl>, ExtUtils::xsubpp, ExtUtils::MakeMaker, L<perlxs>, L<perlxstut>. + +=cut diff --git a/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/XSTest.pm b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/XSTest.pm new file mode 100644 index 00000000000..988ef472e84 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/XSTest.pm @@ -0,0 +1,8 @@ +package XSTest; + +require DynaLoader; +@ISA = qw(Exporter DynaLoader); +$VERSION = '0.01'; +bootstrap XSTest $VERSION; + +1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/XSTest.xs b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/XSTest.xs new file mode 100644 index 00000000000..699c7341aa6 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/XSTest.xs @@ -0,0 +1,67 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +void +xstest_something (char * some_thing) +{ + some_thing = some_thing; +} + +void +xstest_something2 (char * some_thing) +{ + some_thing = some_thing; +} + + +MODULE = XSTest PACKAGE = XSTest PREFIX = xstest_ + +PROTOTYPES: DISABLE + +int +is_even(input) + int input + CODE: + RETVAL = (input % 2 == 0); + OUTPUT: + RETVAL + +void +xstest_something (myclass, some_thing) + char * some_thing + C_ARGS: + some_thing + +void +xstest_something2 (some_thing) + char * some_thing + +void +xstest_something3 (myclass, some_thing) + SV * myclass + char * some_thing + PREINIT: + int i = 0; + PPCODE: + /* it's up to us clear these warnings */ + myclass = myclass; + some_thing = some_thing; + i = i; + XSRETURN_UNDEF; + +int +consts (myclass) + SV * myclass + ALIAS: + const_one = 1 + const_two = 2 + const_three = 3 + CODE: + /* it's up to us clear these warnings */ + myclass = myclass; + ix = ix; + RETVAL = 1; + OUTPUT: + RETVAL + diff --git a/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/basic.t b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/basic.t new file mode 100644 index 00000000000..9b5319e56a5 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/ParseXS/t/basic.t @@ -0,0 +1,79 @@ +#!/usr/bin/perl + +BEGIN { + if ($ENV{PERL_CORE}) { + chdir 't' if -d 't'; + chdir '../lib/ExtUtils/ParseXS' + or die "Can't chdir to lib/ExtUtils/ParseXS: $!"; + @INC = qw(../.. ../../.. .); + } +} +use strict; +use Test; +BEGIN { plan tests => 10 }; +use DynaLoader; +use ExtUtils::ParseXS qw(process_file); +use ExtUtils::CBuilder; +ok(1); # If we made it this far, we're loaded. + +chdir 't' or die "Can't chdir to t/, $!"; + +use Carp; $SIG{__WARN__} = \&Carp::cluck; + +######################### + +# Try sending to filehandle +tie *FH, 'Foo'; +process_file( filename => 'XSTest.xs', output => \*FH, prototypes => 1 ); +ok tied(*FH)->content, '/is_even/', "Test that output contains some text"; + +my $source_file = 'XSTest.c'; + +# Try sending to file +process_file(filename => 'XSTest.xs', output => $source_file, prototypes => 0); +ok -e $source_file, 1, "Create an output file"; + +# TEST doesn't like extraneous output +my $quiet = $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE}; + +# Try to compile the file! Don't get too fancy, though. +my $b = ExtUtils::CBuilder->new(quiet => $quiet); +if ($b->have_compiler) { + my $module = 'XSTest'; + + my $obj_file = $b->compile( source => $source_file ); + ok $obj_file; + ok -e $obj_file, 1, "Make sure $obj_file exists"; + + my $lib_file = $b->link( objects => $obj_file, module_name => $module ); + ok $lib_file; + ok -e $lib_file, 1, "Make sure $lib_file exists"; + + eval {require XSTest}; + ok $@, ''; + ok XSTest::is_even(8); + ok !XSTest::is_even(9); + + # Win32 needs to close the DLL before it can unlink it, but unfortunately + # dl_unload_file was missing on Win32 prior to perl change #24679! + if ($^O eq 'MSWin32' and defined &DynaLoader::dl_unload_file) { + for (my $i = 0; $i < @DynaLoader::dl_modules; $i++) { + if ($DynaLoader::dl_modules[$i] eq $module) { + DynaLoader::dl_unload_file($DynaLoader::dl_librefs[$i]); + last; + } + } + } + 1 while unlink $obj_file; + 1 while unlink $lib_file; +} else { + skip "Skipped can't find a C compiler & linker", 1 for 1..7; +} + +1 while unlink $source_file; + +##################################################################### + +sub Foo::TIEHANDLE { bless {}, 'Foo' } +sub Foo::PRINT { shift->{buf} .= join '', @_ } +sub Foo::content { shift->{buf} } diff --git a/gnu/usr.bin/perl/lib/ExtUtils/README b/gnu/usr.bin/perl/lib/ExtUtils/README index 81bc190d673..9586c0ba173 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/README +++ b/gnu/usr.bin/perl/lib/ExtUtils/README @@ -32,8 +32,8 @@ Every stable MakeMaker release is tested at least on: MacOS X Linux/x86 -ActivePerl on Windows 98 -Cygwin on Windows 98 +ActivePerl on Windows +Cygwin OpenVMS Covering the major portability flavors MakeMaker has to cover. @@ -44,13 +44,14 @@ Known Problems: (See http://rt.cpan.org for a full list of open problems.) -ActivePerl likely broken if installed in C:\Program Files or other -prefix with a space in the name. +Windows will likely be broken if Perl is installed in C:\Program Files or +other prefix with a space in the name. Using the MMS utility on VMS causes lots of extra newlines. Unknown why this is so, might be a bug in MMS. Problem not seen with MMK. +GNU make does not work with MakeMaker on Windows. -See TODO for details. -Please report any bugs via http://rt.cpan.org or to makemaker@perl.org. +Please report any bugs via http://rt.cpan.org. +Send questions and discussion to makemaker@perl.org diff --git a/gnu/usr.bin/perl/lib/ExtUtils/TODO b/gnu/usr.bin/perl/lib/ExtUtils/TODO index 80c69f6282b..fe5a703a2bf 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/TODO +++ b/gnu/usr.bin/perl/lib/ExtUtils/TODO @@ -1,3 +1,6 @@ +This TODO list is out of date. See http://rt.cpan.org for the real list. + + Rethink MM_Win32 tests. Investigate one method per make target. diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/Constant.t b/gnu/usr.bin/perl/lib/ExtUtils/t/Constant.t index f440da4b16f..7c997fe21ba 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/Constant.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/Constant.t @@ -15,7 +15,7 @@ BEGIN { # use warnings; use strict; use ExtUtils::MakeMaker; -use ExtUtils::Constant qw (constant_types C_constant XS_constant autoload); +use ExtUtils::Constant qw (C_constant autoload); use File::Spec; use Cwd; @@ -85,6 +85,30 @@ END { chdir $dir or die $!; push @INC, '../../lib', '../../../lib'; +package TieOut; + +sub TIEHANDLE { + my $class = shift; + bless(\( my $ref = ''), $class); +} + +sub PRINT { + my $self = shift; + $$self .= join('', @_); +} + +sub PRINTF { + my $self = shift; + $$self .= sprintf shift, @_; +} + +sub read { + my $self = shift; + return substr($$self, 0, length($$self), ''); +} + +package main; + sub check_for_bonus_files { my $dir = shift; my %expect = map {($^O eq 'VMS' ? lc($_) : $_), 1} @_; @@ -210,38 +234,45 @@ sub build_and_run { } $realtest++; - # -x is busted on Win32 < 5.6.1, so we emulate it. - my $regen; - if( $^O eq 'MSWin32' && $] <= 5.006001 ) { - open(REGENTMP, ">regentmp") or die $!; - open(XS, "$package.xs") or die $!; - my $saw_shebang; - while(<XS>) { - $saw_shebang++ if /^#!.*/i ; - print REGENTMP $_ if $saw_shebang; - } - close XS; close REGENTMP; - $regen = `$runperl regentmp`; - unlink 'regentmp'; - } - else { - $regen = `$runperl -x $package.xs`; - } - if ($?) { - print "not ok $realtest # $runperl -x $package.xs failed: $?\n"; - } else { - print "ok $realtest - regen\n"; - } - $realtest++; - - if ($expect eq $regen) { - print "ok $realtest - regen worked\n"; + if (defined $expect) { + # -x is busted on Win32 < 5.6.1, so we emulate it. + my $regen; + if( $^O eq 'MSWin32' && $] <= 5.006001 ) { + open(REGENTMP, ">regentmp") or die $!; + open(XS, "$package.xs") or die $!; + my $saw_shebang; + while(<XS>) { + $saw_shebang++ if /^#!.*/i ; + print REGENTMP $_ if $saw_shebang; + } + close XS; close REGENTMP; + $regen = `$runperl regentmp`; + unlink 'regentmp'; + } + else { + $regen = `$runperl -x $package.xs`; + } + if ($?) { + print "not ok $realtest # $runperl -x $package.xs failed: $?\n"; + } else { + print "ok $realtest - regen\n"; + } + $realtest++; + + if ($expect eq $regen) { + print "ok $realtest - regen worked\n"; + } else { + print "not ok $realtest - regen worked\n"; + # open FOO, ">expect"; print FOO $expect; + # open FOO, ">regen"; print FOO $regen; close FOO; + } + $realtest++; } else { - print "not ok $realtest - regen worked\n"; - # open FOO, ">expect"; print FOO $expect; - # open FOO, ">regen"; print FOO $regen; close FOO; + for (0..1) { + print "ok $realtest # skip no regen or expect for this set of tests\n"; + $realtest++; + } } - $realtest++; my $makeclean = "$make clean"; print "# make = '$makeclean'\n"; @@ -320,16 +351,32 @@ sub MANIFEST { } sub write_and_run_extension { - my ($name, $items, $export_names, $package, $header, $testfile, $num_tests) - = @_; - my $types = {}; - my $constant_types = constant_types(); # macro defs - my $C_constant = join "\n", - C_constant ($package, undef, "IV", $types, undef, undef, @$items); - my $XS_constant = XS_constant ($package, $types); # XS for ExtTest::constant + my ($name, $items, $export_names, $package, $header, $testfile, $num_tests, + $wc_args) = @_; + + my $c = tie *C, 'TieOut'; + my $xs = tie *XS, 'TieOut'; + + ExtUtils::Constant::WriteConstants(C_FH => \*C, + XS_FH => \*XS, + NAME => $package, + NAMES => $items, + @$wc_args, + ); + + my $C_code = $c->read(); + my $XS_code = $xs->read(); - my $expect = $constant_types . $C_constant . - "\n#### XS Section:\n" . $XS_constant; + undef $c; + undef $xs; + + untie *C; + untie *XS; + + # Don't check the regeneration code if we specify extra arguments to + # WriteConstants. (Fix this to give finer grained control if needed) + my $expect; + $expect = $C_code . "\n#### XS Section:\n" . $XS_code unless $wc_args; print "# $name\n# $dir/$subdir being created...\n"; mkdir $subdir, 0777 or die "mkdir: $!\n"; @@ -345,23 +392,23 @@ sub write_and_run_extension { close FH or die "close $header_name: $!\n"; ################ XS - my $xs = "$package.xs"; - push @files, $xs; - open FH, ">$xs" or die "open >$xs: $!\n"; + my $xs_name = "$package.xs"; + push @files, $xs_name; + open FH, ">$xs_name" or die "open >$xs_name: $!\n"; - print FH <<'EOT'; + print FH <<"EOT"; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" +#include "$header_name" + + +$C_code +MODULE = $package PACKAGE = $package +PROTOTYPES: ENABLE +$XS_code; EOT - # XXX Here doc these: - print FH "#include \"$header_name\"\n\n"; - print FH $constant_types; - print FH $C_constant, "\n"; - print FH "MODULE = $package PACKAGE = $package\n"; - print FH "PROTOTYPES: ENABLE\n"; - print FH $XS_constant; close FH or die "close $xs: $!\n"; ################ PM @@ -435,6 +482,7 @@ EOT chdir $updir or die "chdir '$updir': $!"; ++$subdir; } + # Tests are arrayrefs of the form # $name, [items], [export_names], $package, $header, $testfile, $num_tests my @tests; @@ -448,9 +496,9 @@ sub start_tests { $here = $dummytest; } sub end_tests { - my ($name, $items, $export_names, $header, $testfile) = @_; + my ($name, $items, $export_names, $header, $testfile, $args) = @_; push @tests, [$name, $items, $export_names, $package, $header, $testfile, - $dummytest - $here]; + $dummytest - $here, $args]; $dummytest += $after_tests; } @@ -467,6 +515,9 @@ my @common_items = ( {name=>$pound, type=>"PV", value=>'"Sterling"', macro=>1}, ); +my @args = undef; +push @args, [PROXYSUBS => 1] if $] > 5.009002; +foreach my $args (@args) { # Simple tests start_tests(); @@ -526,122 +577,146 @@ EOT # Exporter::Heavy (currently) isn't able to export the last 3 of these: push @items, @common_items; - # XXX there are hardwired still. - my $test_body = <<'EOT'; + my $test_body = <<"EOT"; + +my \$test = $dummytest; + +EOT + + $test_body .= <<'EOT'; # What follows goes to the temporary file. # IV my $five = FIVE; if ($five == 5) { - print "ok 5\n"; + print "ok $test\n"; } else { - print "not ok 5 # \$five\n"; + print "not ok $test # \$five\n"; } +$test++; # PV -print OK6; +if (OK6 eq "ok 6\n") { + print "ok $test\n"; +} else { + print "not ok $test # \$five\n"; +} +$test++; # PVN containing embedded \0s $_ = OK7; s/.*\0//s; +s/7/$test/; +$test++; print; # NV my $farthing = FARTHING; if ($farthing == 0.25) { - print "ok 8\n"; + print "ok $test\n"; } else { - print "not ok 8 # $farthing\n"; + print "not ok $test # $farthing\n"; } +$test++; # UV my $not_zero = NOT_ZERO; if ($not_zero > 0 && $not_zero == ~0) { - print "ok 9\n"; + print "ok $test\n"; } else { - print "not ok 9 # \$not_zero=$not_zero ~0=" . (~0) . "\n"; + print "not ok $test # \$not_zero=$not_zero ~0=" . (~0) . "\n"; } +$test++; # Value includes a "*/" in an attempt to bust out of a C comment. # Also tests custom cpp #if clauses my $close = CLOSE; if ($close eq '*/') { - print "ok 10\n"; + print "ok $test\n"; } else { - print "not ok 10 # \$close='$close'\n"; + print "not ok $test # \$close='$close'\n"; } +$test++; # Default values if macro not defined. my $answer = ANSWER; if ($answer == 42) { - print "ok 11\n"; + print "ok $test\n"; } else { - print "not ok 11 # What do you get if you multiply six by nine? '$answer'\n"; + print "not ok $test # What do you get if you multiply six by nine? '$answer'\n"; } +$test++; # not defined macro my $notdef = eval { NOTDEF; }; if (defined $notdef) { - print "not ok 12 # \$notdef='$notdef'\n"; + print "not ok $test # \$notdef='$notdef'\n"; } elsif ($@ !~ /Your vendor has not defined ExtTest macro NOTDEF/) { - print "not ok 12 # \$@='$@'\n"; + print "not ok $test # \$@='$@'\n"; } else { - print "ok 12\n"; + print "ok $test\n"; } +$test++; # not a macro my $notthere = eval { &ExtTest::NOTTHERE; }; if (defined $notthere) { - print "not ok 13 # \$notthere='$notthere'\n"; + print "not ok $test # \$notthere='$notthere'\n"; } elsif ($@ !~ /NOTTHERE is not a valid ExtTest macro/) { chomp $@; - print "not ok 13 # \$@='$@'\n"; + print "not ok $test # \$@='$@'\n"; } else { - print "ok 13\n"; + print "ok $test\n"; } +$test++; # Truth my $yes = Yes; if ($yes) { - print "ok 14\n"; + print "ok $test\n"; } else { - print "not ok 14 # $yes='\$yes'\n"; + print "not ok $test # $yes='\$yes'\n"; } +$test++; # Falsehood my $no = No; if (defined $no and !$no) { - print "ok 15\n"; + print "ok $test\n"; } else { - print "not ok 15 # \$no=" . defined ($no) ? "'$no'\n" : "undef\n"; + print "not ok $test # \$no=" . defined ($no) ? "'$no'\n" : "undef\n"; } +$test++; # Undef my $undef = Undef; unless (defined $undef) { - print "ok 16\n"; + print "ok $test\n"; } else { - print "not ok 16 # \$undef='$undef'\n"; + print "not ok $test # \$undef='$undef'\n"; } +$test++; # invalid macro (chosen to look like a mix up between No and SW) $notdef = eval { &ExtTest::So }; if (defined $notdef) { - print "not ok 17 # \$notdef='$notdef'\n"; + print "not ok $test # \$notdef='$notdef'\n"; } elsif ($@ !~ /^So is not a valid ExtTest macro/) { - print "not ok 17 # \$@='$@'\n"; + print "not ok $test # \$@='$@'\n"; } else { - print "ok 17\n"; + print "ok $test\n"; } +$test++; # invalid defined macro $notdef = eval { &ExtTest::EW }; if (defined $notdef) { - print "not ok 18 # \$notdef='$notdef'\n"; + print "not ok $test # \$notdef='$notdef'\n"; } elsif ($@ !~ /^EW is not a valid ExtTest macro/) { - print "not ok 18 # \$@='$@'\n"; + print "not ok $test # \$@='$@'\n"; } else { - print "ok 18\n"; + print "ok $test\n"; } +$test++; my %compass = ( EOT @@ -669,26 +744,29 @@ while (my ($point, $bearing) = each %compass) { } } if ($fail) { - print "not ok 19\n"; + print "not ok $test\n"; } else { - print "ok 19\n"; + print "ok $test\n"; } +$test++; EOT $test_body .= <<"EOT"; my \$rfc1149 = RFC1149; if (\$rfc1149 ne "$parent_rfc1149") { - print "not ok 20 # '\$rfc1149' ne '$parent_rfc1149'\n"; + print "not ok \$test # '\$rfc1149' ne '$parent_rfc1149'\n"; } else { - print "ok 20\n"; + print "ok \$test\n"; } +\$test++; if (\$rfc1149 != 1149) { - printf "not ok 21 # %d != 1149\n", \$rfc1149; + printf "not ok \$test # %d != 1149\n", \$rfc1149; } else { - print "ok 21\n"; + print "ok \$test\n"; } +\$test++; EOT @@ -696,14 +774,16 @@ $test_body .= <<'EOT'; # test macro=>1 my $open = OPEN; if ($open eq '/*') { - print "ok 22\n"; + print "ok $test\n"; } else { - print "not ok 22 # \$open='$open'\n"; + print "not ok $test # \$open='$open'\n"; } +$test++; EOT $dummytest+=18; - end_tests("Simple tests", \@items, \@export_names, $header, $test_body); + end_tests("Simple tests", \@items, \@export_names, $header, $test_body, + $args); } if ($do_utf_tests) { @@ -787,7 +867,7 @@ foreach (["perl", "rules", "rules"], ) { # Flag an expected error with a reference for the expect string. my ($string, $expect, $expect_bytes) = @$_; - (my $name = $string) =~ s/([^ -~])/sprintf '\x{%X}', ord $1/ges; + (my $name = $string) =~ s/([^ !"#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~])/sprintf '\x{%X}', ord $1/ges; print "# \"$name\" => \'$expect\'\n"; # Try to force this to be bytes if possible. if ($better_than_56) { diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/Embed.t b/gnu/usr.bin/perl/lib/ExtUtils/t/Embed.t index 010d05a827d..e3321ecd471 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/Embed.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/Embed.t @@ -31,11 +31,14 @@ my $libperl_copied; my $testlib; my @cmd; my (@cmd2) if $^O eq 'VMS'; - +# Don't use ccopts() here as we may want to overwrite an existing +# perl with a new one with inconsistent header files, meaning +# the usual value for perl_inc(), which is used by ccopts(), +# will be wrong. if ($^O eq 'VMS') { push(@cmd,$cc,"/Obj=$obj"); my (@incs) = ($inc); - my $crazy = ccopts(); + my $crazy = ccflags(); if ($crazy =~ s#/inc[^=/]*=([\w\$\_\-\.\[\]\:]+)##i) { push(@incs,$1); } @@ -60,7 +63,14 @@ if ($^O eq 'VMS') { else { push(@cmd,$cc,'-o' => $exe); } - push(@cmd,"-I$inc",ccopts(),'embed_test.c'); + if ($^O eq 'dec_osf' && !defined $Config{usedl}) { + # The -non_shared is needed in case of -Uusedl or otherwise + # the test application will try to use libperl.so + # instead of libperl.a. + push @cmd, "-non_shared"; + } + + push(@cmd,"-I$inc",ccflags(),'embed_test.c'); if ($^O eq 'MSWin32') { $inc = File::Spec->catdir($inc,'win32'); push(@cmd,"-I$inc"); @@ -73,7 +83,9 @@ if ($^O eq 'VMS') { push(@cmd,"-L$lib",File::Spec->catfile($lib,$Config{'libperl'}),$Config{'libc'}); } } - else { # Not MSWin32. + elsif ($^O eq 'os390' && $Config{usedl}) { + # Nothing for OS/390 (z/OS) dynamic. + } else { # Not MSWin32 or OS/390 (z/OS) dynamic. push(@cmd,"-L$lib",'-lperl'); local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /No library found for .*perl/ @@ -135,13 +147,13 @@ print "# embed_test = $embed_test\n"; $status = system($embed_test); print (($status? 'not ':'')."ok 9 # system returned $status\n"); unlink($exe,"embed_test.c",$obj); +unlink("$exe.manifest") if $cl and $Config{'ccversion'} =~ /^(\d+)/ and $1 >= 14; unlink("$exe$Config{exe_ext}") if $skip_exe; unlink("embed_test.map","embed_test.lis") if $^O eq 'VMS'; unlink(glob("./*.dll")) if $^O eq 'cygwin'; unlink($testlib) if $libperl_copied; -# gcc -g -I.. -L../ -o perl_test perl_test.c -lperl `../perl -I../lib -MExtUtils::Embed -I../ -e ccopts -e ldopts` - +# gcc -g -I.. -L../ -o perl_test perl_test.c -lperl `../perl -I../lib -MExtUtils::Embed -I../ -e ccflags -e ldopts` __END__ /* perl_test.c */ @@ -158,7 +170,12 @@ static struct perl_vars *my_plvarsp; struct perl_vars* Perl_GetVarsPrivate(void) { return my_plvarsp; } #endif +#ifdef NO_ENV_ARRAY_IN_MAIN +extern char **environ; +int main(int argc, char **argv) +#else int main(int argc, char **argv, char **env) +#endif { PerlInterpreter *my_perl; #ifdef PERL_GLOBAL_STRUCT @@ -171,7 +188,11 @@ int main(int argc, char **argv, char **env) (void)argc; /* PERL_SYS_INIT3 may #define away their use */ (void)argv; +#ifdef NO_ENV_ARRAY_IN_MAIN + PERL_SYS_INIT3(&argc,&argv,&environ); +#else PERL_SYS_INIT3(&argc,&argv,&env); +#endif my_perl = perl_alloc(); @@ -181,7 +202,11 @@ int main(int argc, char **argv, char **env) my_puts("ok 3"); +#ifdef NO_ENV_ARRAY_IN_MAIN + perl_parse(my_perl, NULL, (sizeof(cmds)/sizeof(char *))-1, cmds, environ); +#else perl_parse(my_perl, NULL, (sizeof(cmds)/sizeof(char *))-1, cmds, env); +#endif my_puts("ok 4"); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/FIRST_MAKEFILE.t b/gnu/usr.bin/perl/lib/ExtUtils/t/FIRST_MAKEFILE.t index 731dd34d929..00e6082403b 100755 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/FIRST_MAKEFILE.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/FIRST_MAKEFILE.t @@ -36,5 +36,5 @@ cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || diag @mpl_out; ok( -e 'jakefile', 'FIRST_MAKEFILE honored' ); -ok( grep(/^Writing jakefile for Big::Dummy/, @mpl_out) == 1, +ok( grep(/^Writing jakefile(?:\.)? for Big::Dummy/, @mpl_out) == 1, 'Makefile.PL output looks right' ); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/INSTALL_BASE.t b/gnu/usr.bin/perl/lib/ExtUtils/t/INSTALL_BASE.t new file mode 100644 index 00000000000..cac65f266f0 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/INSTALL_BASE.t @@ -0,0 +1,81 @@ +#!/usr/bin/perl -w + +# Tests INSTALL_BASE + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = ('../lib', 'lib'); + } + else { + unshift @INC, 't/lib'; + } +} + +use strict; +use File::Path; +use Config; + +use Test::More tests => 21; +use MakeMaker::Test::Utils; +use MakeMaker::Test::Setup::BFD; + +my $Is_VMS = $^O eq 'VMS'; + +my $perl = which_perl(); + +chdir 't'; +perl_lib; + +ok( setup_recurs(), 'setup' ); +END { + ok( chdir File::Spec->updir ); + ok( teardown_recurs(), 'teardown' ); +} + +ok( chdir('Big-Dummy'), "chdir'd to Big-Dummy") || diag("chdir failed; $!"); + +my @mpl_out = run(qq{$perl Makefile.PL "INSTALL_BASE=../dummy-install"}); +END { rmtree '../dummy-install'; } + +cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || + diag(@mpl_out); + +my $makefile = makefile_name(); +ok( grep(/^Writing $makefile for Big::Dummy/, + @mpl_out) == 1, + 'Makefile.PL output looks right'); + +my $make = make_run(); +run("$make"); # this is necessary due to a dmake bug. +my $install_out = run("$make install"); +is( $?, 0, ' make install exited normally' ) || diag $install_out; +like( $install_out, qr/^Installing /m ); +like( $install_out, qr/^Writing /m ); + +ok( -r '../dummy-install', ' install dir created' ); + +my @installed_files = + ('../dummy-install/lib/perl5/Big/Dummy.pm', + '../dummy-install/lib/perl5/Big/Liar.pm', + '../dummy-install/bin/program', + "../dummy-install/lib/perl5/$Config{archname}/perllocal.pod", + "../dummy-install/lib/perl5/$Config{archname}/auto/Big/Dummy/.packlist" + ); + +foreach my $file (@installed_files) { + ok( -e $file, " $file installed" ); + ok( -r $file, " $file readable" ); +} + + +# nmake outputs its damned logo +# Send STDERR off to oblivion. +open(SAVERR, ">&STDERR") or die $!; +open(STDERR, ">".File::Spec->devnull) or die $!; + +my $realclean_out = run("$make realclean"); +is( $?, 0, 'realclean' ) || diag($realclean_out); + +open(STDERR, ">&SAVERR") or die $!; +close SAVERR; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/Install.t b/gnu/usr.bin/perl/lib/ExtUtils/t/Install.t index 6058811c265..ae8d7811047 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/Install.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/Install.t @@ -17,7 +17,7 @@ use TieOut; use File::Path; use File::Spec; -use Test::More tests => 32; +use Test::More tests => 38; use MakeMaker::Test::Setup::BFD; @@ -72,13 +72,14 @@ install( { 'blib/lib' => 'install-test/lib/perl', } ); ok( -d 'install-test/lib/perl', 'install made dir' ); ok( -r 'install-test/lib/perl/Big/Dummy.pm', ' .pm file installed' ); +ok(!-r 'install-test/lib/perl/Big/Dummy.SKIP', ' ignored .SKIP file' ); ok( -r 'install-test/packlist', ' packlist exists' ); open(PACKLIST, 'install-test/packlist' ); my %packlist = map { chomp; ($_ => 1) } <PACKLIST>; close PACKLIST; -# On case-insensitive filesystems (ie. VMS), the keys of the packlist might +# On case-insensitive filesystems (ie. VMS), the keys of the packlist might # be lowercase. :( my $native_dummy = File::Spec->catfile(qw(install-test lib perl Big Dummy.pm)); is( keys %packlist, 1 ); @@ -97,13 +98,32 @@ ok( -r 'install-test/packlist', ' packlist exists' ); ok( -r 'install-test/lib/perl/Big/Dummy.pm', ' UNINST=1 preserved same' ); - -# Test UNINST=1 removing other versions in other dirs. chmod 0644, 'blib/lib/Big/Dummy.pm' or die $!; open(DUMMY, ">>blib/lib/Big/Dummy.pm") or die $!; print DUMMY "Extra stuff\n"; close DUMMY; + +# Test UNINST=0 does not remove other versions in other dirs. +{ + ok( -r 'install-test/lib/perl/Big/Dummy.pm', 'different install exists' ); + + local @INC = ('install-test/lib/perl'); + local $ENV{PERL5LIB} = ''; + install( { 'blib/lib' => 'install-test/other_lib/perl', + read => 'install-test/packlist', + write => 'install-test/packlist' + }, + 0, 0, 0); + ok( -d 'install-test/other_lib/perl', 'install made other dir' ); + ok( -r 'install-test/other_lib/perl/Big/Dummy.pm', ' .pm file installed' ); + ok( -r 'install-test/packlist', ' packlist exists' ); + ok( -r 'install-test/lib/perl/Big/Dummy.pm', + ' UNINST=0 left different' ); +} + + +# Test UNINST=1 removing other versions in other dirs. { local @INC = ('install-test/lib/perl'); local $ENV{PERL5LIB} = ''; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/Installed.t b/gnu/usr.bin/perl/lib/ExtUtils/t/Installed.t index ba35deb691b..f820ef49c61 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/Installed.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/Installed.t @@ -21,7 +21,7 @@ use File::Path; use File::Basename; use File::Spec; -use Test::More tests => 46; +use Test::More tests => 63; BEGIN { use_ok( 'ExtUtils::Installed' ) } @@ -30,6 +30,10 @@ my $mandirs = !!$Config{man1direxp} + !!$Config{man3direxp}; # saves having to qualify package name for class methods my $ei = bless( {}, 'ExtUtils::Installed' ); +# Make sure meta info is available +$ei->{':private:'}{Config} = \%Config; +$ei->{':private:'}{INC} = \@INC; + # _is_prefix ok( $ei->_is_prefix('foo/bar', 'foo'), '_is_prefix() should match valid path prefix' ); @@ -53,7 +57,7 @@ foreach my $path (qw( man1dir man3dir )) { # VMS 5.6.1 doesn't seem to have $Config{prefixexp} my $prefix = $Config{prefix} || $Config{prefixexp}; -# You can concatenate /foo but not foo:, which defaults in the current +# You can concatenate /foo but not foo:, which defaults in the current # directory $prefix = VMS::Filespec::unixify($prefix) if $Is_VMS; @@ -65,7 +69,7 @@ ok( $ei->_is_type( File::Spec->catfile($prefix, 'bar'), 'prog'), SKIP: { skip('no man directories on this system', 1) unless $mandirs; - is( $ei->_is_type('bar', 'doc'), 0, + is( $ei->_is_type('bar', 'doc'), 0, '... should not find doc file outside path' ); } @@ -100,10 +104,10 @@ FAKE close FAKEMOD; +my $fake_mod_dir = File::Spec->catdir(cwd(), 'auto', 'FakeMod'); { # avoid warning and death by localizing glob local *ExtUtils::Installed::Config; - my $fake_mod_dir = File::Spec->catdir(cwd(), 'auto', 'FakeMod'); %ExtUtils::Installed::Config = ( %Config, archlibexp => cwd(), @@ -116,31 +120,98 @@ close FAKEMOD; my $realei = ExtUtils::Installed->new(); isa_ok( $realei, 'ExtUtils::Installed' ); isa_ok( $realei->{Perl}{packlist}, 'ExtUtils::Packlist' ); - is( $realei->{Perl}{version}, $Config{version}, + is( $realei->{Perl}{version}, $Config{version}, 'new() should set Perl version from %Config' ); ok( exists $realei->{FakeMod}, 'new() should find modules with .packlists'); isa_ok( $realei->{FakeMod}{packlist}, 'ExtUtils::Packlist' ); - is( $realei->{FakeMod}{version}, '1.1.1', + is( $realei->{FakeMod}{version}, '1.1.1', + '... should find version in modules' ); +} + +# Now try this using PERL5LIB +{ + local $ENV{PERL5LIB} = join $Config{path_sep}, $fake_mod_dir; + local *ExtUtils::Installed::Config; + %ExtUtils::Installed::Config = ( + %Config, + archlibexp => cwd(), + sitearchexp => cwd(), + ); + + my $realei = ExtUtils::Installed->new(); + isa_ok( $realei, 'ExtUtils::Installed' ); + isa_ok( $realei->{Perl}{packlist}, 'ExtUtils::Packlist' ); + is( $realei->{Perl}{version}, $Config{version}, + 'new() should set Perl version from %Config' ); + + ok( exists $realei->{FakeMod}, + 'new() should find modules with .packlists using PERL5LIB' + ); + isa_ok( $realei->{FakeMod}{packlist}, 'ExtUtils::Packlist' ); + is( $realei->{FakeMod}{version}, '1.1.1', + '... should find version in modules' ); +} + +# Do the same thing as the last block, but with overrides for +# %Config and @INC. +{ + my $config_override = { %Config::Config }; + $config_override->{archlibexp} = cwd(); + $config_override->{sitearchexp} = $fake_mod_dir; + $config_override->{version} = 'fake_test_version'; + + my @inc_override = (@INC, $fake_mod_dir); + + my $realei = ExtUtils::Installed->new( + 'config_override' => $config_override, + 'inc_override' => \@inc_override, + ); + isa_ok( $realei, 'ExtUtils::Installed' ); + isa_ok( $realei->{Perl}{packlist}, 'ExtUtils::Packlist' ); + is( $realei->{Perl}{version}, 'fake_test_version', + 'new(config_override => HASH) overrides %Config' ); + + ok( exists $realei->{FakeMod}, 'new() with overrides should find modules with .packlists'); + isa_ok( $realei->{FakeMod}{packlist}, 'ExtUtils::Packlist' ); + is( $realei->{FakeMod}{version}, '1.1.1', + '... should find version in modules' ); +} + +# Check if extra_libs works. +{ + my $realei = ExtUtils::Installed->new( + 'extra_libs' => [ cwd() ], + ); + isa_ok( $realei, 'ExtUtils::Installed' ); + isa_ok( $realei->{Perl}{packlist}, 'ExtUtils::Packlist' ); + ok( exists $realei->{FakeMod}, + 'new() with extra_libs should find modules with .packlists'); + + #{ use Data::Dumper; local $realei->{':private:'}{Config}; + # warn Dumper($realei); } + + isa_ok( $realei->{FakeMod}{packlist}, 'ExtUtils::Packlist' ); + is( $realei->{FakeMod}{version}, '1.1.1', '... should find version in modules' ); } # modules $ei->{$_} = 1 for qw( abc def ghi ); -is( join(' ', $ei->modules()), 'abc def ghi', +is( join(' ', $ei->modules()), 'abc def ghi', 'modules() should return sorted keys' ); # This didn't work for a long time due to a sort in scalar context oddity. is( $ei->modules, 3, 'modules() in scalar context' ); # files -$ei->{goodmod} = { - packlist => { - ($Config{man1direxp} ? - (File::Spec->catdir($Config{man1direxp}, 'foo') => 1) : +$ei->{goodmod} = { + packlist => { + ($Config{man1direxp} ? + (File::Spec->catdir($Config{man1direxp}, 'foo') => 1) : ()), - ($Config{man3direxp} ? - (File::Spec->catdir($Config{man3direxp}, 'bar') => 1) : + ($Config{man3direxp} ? + (File::Spec->catdir($Config{man3direxp}, 'bar') => 1) : ()), File::Spec->catdir($prefix, 'foobar') => 1, foobaz => 1, @@ -154,8 +225,8 @@ like( $@, qr/type must be/,'files() should croak given bad type' ); my @files; SKIP: { - skip('no man directory man1dir on this system', 2) - unless $Config{man1direxp}; + skip('no man directory man1dir on this system', 2) + unless $Config{man1direxp}; @files = $ei->files('goodmod', 'doc', $Config{man1direxp}); is( scalar @files, 1, '... should find doc file under given dir' ); is( (grep { /foo$/ } @files), 1, '... checking file name' ); @@ -190,22 +261,22 @@ is( scalar @dirs, 2 + $mandirs, '... should find all files files() would, again' is( join(' ', @files), join(' ', @dirs), '... should sort output' ); # directory_tree -my $expectdirs = - ($mandirs == 2) && +my $expectdirs = + ($mandirs == 2) && (dirname($Config{man1direxp}) eq dirname($Config{man3direxp})) ? 3 : 2; - + SKIP: { skip('no man directories on this system', 1) unless $mandirs; @dirs = $ei->directory_tree('goodmod', 'doc', $Config{man1direxp} ? dirname($Config{man1direxp}) : dirname($Config{man3direxp})); - is( scalar @dirs, $expectdirs, + is( scalar @dirs, $expectdirs, 'directory_tree() should report intermediate dirs to those requested' ); } my $fakepak = Fakepak->new(102); -$ei->{yesmod} = { +$ei->{yesmod} = { version => 101, packlist => $fakepak, }; @@ -213,20 +284,20 @@ $ei->{yesmod} = { # these should all croak foreach my $sub (qw( validate packlist version )) { eval { $ei->$sub('nomod') }; - like( $@, qr/nomod is not installed/, + like( $@, qr/nomod is not installed/, "$sub() should croak when asked about uninstalled module" ); } # validate -is( $ei->validate('yesmod'), 'validated', +is( $ei->validate('yesmod'), 'validated', 'validate() should return results of packlist validate() call' ); # packlist -is( ${ $ei->packlist('yesmod') }, 102, +is( ${ $ei->packlist('yesmod') }, 102, 'packlist() should report installed mod packlist' ); # version -is( $ei->version('yesmod'), 101, +is( $ei->version('yesmod'), 101, 'version() should report installed mod version' ); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_NW5.t b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_NW5.t index 13359d17fbc..f8a3635331c 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_NW5.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_NW5.t @@ -16,7 +16,7 @@ use Test::More; BEGIN { if ($^O =~ /NetWare/i) { - plan tests => 40; + plan tests => 39; } else { plan skip_all => 'This is not NW5'; } @@ -254,21 +254,6 @@ unlink "${script_name}$script_ext" if -f "${script_name}$script_ext"; 'tool_autosplit()' ); } -# tools_other() -{ - ( my $mm_w32 = bless { }, 'MM' )->init_others(); - - my $bin_sh = ( $Config{make} =~ /^dmake/i - ? "" : ($Config{sh} || 'cmd /c') . "\n" ); - $bin_sh = "SHELL = $bin_sh" if $bin_sh; - - my $tools = join "\n", map "$_ = $mm_w32->{ $_ }" - => qw(CHMOD CP LD MV NOOP RM_F RM_RF TEST_F TOUCH UMASK_NULL DEV_NULL); - - like( $mm_w32->tools_other(), - qr/^\Q$bin_sh$tools/m, - 'tools_other()' ); -}; # xs_o() should look into that # top_targets() should look into that diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Unix.t b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Unix.t index f9b07f8c0cc..ffcfd295de3 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Unix.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Unix.t @@ -18,7 +18,7 @@ BEGIN { plan skip_all => 'Non-Unix platform'; } else { - plan tests => 110; + plan tests => 109; } } @@ -176,11 +176,6 @@ chmod 0755, "command"; ok ($t->maybe_command('command'), "executable file is a command"); unlink "command"; -############################################################################### -# nicetext (dummy method) - -is ($t->nicetext('LOTR'),'LOTR','nicetext'); - ############################################################################### # perl_script (on unix any ordinary, readable file) diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_VMS.t b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_VMS.t index dcc5ed6230a..406b17f2ba2 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_VMS.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_VMS.t @@ -56,7 +56,6 @@ BEGIN { test_via_harness test_via_script makeaperl - nicetext )); } diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Win32.t b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Win32.t index 7acde33a949..866c135bc56 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Win32.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/MM_Win32.t @@ -37,6 +37,7 @@ my $MM = bless { MAKEFILE => 'Makefile', RM_RF => 'rm -rf', MV => 'mv', + MAKE => $Config{make} }, 'MM'; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/Manifest.t b/gnu/usr.bin/perl/lib/ExtUtils/t/Manifest.t index bba68439ad2..e8732ad9fc1 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/Manifest.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/Manifest.t @@ -13,12 +13,13 @@ chdir 't'; use strict; -use Test::More tests => 49; +use Test::More tests => 66; use Cwd; use File::Spec; use File::Path; use File::Find; +use Config; my $Is_VMS = $^O eq 'VMS'; @@ -46,7 +47,7 @@ sub read_manifest { } sub catch_warning { - my $warn; + my $warn = ''; local $SIG{__WARN__} = sub { $warn .= $_[0] }; return join('', $_[0]->() ), $warn; } @@ -71,8 +72,14 @@ ok( mkdir( 'mantest', 0777 ), 'make mantest directory' ); ok( chdir( 'mantest' ), 'chdir() to mantest' ); ok( add_file('foo'), 'add a temporary file' ); +# This ensures the -x check for manicopy means something +# Some platforms don't have chmod or an executable bit, in which case +# this call will do nothing or fail, but on the platforms where chmod() +# works, we test the executable bit is copied +chmod( 0744, 'foo') if $Config{'chmod'}; + # there shouldn't be a MANIFEST there -my ($res, $warn) = catch_warning( \&mkmanifest ); +my ($res, $warn) = catch_warning( \&mkmanifest ); # Canonize the order. $warn = join("", map { "$_|" } sort { lc($a) cmp lc($b) } split /\r?\n/, $warn); @@ -97,10 +104,10 @@ like( $warn, qr/^Not in MANIFEST: bar/, 'warning that bar has been added' ); is( $res, 'bar', 'bar reported as new' ); # now quiet the warning that bar was added and test again -($res, $warn) = do { local $ExtUtils::Manifest::Quiet = 1; - catch_warning( \&skipcheck ) +($res, $warn) = do { local $ExtUtils::Manifest::Quiet = 1; + catch_warning( \&skipcheck ) }; -ok( ! defined $warn, 'disabled warnings' ); +is( $warn, '', 'disabled warnings' ); # add a skip file with a rule to skip itself (and the nonexistent glob '*baz*') add_file( 'MANIFEST.SKIP', "baz\n.SKIP" ); @@ -164,7 +171,7 @@ is( ExtUtils::Manifest::maniread()->{none}, '#none', ok( mkdir( 'copy', 0777 ), 'made copy directory' ); $files = maniread(); eval { (undef, $warn) = catch_warning( sub { - manicopy( $files, 'copy', 'cp' ) }) + manicopy( $files, 'copy', 'cp' ) }) }; like( $@, qr/^Can't read none: /, 'croaked about none' ); @@ -179,7 +186,7 @@ like($warn, qr/^Skipping MANIFEST.SKIP/i, 'warned about MANIFEST.SKIP' ); local $ExtUtils::Manifest::MANIFEST = 'albatross'; ($res, $warn) = catch_warning( \&mkmanifest ); like( $warn, qr/Added to albatross: /, 'using a new manifest file' ); - + # add the new file to the list of files to be deleted $Files{'albatross'}++; } @@ -200,7 +207,7 @@ add_file( 'MANIFEST' => "foobar\n" ); add_file( 'foobar' => '123' ); ($res, $warn) = catch_warning( \&manicheck ); is( $res, '', 'MANIFEST overrides MANIFEST.SKIP' ); -is( $warn, undef, 'MANIFEST overrides MANIFEST.SKIP, no warnings' ); +is( $warn, '', 'MANIFEST overrides MANIFEST.SKIP, no warnings' ); $files = maniread; ok( !$files->{wibble}, 'MANIFEST in good state' ); @@ -211,6 +218,41 @@ is( $files->{wibble}, '', 'maniadd() with undef comment' ); is( $files->{yarrow}, 'hock',' with comment' ); is( $files->{foobar}, '', ' preserved old entries' ); +# test including an external manifest.skip file in MANIFEST.SKIP +{ + maniadd({ foo => undef , albatross => undef, + 'mymanifest.skip' => undef, 'mydefault.skip' => undef}); + add_file('mymanifest.skip' => "^foo\n"); + add_file('mydefault.skip' => "^my\n"); + $ExtUtils::Manifest::DEFAULT_MSKIP = + File::Spec->catfile($cwd, qw(mantest mydefault.skip)); + my $skip = File::Spec->catfile($cwd, qw(mantest mymanifest.skip)); + add_file('MANIFEST.SKIP' => + "albatross\n#!include $skip\n#!include_default"); + my ($res, $warn) = catch_warning( \&skipcheck ); + for (qw(albatross foo foobar mymanifest.skip mydefault.skip)) { + like( $warn, qr/Skipping \b$_\b/, + "Skipping $_" ); + } + ($res, $warn) = catch_warning( \&mkmanifest ); + for (qw(albatross foo foobar mymanifest.skip mydefault.skip)) { + like( $warn, qr/Removed from MANIFEST: \b$_\b/, + "Removed $_ from MANIFEST" ); + } + my $files = maniread; + ok( ! exists $files->{albatross}, 'albatross excluded via MANIFEST.SKIP' ); + ok( exists $files->{yarrow}, 'yarrow included in MANIFEST' ); + ok( exists $files->{bar}, 'bar included in MANIFEST' ); + ok( ! exists $files->{foobar}, 'foobar excluded via mymanifest.skip' ); + ok( ! exists $files->{foo}, 'foo excluded via mymanifest.skip' ); + ok( ! exists $files->{'mymanifest.skip'}, + 'mymanifest.skip excluded via mydefault.skip' ); + ok( ! exists $files->{'mydefault.skip'}, + 'mydefault.skip excluded via mydefault.skip' ); + my $extsep = $Is_VMS ? '_' : '.'; + $Files{"$_.bak"}++ for ('MANIFEST', "MANIFEST${extsep}SKIP"); +} + add_file('MANIFEST' => 'Makefile.PL'); maniadd({ foo => 'bar' }); $files = maniread; @@ -221,8 +263,8 @@ my %expect = ( 'makefile.pl' => '', ); is_deeply( $files, \%expect, 'maniadd() vs MANIFEST without trailing newline'); -add_file('MANIFEST' => 'Makefile.PL'); -maniadd({ foo => 'bar' }); +#add_file('MANIFEST' => 'Makefile.PL'); +#maniadd({ foo => 'bar' }); SKIP: { chmod( 0400, 'MANIFEST' ); diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/Packlist.t b/gnu/usr.bin/perl/lib/ExtUtils/t/Packlist.t index 58eaf8f6795..cb73e00d14b 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/Packlist.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/Packlist.t @@ -39,7 +39,7 @@ is( ExtUtils::Packlist::FETCH($pl, 'foo'), 'bar', 'check FETCH()' ); # test FIRSTKEY and NEXTKEY SKIP: { $pl->{data}{bar} = 'baz'; - skip('not enough keys to test FIRSTKEY', 2) + skip('not enough keys to test FIRSTKEY', 2) unless keys %{ $pl->{data} } > 2; # get the first and second key @@ -50,9 +50,9 @@ SKIP: { for (keys %{ $pl->{data} } ) { last if $i++; } - + # finally, see if it really can get the first key again - is( ExtUtils::Packlist::FIRSTKEY($pl), $first, + is( ExtUtils::Packlist::FIRSTKEY($pl), $first, 'FIRSTKEY() should be consistent' ); is( ExtUtils::Packlist::NEXTKEY($pl), $second, @@ -155,9 +155,9 @@ SKIP: { is( ExtUtils::Packlist::validate($pl), 1, 'validate() should find missing files' ); ExtUtils::Packlist::validate($pl, 1); - ok( !exists $pl->{data}{fake}, + ok( !exists $pl->{data}{fake}, 'validate() should remove missing files when prompted' ); - + # one more new() test, to see if it calls read() successfully $pl = ExtUtils::Packlist->new('eplist'); } diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/WriteEmptyMakefile.t b/gnu/usr.bin/perl/lib/ExtUtils/t/WriteEmptyMakefile.t new file mode 100644 index 00000000000..a5de6f16c94 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/WriteEmptyMakefile.t @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +# This is a test of WriteEmptyMakefile. + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = ('../lib', 'lib'); + } + else { + unshift @INC, 't/lib'; + } +} + +chdir 't'; + +use strict; +use Test::More tests => 5; + +use ExtUtils::MakeMaker qw(WriteEmptyMakefile); +use TieOut; + +can_ok __PACKAGE__, 'WriteEmptyMakefile'; + +eval { WriteEmptyMakefile("something"); }; +like $@, qr/Need an even number of args/; + + +{ + ok( my $stdout = tie *STDOUT, 'TieOut' ); + + ok !-e 'wibble'; + END { 1 while unlink 'wibble' } + + WriteEmptyMakefile( + NAME => "Foo", + FIRST_MAKEFILE => "wibble", + ); + ok -e 'wibble'; +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/basic.t b/gnu/usr.bin/perl/lib/ExtUtils/t/basic.t index ba476876263..64352d85cbd 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/basic.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/basic.t @@ -15,8 +15,9 @@ BEGIN { use strict; use Config; +use ExtUtils::MakeMaker; -use Test::More tests => 80; +use Test::More tests => 83; use MakeMaker::Test::Utils; use MakeMaker::Test::Setup::BFD; use File::Find; @@ -30,6 +31,9 @@ delete @ENV{qw(PREFIX LIB MAKEFLAGS)}; my $perl = which_perl(); my $Is_VMS = $^O eq 'VMS'; +# GNV logical interferes with testing +$ENV{'bin'} = '[.bin]' if $Is_VMS; + chdir 't'; perl_lib; @@ -102,7 +106,9 @@ like( $ppd_html, qr{^\s*<DEPENDENCY NAME="strict" VERSION="0,0,0,0" />}m, ' <DEPENDENCY>' ); like( $ppd_html, qr{^\s*<OS NAME="$Config{osname}" />}m, ' <OS>' ); -like( $ppd_html, qr{^\s*<ARCHITECTURE NAME="$Config{archname}" />}m, +my $archname = $Config{archname}; +$archname .= "-". substr($Config{version},0,3) if $] >= 5.008; +like( $ppd_html, qr{^\s*<ARCHITECTURE NAME="$archname" />}m, ' <ARCHITECTURE>'); like( $ppd_html, qr{^\s*<CODEBASE HREF="" />}m, ' <CODEBASE>'); like( $ppd_html, qr{^\s*</IMPLEMENTATION>}m, ' </IMPLEMENTATION>'); @@ -244,6 +250,27 @@ ok( !-f 'META.yml', 'META.yml not written to source dir' ); ok( -f $meta_yml, 'META.yml written to dist dir' ); ok( !-e "META_new.yml", 'temp META.yml file not left around' ); +ok open META, $meta_yml or diag $!; +my $meta = join '', <META>; +ok close META; + +is $meta, <<"END"; +--- #YAML:1.0 +name: Big-Dummy +version: 0.01 +abstract: Try "our" hot dog's +license: ~ +author: + - Michael G Schwern <schwern\@pobox.com> +generated_by: ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION +distribution_type: module +requires: + strict: 0 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 +END + my $manifest = maniread("$distdir/MANIFEST"); # VMS is non-case preserving, so we can't know what the MANIFEST will # look like. :( diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/build_man.t b/gnu/usr.bin/perl/lib/ExtUtils/t/build_man.t new file mode 100644 index 00000000000..4a544fbb53d --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/build_man.t @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w + +# Test if MakeMaker declines to build man pages under the right conditions. + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = ('../lib', 'lib'); + } + else { + unshift @INC, 't/lib'; + } +} + +use strict; +use Test::More tests => 9; + +use File::Spec; +use TieOut; +use MakeMaker::Test::Utils; +use MakeMaker::Test::Setup::BFD; + +use ExtUtils::MakeMaker; +use ExtUtils::MakeMaker::Config; + +# Simulate an installation which has man page generation turned off to +# ensure these tests will still work. +$Config{installman3dir} = 'none'; + +chdir 't'; + +perl_lib(); + +ok( setup_recurs(), 'setup' ); +END { + ok( chdir File::Spec->updir ); + ok( teardown_recurs(), 'teardown' ); +} + +ok( chdir 'Big-Dummy', "chdir'd to Big-Dummy" ) || + diag("chdir failed: $!"); + +ok( my $stdout = tie *STDOUT, 'TieOut' ); + +{ + local $Config{installman3dir} = File::Spec->catdir(qw(t lib)); + + my $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION_FROM => 'lib/Big/Dummy.pm', + ); + + ok( keys %{ $mm->{MAN3PODS} } ); +} + +{ + my $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION_FROM => 'lib/Big/Dummy.pm', + INSTALLMAN3DIR => 'none' + ); + + ok( !keys %{ $mm->{MAN3PODS} } ); +} + + +{ + my $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION_FROM => 'lib/Big/Dummy.pm', + MAN3PODS => {} + ); + + is_deeply( $mm->{MAN3PODS}, { } ); +} + + +{ + my $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION_FROM => 'lib/Big/Dummy.pm', + MAN3PODS => { "Foo.pm" => "Foo.1" } + ); + + is_deeply( $mm->{MAN3PODS}, { "Foo.pm" => "Foo.1" } ); +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/cd.t b/gnu/usr.bin/perl/lib/ExtUtils/t/cd.t new file mode 100644 index 00000000000..9d62d139e7c --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/cd.t @@ -0,0 +1,67 @@ +#!/usr/bin/perl -w + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ('../lib', 'lib/'); + } + else { + unshift @INC, 't/lib/'; + } +} +chdir 't'; + +my $Is_VMS = $^O eq 'VMS'; + +use File::Spec; + +use Test::More tests => 4; + +my @cd_args = ("some/dir", "command1", "command2"); + +{ + package Test::MM_Win32; + use ExtUtils::MM_Win32; + @ISA = qw(ExtUtils::MM_Win32); + + my $mm = bless {}, 'Test::MM_Win32'; + + { + local *make = sub { "nmake" }; + + my @dirs = (File::Spec->updir) x 2; + my $expected_updir = File::Spec->catdir(@dirs); + + ::is $mm->cd(@cd_args), +qq{cd some/dir + command1 + command2 + cd $expected_updir}; + } + + { + local *make = sub { "dmake" }; + + ::is $mm->cd(@cd_args), +q{cd some/dir && command1 + cd some/dir && command2}; + } +} + +{ + is +ExtUtils::MM_Unix->cd(@cd_args), +q{cd some/dir && command1 + cd some/dir && command2}; +} + +SKIP: { + skip("VMS' cd requires vmspath which is only on VMS", 1) unless $Is_VMS; + + use ExtUtils::MM_VMS; + is +ExtUtils::MM_VMS->cd(@cd_args), +q{startdir = F$Environment("Default") + Set Default [.some.dir] + command1 + command2 + Set Default 'startdir'}; +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/eu_command.t b/gnu/usr.bin/perl/lib/ExtUtils/t/eu_command.t new file mode 100644 index 00000000000..2d2fdbae223 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/eu_command.t @@ -0,0 +1,295 @@ +#!/usr/bin/perl -w + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ('../lib', 'lib/'); + } + else { + unshift @INC, 't/lib/'; + } +} +chdir 't'; + +BEGIN { + $Testfile = 'testfile.foo'; +} + +BEGIN { + 1 while unlink $Testfile, 'newfile'; + # forcibly remove ecmddir/temp2, but don't import mkpath + use File::Path (); + File::Path::rmtree( 'ecmddir' ); +} + +BEGIN { + use Test::More tests => 41; + use File::Spec; +} + +BEGIN { + # bad neighbor, but test_f() uses exit() + *CORE::GLOBAL::exit = ''; # quiet 'only once' warning. + *CORE::GLOBAL::exit = sub (;$) { return $_[0] }; + use_ok( 'ExtUtils::Command' ); +} + +{ + # concatenate this file with itself + # be extra careful the regex doesn't match itself + use TieOut; + my $out = tie *STDOUT, 'TieOut'; + my $self = $0; + unless (-f $self) { + my ($vol, $dirs, $file) = File::Spec->splitpath($self); + my @dirs = File::Spec->splitdir($dirs); + unshift(@dirs, File::Spec->updir); + $dirs = File::Spec->catdir(@dirs); + $self = File::Spec->catpath($vol, $dirs, $file); + } + @ARGV = ($self, $self); + + cat(); + is( scalar( $$out =~ s/use_ok\( 'ExtUtils::Command'//g), 2, + 'concatenation worked' ); + + # the truth value here is reversed -- Perl true is shell false + @ARGV = ( $Testfile ); + is( test_f(), 1, 'testing non-existent file' ); + + @ARGV = ( $Testfile ); + is( ! test_f(), '', 'testing non-existent file' ); + + # these are destructive, have to keep setting @ARGV + @ARGV = ( $Testfile ); + touch(); + + @ARGV = ( $Testfile ); + is( test_f(), 0, 'testing touch() and test_f()' ); + is_deeply( \@ARGV, [$Testfile], 'test_f preserves @ARGV' ); + + @ARGV = ( $Testfile ); + ok( -e $ARGV[0], 'created!' ); + + my ($now) = time; + utime ($now, $now, $ARGV[0]); + sleep 2; + + # Just checking modify time stamp, access time stamp is set + # to the beginning of the day in Win95. + # There's a small chance of a 1 second flutter here. + my $stamp = (stat($ARGV[0]))[9]; + cmp_ok( abs($now - $stamp), '<=', 1, 'checking modify time stamp' ) || + diag "mtime == $stamp, should be $now"; + + @ARGV = qw(newfile); + touch(); + + my $new_stamp = (stat('newfile'))[9]; + cmp_ok( abs($new_stamp - $stamp), '>=', 2, 'newer file created' ); + + @ARGV = ('newfile', $Testfile); + eqtime(); + + $stamp = (stat($Testfile))[9]; + cmp_ok( abs($new_stamp - $stamp), '<=', 1, 'eqtime' ); + + # eqtime use to clear the contents of the file being equalized! + open(FILE, ">>$Testfile") || die $!; + print FILE "Foo"; + close FILE; + + @ARGV = ('newfile', $Testfile); + eqtime(); + ok( -s $Testfile, "eqtime doesn't clear the file being equalized" ); + + SKIP: { + if ($^O eq 'amigaos' || $^O eq 'os2' || $^O eq 'MSWin32' || + $^O eq 'NetWare' || $^O eq 'dos' || $^O eq 'cygwin' || + $^O eq 'MacOS' + ) { + skip( "different file permission semantics on $^O", 3); + } + + # change a file to execute-only + @ARGV = ( '0100', $Testfile ); + ExtUtils::Command::chmod(); + + is( ((stat($Testfile))[2] & 07777) & 0700, + 0100, 'change a file to execute-only' ); + + # change a file to read-only + @ARGV = ( '0400', $Testfile ); + ExtUtils::Command::chmod(); + + is( ((stat($Testfile))[2] & 07777) & 0700, + ($^O eq 'vos' ? 0500 : 0400), 'change a file to read-only' ); + + # change a file to write-only + @ARGV = ( '0200', $Testfile ); + ExtUtils::Command::chmod(); + + is( ((stat($Testfile))[2] & 07777) & 0700, + ($^O eq 'vos' ? 0700 : 0200), 'change a file to write-only' ); + } + + # change a file to read-write + @ARGV = ( '0600', $Testfile ); + my @orig_argv = @ARGV; + ExtUtils::Command::chmod(); + is_deeply( \@ARGV, \@orig_argv, 'chmod preserves @ARGV' ); + + is( ((stat($Testfile))[2] & 07777) & 0700, + ($^O eq 'vos' ? 0700 : 0600), 'change a file to read-write' ); + + + SKIP: { + if ($^O eq 'amigaos' || $^O eq 'os2' || $^O eq 'MSWin32' || + $^O eq 'NetWare' || $^O eq 'dos' || $^O eq 'cygwin' || + $^O eq 'MacOS' + ) { + skip( "different file permission semantics on $^O", 5); + } + + @ARGV = ('testdir'); + mkpath; + ok( -e 'testdir' ); + + # change a dir to execute-only + @ARGV = ( '0100', 'testdir' ); + ExtUtils::Command::chmod(); + + is( ((stat('testdir'))[2] & 07777) & 0700, + 0100, 'change a dir to execute-only' ); + + # change a dir to read-only + @ARGV = ( '0400', 'testdir' ); + ExtUtils::Command::chmod(); + + is( ((stat('testdir'))[2] & 07777) & 0700, + ($^O eq 'vos' ? 0500 : 0400), 'change a dir to read-only' ); + + # change a dir to write-only + @ARGV = ( '0200', 'testdir' ); + ExtUtils::Command::chmod(); + + is( ((stat('testdir'))[2] & 07777) & 0700, + ($^O eq 'vos' ? 0700 : 0200), 'change a dir to write-only' ); + + @ARGV = ('testdir'); + rm_rf; + ok( ! -e 'testdir', 'rm_rf can delete a read-only dir' ); + } + + + # mkpath + my $test_dir = File::Spec->join( 'ecmddir', 'temp2' ); + @ARGV = ( $test_dir ); + ok( ! -e $ARGV[0], 'temp directory not there yet' ); + is( test_d(), 1, 'testing non-existent directory' ); + + @ARGV = ( $test_dir ); + mkpath(); + ok( -e $ARGV[0], 'temp directory created' ); + is( test_d(), 0, 'testing existing dir' ); + + @ARGV = ( $test_dir ); + # copy a file to a nested subdirectory + unshift @ARGV, $Testfile; + @orig_argv = @ARGV; + cp(); + is_deeply( \@ARGV, \@orig_argv, 'cp preserves @ARGV' ); + + ok( -e File::Spec->join( 'ecmddir', 'temp2', $Testfile ), 'copied okay' ); + + # cp should croak if destination isn't directory (not a great warning) + @ARGV = ( $Testfile ) x 3; + eval { cp() }; + + like( $@, qr/Too many arguments/, 'cp croaks on error' ); + + # move a file to a subdirectory + @ARGV = ( $Testfile, 'ecmddir' ); + @orig_argv = @ARGV; + ok( mv() ); + is_deeply( \@ARGV, \@orig_argv, 'mv preserves @ARGV' ); + + ok( ! -e $Testfile, 'moved file away' ); + ok( -e File::Spec->join( 'ecmddir', $Testfile ), 'file in new location' ); + + # mv should also croak with the same wacky warning + @ARGV = ( $Testfile ) x 3; + + eval { mv() }; + like( $@, qr/Too many arguments/, 'mv croaks on error' ); + + # Test expand_wildcards() + { + my $file = $Testfile; + @ARGV = (); + chdir 'ecmddir'; + + # % means 'match one character' on VMS. Everything else is ? + my $match_char = $^O eq 'VMS' ? '%' : '?'; + ($ARGV[0] = $file) =~ s/.\z/$match_char/; + + # this should find the file + ExtUtils::Command::expand_wildcards(); + + is_deeply( \@ARGV, [$file], 'expanded wildcard ? successfully' ); + + # try it with the asterisk now + ($ARGV[0] = $file) =~ s/.{3}\z/\*/; + ExtUtils::Command::expand_wildcards(); + + is_deeply( \@ARGV, [$file], 'expanded wildcard * successfully' ); + + chdir File::Spec->updir; + } + + # remove some files + my @files = @ARGV = ( File::Spec->catfile( 'ecmddir', $Testfile ), + File::Spec->catfile( 'ecmddir', 'temp2', $Testfile ) ); + rm_f(); + + ok( ! -e $_, "removed $_ successfully" ) for (@ARGV); + + # rm_f dir + @ARGV = my $dir = File::Spec->catfile( 'ecmddir' ); + rm_rf(); + ok( ! -e $dir, "removed $dir successfully" ); +} + +{ + { local @ARGV = 'd2utest'; mkpath; } + open(FILE, '>d2utest/foo'); + binmode(FILE); + print FILE "stuff\015\012and thing\015\012"; + close FILE; + + open(FILE, '>d2utest/bar'); + binmode(FILE); + my $bin = "\c@\c@\c@\c@\c@\c@\cA\c@\c@\c@\015\012". + "\@\c@\cA\c@\c@\c@8__LIN\015\012"; + print FILE $bin; + close FILE; + + local @ARGV = 'd2utest'; + ExtUtils::Command::dos2unix(); + + open(FILE, 'd2utest/foo'); + is( join('', <FILE>), "stuff\012and thing\012", 'dos2unix' ); + close FILE; + + open(FILE, 'd2utest/bar'); + binmode(FILE); + ok( -B 'd2utest/bar' ); + is( join('', <FILE>), $bin, 'dos2unix preserves binaries'); + close FILE; +} + +END { + 1 while unlink $Testfile, 'newfile'; + File::Path::rmtree( 'ecmddir' ); + File::Path::rmtree( 'd2utest' ); +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/fixin.t b/gnu/usr.bin/perl/lib/ExtUtils/t/fixin.t new file mode 100644 index 00000000000..69c0ac722b8 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/fixin.t @@ -0,0 +1,45 @@ +#!/usr/bin/perl -w + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ('../lib', 'lib/'); + } + else { + unshift @INC, 't/lib/'; + } +} +chdir 't'; + +use File::Spec; + +use Test::More tests => 6; + +use TieOut; +use MakeMaker::Test::Utils; +use MakeMaker::Test::Setup::BFD; + +use ExtUtils::MakeMaker; + +chdir 't'; + +perl_lib(); + +ok( setup_recurs(), 'setup' ); +END { + ok( chdir File::Spec->updir ); + ok( teardown_recurs(), 'teardown' ); +} + +ok( chdir 'Big-Dummy', "chdir'd to Big-Dummy" ) || + diag("chdir failed: $!"); + +# [rt.cpan.org 26234] +{ + local $/ = "foo"; + local $\ = "bar"; + MY->fixin("bin/program"); + is $/, "foo", '$/ not clobbered'; + is $\, "bar", '$\ not clobbered'; +} + diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/make.t b/gnu/usr.bin/perl/lib/ExtUtils/t/make.t new file mode 100644 index 00000000000..3a1626028f9 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/make.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ('../lib', 'lib/'); + } + else { + unshift @INC, 't/lib/'; + } +} + +use Test::More tests => 3; + +use ExtUtils::MakeMaker; + +my $MM = bless { MAKE => "nmake6" }, "MM"; +is $MM->make, 'nmake'; + +$MM->{MAKE} = 'GNUmake'; +is $MM->make, 'gmake'; + +$MM->{MAKE} = 'MMS'; +is $MM->make, 'mms'; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/maketext_filter.t b/gnu/usr.bin/perl/lib/ExtUtils/t/maketext_filter.t new file mode 100644 index 00000000000..ed3a44d6013 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/maketext_filter.t @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = '../lib'; + } + else { + unshift @INC, 't/lib'; + } +} +chdir 't'; + +use Test::More tests => 6; + +use ExtUtils::MakeMaker; +use ExtUtils::MM_VMS; + +sub test_filter { + my($text, $vms_text) = @_; + + local $Test::Builder::Level = $Test::Builder::Level + 1; + is( ExtUtils::MM_Any->maketext_filter($text), $text, 'default filter' ); + is( ExtUtils::MM_VMS->maketext_filter($text), $vms_text, 'VMS filter' ); +} + + +# VMS filter puts a space after the target +test_filter(<<'END', <<'VMS'); +foo: bar + thing: splat +END +foo : bar + thing: splat +VMS + + +# And it does it for all targets +test_filter(<<'END', <<'VMS'); +foo: bar + thing: splat + +up: down + yes +END +foo : bar + thing: splat + +up : down + yes +VMS + + +# And it doesn't mess with macros +test_filter(<<'END', <<'VMS'); +CLASS=Foo: Bar + +target: stuff + $(PROGRAM) And::Stuff +END +CLASS=Foo: Bar + +target : stuff + $(PROGRAM) And::Stuff +VMS diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/parse_version.t b/gnu/usr.bin/perl/lib/ExtUtils/t/parse_version.t index 8d2a8d0c505..74621734334 100755 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/parse_version.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/parse_version.t @@ -11,24 +11,63 @@ BEGIN { } chdir 't'; -use Test::More tests => 10; +use Test::More; use ExtUtils::MakeMaker; -my %versions = ('$VERSION = 0.02' => 0.02, - '$VERSION = 0.0' => 0.0, - '$VERSION = -1.0' => -1.0, - '$VERSION = undef' => 'undef', - '$wibble = 1.0' => 'undef', +my $Has_Version = eval 'require version; "version"->import; 1'; + +my %versions = (q[$VERSION = '1.00'] => '1.00', + q[*VERSION = \'1.01'] => '1.01', + q[($VERSION) = q$Revision: 1.1.1.2 $ =~ /(\d+)/g;] => 32208, + q[$FOO::VERSION = '1.10';] => '1.10', + q[*FOO::VERSION = \'1.11';] => '1.11', + '$VERSION = 0.02' => 0.02, + '$VERSION = 0.0' => 0.0, + '$VERSION = -1.0' => -1.0, + '$VERSION = undef' => 'undef', + '$wibble = 1.0' => 'undef', + q[my $VERSION = '1.01'] => 'undef', + q[local $VERISON = '1.02'] => 'undef', + q[local $FOO::VERSION = '1.30'] => 'undef', + q[our $VERSION = '1.23';] => '1.23', ); +if( $Has_Version ) { + $versions{q[use version; $VERSION = qv("1.2.3");]} = qv("1.2.3"); + $versions{q[$VERSION = qv("1.2.3")]} = qv("1.2.3"); +} + +plan tests => (2 * keys %versions) + 4; + while( my($code, $expect) = each %versions ) { + is( parse_version_string($code), $expect, $code ); +} + + +sub parse_version_string { + my $code = shift; + open(FILE, ">VERSION.tmp") || die $!; print FILE "$code\n"; close FILE; $_ = 'foo'; - is( MM->parse_version('VERSION.tmp'), $expect, $code ); + my $version = MM->parse_version('VERSION.tmp'); is( $_, 'foo', '$_ not leaked by parse_version' ); - + unlink "VERSION.tmp"; + + return $version; +} + + +# This is a specific test to see if a version subroutine in the $VERSION +# declaration confuses later calls to the version class. +# [rt.cpan.org 30747] +SKIP: { + skip "need version.pm", 4 unless $Has_Version; + is parse_version_string(q[ $VERSION = '1.00'; sub version { $VERSION } ]), + '1.00'; + is parse_version_string(q[ use version; $VERSION = version->new("1.2.3") ]), + qv("1.2.3"); } diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/pm.t b/gnu/usr.bin/perl/lib/ExtUtils/t/pm.t new file mode 100644 index 00000000000..1f6952710c0 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/pm.t @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +# Test that MakeMaker honors user's PM override. + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = ('../lib', 'lib'); + } + else { + unshift @INC, 't/lib'; + } +} + +use strict; +use Test::More tests => 6; + +use TieOut; +use MakeMaker::Test::Utils; +use MakeMaker::Test::Setup::BFD; + +use ExtUtils::MakeMaker; + +chdir 't'; + +perl_lib(); + +ok( setup_recurs(), 'setup' ); +END { + ok( chdir File::Spec->updir ); + ok( teardown_recurs(), 'teardown' ); +} + +ok( chdir 'Big-Dummy', "chdir'd to Big-Dummy" ) || + diag("chdir failed: $!"); + +ok( my $stdout = tie *STDOUT, 'TieOut' ); + +{ + my $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION_FROM => 'lib/Big/Dummy.pm', + PM => { 'wibble' => 'woof' } + ); + + is_deeply( $mm->{PM}, { wibble => 'woof' } ); +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/prereq.t b/gnu/usr.bin/perl/lib/ExtUtils/t/prereq.t new file mode 100644 index 00000000000..c690a55a02e --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/prereq.t @@ -0,0 +1,133 @@ +#!/usr/bin/perl -w + +# This is a test of the verification of the arguments to +# WriteMakefile. + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = ('../lib', 'lib'); + } + else { + unshift @INC, 't/lib'; + } +} + +use strict; +use Test::More tests => 13; + +use TieOut; +use MakeMaker::Test::Utils; +use MakeMaker::Test::Setup::BFD; + +use ExtUtils::MakeMaker; + +chdir 't'; + +perl_lib(); + +ok( setup_recurs(), 'setup' ); +END { + ok( chdir File::Spec->updir ); + ok( teardown_recurs(), 'teardown' ); +} + +ok( chdir 'Big-Dummy', "chdir'd to Big-Dummy" ) || + diag("chdir failed: $!"); + +{ + ok( my $stdout = tie *STDOUT, 'TieOut' ); + my $warnings = ''; + local $SIG{__WARN__} = sub { + $warnings .= join '', @_; + }; + + WriteMakefile( + NAME => 'Big::Dummy', + PREREQ_PM => { + strict => 0 + } + ); + is $warnings, ''; + + $warnings = ''; + WriteMakefile( + NAME => 'Big::Dummy', + PREREQ_PM => { + strict => 99999 + } + ); + is $warnings, + sprintf("Warning: prerequisite strict 99999 not found. We have %s.\n", + strict->VERSION); + + $warnings = ''; + WriteMakefile( + NAME => 'Big::Dummy', + PREREQ_PM => { + "I::Do::Not::Exist" => 0, + } + ); + is $warnings, + "Warning: prerequisite I::Do::Not::Exist 0 not found.\n"; + + $warnings = ''; + WriteMakefile( + NAME => 'Big::Dummy', + PREREQ_PM => { + "I::Do::Not::Exist" => 0, + "strict" => 99999, + } + ); + is $warnings, + "Warning: prerequisite I::Do::Not::Exist 0 not found.\n". + sprintf("Warning: prerequisite strict 99999 not found. We have %s.\n", + strict->VERSION); + + $warnings = ''; + eval { + WriteMakefile( + NAME => 'Big::Dummy', + PREREQ_PM => { + "I::Do::Not::Exist" => 0, + "Nor::Do::I" => 0, + "strict" => 99999, + }, + PREREQ_FATAL => 1, + ); + }; + + is $warnings, ''; + is $@, <<'END', "PREREQ_FATAL"; +MakeMaker FATAL: prerequisites not found. + I::Do::Not::Exist not installed + Nor::Do::I not installed + strict 99999 + +Please install these modules first and rerun 'perl Makefile.PL'. +END + + + $warnings = ''; + eval { + WriteMakefile( + NAME => 'Big::Dummy', + PREREQ_PM => { + "I::Do::Not::Exist" => 0, + }, + CONFIGURE => sub { + require I::Do::Not::Exist; + }, + PREREQ_FATAL => 1, + ); + }; + + is $warnings, ''; + is $@, <<'END', "PREREQ_FATAL happens before CONFIGURE"; +MakeMaker FATAL: prerequisites not found. + I::Do::Not::Exist not installed + +Please install these modules first and rerun 'perl Makefile.PL'. +END + +} diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/recurs.t b/gnu/usr.bin/perl/lib/ExtUtils/t/recurs.t index 53bdf478dc1..17da39ee398 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/recurs.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/recurs.t @@ -15,7 +15,7 @@ BEGIN { use strict; use Config; -use Test::More tests => 25; +use Test::More tests => 26; use MakeMaker::Test::Utils; use MakeMaker::Test::Setup::Recurs; @@ -111,3 +111,12 @@ ok( open(MAKEFILE, $submakefile) ) || diag("Can't open $submakefile: $!"); 'prepend .. not stomping WriteMakefile args' ) } close MAKEFILE; + + +{ + # Quiet "make test" failure noise + close *STDERR; + + my $test_out = run("$make test"); + isnt $?, 0, 'test failure in a subdir causes make to fail'; +}
\ No newline at end of file diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/revision.t b/gnu/usr.bin/perl/lib/ExtUtils/t/revision.t new file mode 100644 index 00000000000..896b1914ca0 --- /dev/null +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/revision.t @@ -0,0 +1,23 @@ +#!/usr/bin/perl -w + +BEGIN { + if( $ENV{PERL_CORE} ) { + chdir 't' if -d 't'; + @INC = ('../lib', 'lib'); + } + else { + unshift @INC, 't/lib'; + } +} + +use Test::More tests => 4; + +BEGIN { + use_ok 'ExtUtils::MakeMaker'; + use_ok 'ExtUtils::MM_VMS'; +} + +# Why 1? Because a common mistake is for the regex to run in scalar context +# thus getting the count of captured elements (1) rather than the value of $1 +cmp_ok $ExtUtils::MakeMaker::Revision, '>', 1; +cmp_ok $ExtUtils::MM_VMS::Revision, '>', 1; diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/writemakefile_args.t b/gnu/usr.bin/perl/lib/ExtUtils/t/writemakefile_args.t index a19a5ee644b..da274d6cc7c 100644 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/writemakefile_args.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/writemakefile_args.t @@ -14,7 +14,7 @@ BEGIN { } use strict; -use Test::More tests => 16; +use Test::More tests => 28; use TieOut; use MakeMaker::Test::Utils; @@ -53,7 +53,7 @@ ok( chdir 'Big-Dummy', "chdir'd to Big-Dummy" ) || }; is( $warnings, <<VERIFY ); -WARNING: MAN3PODS takes a hash reference not a string/number. +WARNING: MAN3PODS takes a HASH reference not a string/number. Please inform the author. VERIFY @@ -67,7 +67,7 @@ VERIFY }; is( $warnings, <<VERIFY ); -WARNING: AUTHOR takes a string/number not a code reference. +WARNING: AUTHOR takes a string/number not a CODE reference. Please inform the author. VERIFY @@ -105,7 +105,7 @@ VERIFY }; # We'll get warnings about the bogus libs, that's ok. - like( $warnings, qr{^WARNING: LIBS takes a array reference or string/number not a hash reference}m ); + like( $warnings, qr{^WARNING: LIBS takes a ARRAY reference or string/number not a HASH reference}m ); $warnings = ''; @@ -120,4 +120,75 @@ VERIFY is( $mm->{WIBBLE}, 'something' ); is_deeply( $mm->{wump}, { foo => 42 } ); -} + + + # Test VERSION + $warnings = ''; + eval { + $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION => [1,2,3], + ); + }; + like( $warnings, qr{^WARNING: VERSION takes a version object or string/number} ); + + $warnings = ''; + eval { + $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION => 1.002_003, + ); + }; + is( $warnings, '' ); + is( $mm->{VERSION}, '1.002003' ); + + $warnings = ''; + eval { + $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION => '1.002_003', + ); + }; + is( $warnings, '' ); + is( $mm->{VERSION}, '1.002_003' ); + + + $warnings = ''; + eval { + $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION => bless {}, "Some::Class", + ); + }; + like( $warnings, '/^WARNING: VERSION takes a version object or string/number not a Some::Class object/' ); + + + SKIP: { + skip("Can't test version objects",6) unless eval { require version }; + version->import; + + my $version = version->new("1.2.3"); + $warnings = ''; + eval { + $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION => $version, + ); + }; + is( $warnings, '' ); + isa_ok( $mm->{VERSION}, 'version' ); + is( $mm->{VERSION}, $version ); + + $warnings = ''; + $version = qv('1.2.3'); + eval { + $mm = WriteMakefile( + NAME => 'Big::Dummy', + VERSION => $version, + ); + }; + is( $warnings, '' ); + isa_ok( $mm->{VERSION}, 'version' ); + is( $mm->{VERSION}, $version ); + } +}
\ No newline at end of file diff --git a/gnu/usr.bin/perl/lib/ExtUtils/t/xs.t b/gnu/usr.bin/perl/lib/ExtUtils/t/xs.t index 62d29eae798..1cadc109b77 100755 --- a/gnu/usr.bin/perl/lib/ExtUtils/t/xs.t +++ b/gnu/usr.bin/perl/lib/ExtUtils/t/xs.t @@ -13,12 +13,49 @@ chdir 't'; use Test::More; use MakeMaker::Test::Utils; +use MakeMaker::Test::Setup::XS; +use File::Find; +use File::Spec; +use File::Path; if( have_compiler() ) { - plan tests => 1; + plan tests => 7; } else { plan skip_all => "ExtUtils::CBuilder not installed or couldn't find a compiler"; } -pass("You have a compiler, isn't that great?"); +my $Is_VMS = $^O eq 'VMS'; +my $perl = which_perl(); + +# GNV logical interferes with testing +$ENV{'bin'} = '[.bin]' if $Is_VMS; + +chdir 't'; + +perl_lib; + +$| = 1; + +ok( setup_xs(), 'setup' ); +END { + ok( chdir File::Spec->updir ); + ok( teardown_xs(), 'teardown' ); +} + +ok( chdir('XS-Test'), "chdir'd to XS-Test" ) || + diag("chdir failed: $!"); + +my @mpl_out = run(qq{$perl Makefile.PL}); + +cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || + diag(@mpl_out); + +my $make = make_run(); +my $make_out = run("$make"); +is( $?, 0, ' make exited normally' ) || + diag $make_out; + +my $test_out = run("$make"); +is( $?, 0, ' make test exited normally' ) || + diag $test_out; |