diff options
Diffstat (limited to 'dist')
19 files changed, 3060 insertions, 0 deletions
diff --git a/dist/ExtUtils-CBuilder/Changes b/dist/ExtUtils-CBuilder/Changes new file mode 100644 index 0000000000..41b4de2d72 --- /dev/null +++ b/dist/ExtUtils-CBuilder/Changes @@ -0,0 +1,390 @@ +Revision history for Perl extension ExtUtils::CBuilder. + +0.2802 - Sun Dec 12 07:22:43 EST 2010 + + Fixed: + + - Incorporated another t/04-base.t fix from bleadperl + [Chris Williams] + +0.2801 - Wed Dec 8 21:36:56 EST 2010 + + Fixed: + + - Fixed spurious t/04-base.t failure when run from Perl core + [David Golden] + +0.2800 - Mon Dec 6 16:05:46 EST 2010 + + - No changes from 0.27_07 + +0.27_07 - Wed Sep 29 21:48:55 EDT 2010 + + Fixed: + + - Fixed t/02-link.t on perl < 5.8 + +0.27_06 - Mon Sep 27 15:29:54 EDT 2010 + + Fixed: + + - Preserves exit status on VMS [Craig Berry] + + - Fix Win32 split_like_shell escaping [Christian Walde] + +0.27_05 - Wed Jul 28 15:29:59 EDT 2010 + + Fixed: + + - Tests no longer fail if user has set the CC environment variable + +0.27_04 - Mon Jul 26 22:41:43 EDT 2010 + + Added: + - handle c compiler and c++ compiler separately + (adds requirement for IPC::Cmd) [Jens Rehsack] + + Others: + - rely on File::Temp::tempfile and File::Spec::tmpdir to + get unique file name for checking for compiler + [Jens Rehsack] + + - Code base modernization and substantial code coverage improvments + [Jim Keenan] + +0.2703 - Tue Mar 16 17:10:55 EDT 2010 + + Bugs fixed: + - fixed tests for Windows and MSVC [Jan Dubois] + +0.2702 - Mon Feb 22 15:10:52 EST 2010 + + Bugs fixed: + - compile() changes in 0.2701 did not work on Windows. Now fixed. + +0.2701 - Tue Feb 16 09:12:45 EST 2010 + + Bugs fixed: + - compile() now accepts both string & array for 'include_dirs' + argument, as documented.(RT#54606) [Alberto Simões] + +0.27 - Thu Oct 29 21:29:56 EDT 2009 + + Other: + - Removed Build.PL to avoid creating a circular dependency + - Added version numbers to Windows compiler driver modules + +0.26_05 - Sun Oct 25 17:29:02 EDT 2009 + + Bugs fixed: + - Fixed t/02link.t failures on cygwin with Perl 5.8 [David Golden] + + Other: + - Made have_compiler (and have_cplusplus) quiet without echoing + the test command to STDOUT [David Golden] + +0.26_04 - Mon Oct 19 21:57:46 EDT 2009 + + Enhancements: + - Added 'have_cplusplus()' method to check for C++ support + - Added patches for building Perl with mingw64 [Sisyphus] + - Allow CC environment variable to override $Config{cc} + + Bugs fixed: + - Fixed link executable command for Win32 MSVC (RT#40819) [Cosimo + Streppone] + - Removed MSVC version check when embedding a manifest file + (RT #43002) [Steve Hay] + + Other: + - Split Windows compiler driver packages into individual *.pm files + +0.260301 - Sat Aug 29 11:04:41 EDT 2009 + + Bugs fixed: + - Fixed linking error on Win32 with gcc compiler (RT#49000) + [kmx] + +0.2603 - Sat Jul 18 06:56:06 EDT 2009 + + Bugs fixed: + - Makefile.PL had wrong INSTALLDIRS setting for older Perls + (RT#47985) [David Golden] + +0.2602 - Sat Jul 4 10:57:12 EDT 2009 + + Bugs fixed: + - Fixed 00-have-compiler.t if $^X is a relative path [David Wheeler] + +0.2601 - Wed Jul 1 09:37:39 EDT 2009 + + Bugs fixed: + - On VMS, cleans up extra files generated during testing + [John E. Malmberg, Craig Berry] + +0.26 - Mon Jun 29 20:11:52 EDT 2009 + + - No changes from 0.25_01 + +0.25_01 - Sat Jun 27 23:13:20 EDT 2009 + + - Changed test library to Test::More + + - Added tests for have_compiler + + - Skips tests that need a compiler if have_compiler is false + + - have_compiler will try to compile in the current directory + if compiling in tmpdir fails for whatever reason + +0.25 - Fri Jun 26 16:18:13 EDT 2009 + + - Slight diagnostic improvements in link.t + +0.24_01 - Sun Mar 8 14:50:10 2009 + + - On Windows, don't generate "mt" command when CRT is statically + linked. [Jan Dubois] + + - On Cygwin, examine $Config{useshrplib} to see whether we're + supposed to be linking with a shared perl library or not. [Reini + Urban] + + - In link_executable() on Cygwin, trust $Config{ld} rather than using + $Config{cc} for linking. [Reini Urban] + + - Add 'haiku' as a Unix-like platform. [Ingo Weinhold] + +0.24 - Fri Aug 15 22:01:48 2008 + + - Added 'gnu' and 'gnukfreebsd' as Unix variants. [Niko Tyni] + + - Brought in some VMS fixes from bleadperl: "Correct and complete + CBuilder's handling of external libraries when linking on VMS." + [Craig Berry] + +0.23 - Sat Apr 19 22:28:03 2008 + + - Fixed some problems (some old, some new) with Strawberry Perl on + Windows. [Alberto Simo~es] + + - Will now install in the core perl lib directory when the user's + perl is new enough to have us in core. [Yi Ma Mao] + +0.22 - Fri Feb 8 21:52:21 2008 + + - Replaced the split_like_shell() method on Windows with a + near-no-op, which is probably more correct and has the benefit of + not messing up UNC paths. [John R. LoVerso, see + http://rt.cpan.org/Ticket/Display.html?id=26545] + + - Fixed extra_compiler_flags on Windows, they were being + ignored. [Robert May] + +0.21 - Tue Oct 30 06:46:01 2007 + + - 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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder.pm new file mode 100644 index 0000000000..e93e4f3469 --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder.pm @@ -0,0 +1,331 @@ +package ExtUtils::CBuilder; + +use File::Spec (); +use File::Path (); +use File::Basename (); + +use vars qw($VERSION @ISA); +$VERSION = '0.2802'; +$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 + gnu Unix + gnukfreebsd Unix + haiku 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. The sample will be compiled in the system +tempdir or, if that fails for some reason, in the current directory. + +=item have_cplusplus + +Just like have_compiler but for C++ instead of C. + +=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. + +=item C<C++> + +Specifies that the source file is a C++ source file and sets appropriate +compiler flags + +=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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Base.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Base.pm new file mode 100644 index 0000000000..3249032e4a --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Base.pm @@ -0,0 +1,383 @@ +package ExtUtils::CBuilder::Base; + +use strict; +use File::Spec; +use File::Basename; +use Cwd (); +use Config; +use Text::ParseWords; +use IO::File; +use Data::Dumper;$Data::Dumper::Indent=1; +use IPC::Cmd qw(can_run); +use File::Temp qw(tempfile); + +use vars qw($VERSION); +$VERSION = '0.2802'; + +# More details about C/C++ compilers: +# http://developers.sun.com/sunstudio/documentation/product/compiler.jsp +# http://gcc.gnu.org/ +# http://publib.boulder.ibm.com/infocenter/comphelp/v101v121/index.jsp +# http://msdn.microsoft.com/en-us/vstudio/default.aspx + +my %cc2cxx = ( + # first line order is important to support wrappers like in pkgsrc + cc => [ 'c++', 'CC', 'aCC', 'cxx', ], # Sun Studio, HP ANSI C/C++ Compilers + gcc => [ 'g++' ], # GNU Compiler Collection + xlc => [ 'xlC' ], # IBM C/C++ Set, xlc without thread-safety + xlc_r => [ 'xlC_r' ], # IBM C/C++ Set, xlc with thread-safety + cl => [ 'cl' ], # Microsoft Visual Studio +); + +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}; + } + $self->{config}{cc} = $ENV{CC} if defined $ENV{CC}; + $self->{config}{ccflags} = $ENV{CFLAGS} if defined $ENV{CFLAGS}; + $self->{config}{cxx} = $ENV{CXX} if defined $ENV{CXX}; + $self->{config}{cxxflags} = $ENV{CXXFLAGS} if defined $ENV{CXXFLAGS}; + $self->{config}{ld} = $ENV{LD} if defined $ENV{LD}; + $self->{config}{ldflags} = $ENV{LDFLAGS} if defined $ENV{LDFLAGS}; + + unless ( exists $self->{config}{cxx} ) { + my ($ccpath, $ccbase, $ccsfx ) = fileparse($self->{config}{cc}, qr/\.[^.]*/); + foreach my $cxx (@{$cc2cxx{$ccbase}}) { + if( can_run( File::Spec->catfile( $ccpath, $cxx, $ccsfx ) ) ) { + $self->{config}{cxx} = File::Spec->catfile( $ccpath, $cxx, $ccsfx ); + last; + } + if( can_run( File::Spec->catfile( $cxx, $ccsfx ) ) ) { + $self->{config}{cxx} = File::Spec->catfile( $cxx, $ccsfx ); + last; + } + if( can_run( $cxx ) ) { + $self->{config}{cxx} = $cxx; + last; + } + } + unless ( exists $self->{config}{cxx} ) { + $self->{config}{cxx} = $self->{config}{cc}; + my $cflags = $self->{config}{cflags}; + $self->{config}{cxxflags} = '-x c++'; + $self->{config}{cxxflags} .= " $cflags" if defined $cflags; + } + } + + 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); # XXX how about using IPC::Cmd::can_run here? + 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 get_config { + return %{ $_[0]->{config} }; +} + +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 + + my $object_file = $args{object_file} + ? $args{object_file} + : $self->object_file($args{source}); + + my $include_dirs_ref = + (exists($args{include_dirs}) && ref($args{include_dirs}) ne "ARRAY") + ? [ $args{include_dirs} ] + : $args{include_dirs}; + my @include_dirs = $self->arg_include_dirs( + @{ $include_dirs_ref || [] }, + $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($args{'C++'} ? $cf->{cxxflags} : $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($object_file), + ); + my @cc = $self->split_like_shell($args{'C++'} ? $cf->{cxx} : $cf->{cc}); + + $self->do_system(@cc, @flags, $args{source}) + or die "error building $object_file from '$args{source}'"; + + return $object_file; +} + +sub have_compiler { + my ($self, $is_cplusplus) = @_; + my $have_compiler_flag = $is_cplusplus ? "have_cxx" : "have_cc"; + my $suffix = $is_cplusplus ? ".cc" : ".c"; + return $self->{$have_compiler_flag} if defined $self->{$have_compiler_flag}; + + my $result; + my $attempts = 3; + # tmpdir has issues for some people so fall back to current dir + + # don't clobber existing files (rare, but possible) + my ( $FH, $tmpfile ) = tempfile( "compilet-XXXXX", SUFFIX => $suffix ); + binmode $FH; + + if ( $is_cplusplus ) { + print $FH "class Bogus { public: int boot_compilet() { return 1; } };\n"; + } + else { + print $FH "int boot_compilet() { return 1; }\n"; + } + close $FH; + + my ($obj_file, @lib_files); + eval { + local $^W = 0; + local $self->{quiet} = 1; + $obj_file = $self->compile('C++' => $is_cplusplus, source => $tmpfile); + @lib_files = $self->link(objects => $obj_file, module_name => 'compilet'); + }; + $result = $@ ? 0 : 1; + + foreach (grep defined, $tmpfile, $obj_file, @lib_files) { + 1 while unlink; + } + + return $self->{$have_compiler_flag} = $result; +} + +sub have_cplusplus { + push @_, 1; + goto &have_compiler; +} + +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) = @_; + + my ($dl_file_out, $mksymlists_args) = _prepare_mksymlists_args(\%args); + + require ExtUtils::Mksymlists; + # dl. abbrev for dynamic library + ExtUtils::Mksymlists::Mksymlists( %{ $mksymlists_args } ); + + # Mksymlists will create one of these files + return grep -e, map "$dl_file_out.$_", qw(ext def opt); +} + +sub _prepare_mksymlists_args { + my $args = shift; + ($args->{dl_file} = $args->{dl_name}) =~ s/.*::// unless $args->{dl_file}; + + my %mksymlists_args = ( + 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'), + ); + return ($args->{dl_file}, \%mksymlists_args); +} + +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); + + # Text::ParseWords replaces all 'escaped' characters with themselves, which completely + # breaks paths under windows. As such, we forcibly replace backwards slashes with forward + # slashes on windows. + $string =~ s@\\@/@g if $^O eq 'MSWin32'; + + 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; + +# vim: ts=2 sw=2 et: diff --git a/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Unix.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Unix.pm new file mode 100644 index 0000000000..4bddff1e7f --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Unix.pm @@ -0,0 +1,40 @@ +package ExtUtils::CBuilder::Platform::Unix; + +use strict; +use ExtUtils::CBuilder::Base; + +use vars qw($VERSION @ISA); +$VERSION = '0.2802'; +@ISA = qw(ExtUtils::CBuilder::Base); + +sub link_executable { + my $self = shift; + + # On some platforms (which ones??) $Config{cc} seems to be a better + # bet for linking executables than $Config{ld}. Cygwin is a notable + # exception. + 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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/VMS.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/VMS.pm new file mode 100644 index 0000000000..c9ad1d9c00 --- /dev/null +++ b/dist/ExtUtils-CBuilder/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.2802'; +@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 ensure 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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows.pm new file mode 100644 index 0000000000..0fdd37097b --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows.pm @@ -0,0 +1,291 @@ +package ExtUtils::CBuilder::Platform::Windows; + +use strict; +use warnings; + +use File::Basename; +use File::Spec; + +use ExtUtils::CBuilder::Base; +use IO::File; + +use vars qw($VERSION @ISA); +$VERSION = '0.2802'; +@ISA = qw(ExtUtils::CBuilder::Base); + +=begin comment + +The compiler-specific packages 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 + +sub new { + my $class = shift; + my $self = $class->SUPER::new(@_); + my $cf = $self->{config}; + + # Inherit from an appropriate compiler driver class + my $driver = "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type; + eval "require $driver" or die "Could not load compiler driver: $@"; + unshift @ISA, $driver; + + 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 { + # Since Windows will pass the whole command string (not an argument + # array) to the target program and make the program parse it itself, + # we don't actually need to do any processing here. + (my $self, local $_) = @_; + + return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY'); + return unless defined() && length(); + return ($_); +} + +sub do_system { + # See above + my $self = shift; + my $cmd = join(" ", + grep length, + map {$a=$_;$a=~s/\t/ /g;$a=~s/^\s+|\s+$//;$a} + grep defined, @_); + return $self->SUPER::do_system($cmd); +} + +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}; + + $args{include_dirs} = [ $args{include_dirs} ] + if exists($args{include_dirs}) && ref($args{include_dirs}) ne "ARRAY"; + + 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 => $args{object_file} || 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($args{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; + +__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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/BCC.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/BCC.pm new file mode 100644 index 0000000000..4810e79e70 --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/BCC.pm @@ -0,0 +1,130 @@ +package ExtUtils::CBuilder::Platform::Windows::BCC; + +use vars qw($VERSION); +$VERSION = '0.2802'; + +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}; + + my $SCRIPT = IO::File->new( ">$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) } ) + ); + + 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. + my $LD_SCRIPT = IO::File->new( ">$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) } ) + ); + + # Script 2: contains name of libs to link against. + my $LD_LIBS = IO::File->new( ">$ld_libs" ) + or die( "Could not create linker script '$ld_libs': $!" ); + + print $LD_LIBS join( " +\n", + (delete $spec{libperl} || ''), + @{delete $spec{perllibs} || []}, + ); + + push @{$spec{lddlflags}}, '@"' . $ld_script . '"'; + push @{$spec{perllibs}}, '@"' . $ld_libs . '"'; + + return %spec; +} + +1; + + diff --git a/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/GCC.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/GCC.pm new file mode 100644 index 0000000000..98f1176741 --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/GCC.pm @@ -0,0 +1,151 @@ +package ExtUtils::CBuilder::Platform::Windows::GCC; + +use vars qw($VERSION); +$VERSION = '0.2802'; + +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) = @_; + my $cf = $self->{config}; + + # 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. + + my $DLLTOOL = $cf->{dlltool} || 'dlltool'; + + 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}; + + my $SCRIPT = IO::File->new( ">$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"; + + #it is important to keep the order 1.linker_script - 2.other_ldflags + unshift @{$spec{other_ldflags}}, '"' . $script . '"'; + + return %spec; +} + +1; + + diff --git a/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/MSVC.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/MSVC.pm new file mode 100644 index 0000000000..df1b7cefd7 --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/Windows/MSVC.pm @@ -0,0 +1,131 @@ +package ExtUtils::CBuilder::Platform::Windows::MSVC; + +use vars qw($VERSION); +$VERSION = '0.2802'; + +sub arg_exec_file { + my ($self, $file) = @_; + return "/OUT:$file"; +} + +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}; + + my $SCRIPT = IO::File->new( ">$script" ) + or die( "Could not create script '$script': $!" ); + + print $SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(includes cflags optimize defines perlinc) } ) + ); + + 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 if it exists + push @cmds, [ + 'if', 'exist', $spec{manifest}, '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}; + + my $SCRIPT = IO::File->new( ">$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) } ) + ); + + push @{$spec{lddlflags}}, '@"' . $script . '"'; + + return %spec; +} + +1; + + diff --git a/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/aix.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/aix.pm new file mode 100644 index 0000000000..4789ff77c5 --- /dev/null +++ b/dist/ExtUtils-CBuilder/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.2802'; +@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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/cygwin.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/cygwin.pm new file mode 100644 index 0000000000..442bbd8df1 --- /dev/null +++ b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/cygwin.pm @@ -0,0 +1,33 @@ +package ExtUtils::CBuilder::Platform::cygwin; + +use strict; +use File::Spec; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.2802'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +# TODO: If a specific exe_file name is requested, if the exe created +# doesn't have that name, we might want to rename it. Apparently asking +# for an exe of "foo" might result in "foo.exe". Alternatively, we should +# make sure the return value is correctly "foo.exe". +# C.f http://rt.cpan.org/Public/Bug/Display.html?id=41003 +sub link_executable { + my $self = shift; + return $self->SUPER::link_executable(@_); +} + +sub link { + my ($self, %args) = @_; + + my $lib = $self->{config}{useshrplib} ? 'libperl.dll.a' : 'libperl.a'; + $args{extra_linker_flags} = [ + File::Spec->catfile($self->perl_inc(), $lib), + $self->split_like_shell($args{extra_linker_flags}) + ]; + + return $self->SUPER::link(%args); +} + +1; diff --git a/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/darwin.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/darwin.pm new file mode 100644 index 0000000000..89565b837e --- /dev/null +++ b/dist/ExtUtils-CBuilder/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.2802'; +@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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/dec_osf.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/dec_osf.pm new file mode 100644 index 0000000000..2798c696d9 --- /dev/null +++ b/dist/ExtUtils-CBuilder/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.2802'; + +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/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/os2.pm b/dist/ExtUtils-CBuilder/lib/ExtUtils/CBuilder/Platform/os2.pm new file mode 100644 index 0000000000..e4f161df57 --- /dev/null +++ b/dist/ExtUtils-CBuilder/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.2802'; +@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/dist/ExtUtils-CBuilder/t/00-have-compiler.t b/dist/ExtUtils-CBuilder/t/00-have-compiler.t new file mode 100644 index 0000000000..581a21461b --- /dev/null +++ b/dist/ExtUtils-CBuilder/t/00-have-compiler.t @@ -0,0 +1,57 @@ +#! perl -w + +use File::Spec; +my $perl; +BEGIN { + $perl = File::Spec->rel2abs($^X); +} + +use strict; +use Test::More; +BEGIN { + if ($^O eq 'VMS') { + # So we can get the return value of system() + require vmsish; + import vmsish; + } +} + +plan tests => 7; + +require_ok "ExtUtils::CBuilder"; + +my $b = eval { ExtUtils::CBuilder->new(quiet => 1) }; +ok( $b, "got CBuilder object" ) or diag $@; + +my $bogus_path = 'djaadjfkadjkfajdf'; +my $run_perl = "$perl -e1 --"; +# test missing compiler +$b->{config}{cc} = $bogus_path; +$b->{config}{ld} = $bogus_path; + +$b->{have_cc} = undef; +is( $b->have_compiler, 0, "have_compiler: fake missing cc" ); +$b->{have_cxx} = undef; +is( $b->have_cplusplus, 0, "have_cplusplus: fake missing c++" ); + +# test found compiler +$b->{config}{cc} = $run_perl; +$b->{config}{ld} = $run_perl; +$b->{config}{cxx} = $run_perl; +$b->{have_cc} = undef; +is( $b->have_compiler, 1, "have_compiler: fake present cc" ); +$b->{have_cxx} = undef; +is( $b->have_cplusplus, 1, "have_cpp_compiler: fake present c++" ); + +# test missing cpp compiler + +# test one non-exported subroutine +{ + my $type = ExtUtils::CBuilder::os_type(); + if ($type) { + pass( "OS type $type located for $^O" ); + } + else { + pass( "OS type not yet listed for $^O" ); + } +} diff --git a/dist/ExtUtils-CBuilder/t/01-basic.t b/dist/ExtUtils-CBuilder/t/01-basic.t new file mode 100644 index 0000000000..ffcd60ce9c --- /dev/null +++ b/dist/ExtUtils-CBuilder/t/01-basic.t @@ -0,0 +1,106 @@ +#! perl -w + +use strict; +use Test::More; +BEGIN { + if ($^O eq 'VMS') { + # So we can get the return value of system() + require vmsish; + import vmsish; + } +} +use ExtUtils::CBuilder; +use File::Spec; + +# TEST does not like extraneous output +my $quiet = $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE}; +my ($source_file, $object_file, $lib_file); + +my $b = ExtUtils::CBuilder->new(quiet => $quiet); + +# test plan +if ( ! $b->have_compiler ) { + plan skip_all => "no compiler available for testing"; +} +else { + plan tests => 12; +} + +ok $b, "created EU::CB object"; + +ok $b->have_compiler, "have_compiler"; + +$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, "source file '$source_file' created"; + +$object_file = $b->object_file($source_file); +ok 1; + +is $object_file, $b->compile(source => $source_file); + +$lib_file = $b->lib_file($object_file); +ok 1; + +my ($lib, @temps) = $b->link(objects => $object_file, + module_name => 'compilet'); +$lib =~ tr/"'//d; +is $lib_file, $lib; + +for ($source_file, $object_file, $lib_file) { + tr/"'//d; + 1 while unlink; +} + +if ($^O eq 'VMS') { + 1 while unlink 'COMPILET.LIS'; + 1 while unlink 'COMPILET.OPT'; +} + +my @words = $b->split_like_shell(' foo bar'); + +SKIP: { + skip "MSWindows", 3 if $^O =~ m/MSWin/; + is( @words, 2 ); + is( $words[0], 'foo' ); + is( $words[1], 'bar' ); +} + +# include_dirs should be settable as string or list +{ + package Sub; + use vars '@ISA'; + @ISA = ('ExtUtils::CBuilder'); + my $saw = 0; + sub do_system { + if ($^O eq "MSWin32") { + # ExtUtils::CBuilder::MSVC::write_compiler_script() puts the + # include_dirs into a response file and not the commandline + for (@_) { + next unless /^\@"(.*)"$/; + open(my $fh, "<", $1) or next; + local $/; + $saw = 1 if <$fh> =~ /another dir/; + last; + } + } + $saw = 1 if grep {$_ =~ /another dir/} @_; + return 1; + } + + package main; + my $s = Sub->new(); + $s->compile(source => 'foo', + include_dirs => 'another dir'); + ok $saw; + + $saw = 0; + $s->compile(source => 'foo', + include_dirs => ['a dir', 'another dir']); + ok $saw; +} diff --git a/dist/ExtUtils-CBuilder/t/02-link.t b/dist/ExtUtils-CBuilder/t/02-link.t new file mode 100644 index 0000000000..822b071223 --- /dev/null +++ b/dist/ExtUtils-CBuilder/t/02-link.t @@ -0,0 +1,97 @@ +#! perl -w + +use strict; +use Test::More; +BEGIN { + if ($^O eq 'VMS') { + # So we can get the return value of system() + require vmsish; + import vmsish; + } +} +use ExtUtils::CBuilder; +use File::Spec; + +# TEST does not like extraneous output +my $quiet = $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE}; +my ($source_file, $object_file, $exe_file); + +my $b = ExtUtils::CBuilder->new(quiet => $quiet); + +# test plan +if ($^O eq 'MSWin32') { + plan skip_all => "link_executable() is not implemented yet on Win32"; +} +elsif ( ! $b->have_compiler ) { + plan skip_all => "no compiler available for testing"; +} +else { + plan tests => 8; +} + +ok $b, "created EU::CB object"; + +$source_file = File::Spec->catfile('t', 'compilet.c'); +{ + open my $FH, "> $source_file" or die "Can't create $source_file: $!"; + print $FH "int main(void) { return 11; }\n"; + close $FH; +} +ok -e $source_file, "generated '$source_file'"; + +# Compile +eval { $object_file = $b->compile(source => $source_file) }; +is $@, q{}, "no exception from compilation"; +ok -e $object_file, "found object file"; + +# Link +SKIP: { + skip "error compiling source", 4 + unless -e $object_file; + + my @temps; + eval { ($exe_file, @temps) = $b->link_executable(objects => $object_file) }; + is $@, q{}, "no exception from linking"; + ok -e $exe_file, "found executable file"; + ok -x $exe_file, "executable file appears to be executable"; + + 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 + my $ec = my_system($exe_file); + is( $ec, 11, "got expected exit code from executable" ) + or diag( $ec == -1 ? "Could not run '$exe_file': $!\n" + : "Unexpected exit code '$ec'\n"); +} + +# Clean up +for ($source_file, $object_file, $exe_file) { + tr/"'//d; + 1 while unlink; +} + +if ($^O eq 'VMS') { + 1 while unlink 'COMPILET.LIS'; + 1 while unlink 'COMPILET.OPT'; +} + +sub my_system { + my $cmd = shift; + my $ec; + if ($^O eq 'VMS') { + # Preserve non-posixified status and don't bit shift the result + # because we're running under "use vmsish"; + $ec = system("mcr $cmd"); + return $ec; + } + else { + $ec = system($cmd); + return $ec == -1 ? -1 : $ec >> 8; + } +} diff --git a/dist/ExtUtils-CBuilder/t/03-cplusplus.t b/dist/ExtUtils-CBuilder/t/03-cplusplus.t new file mode 100644 index 0000000000..02555df3db --- /dev/null +++ b/dist/ExtUtils-CBuilder/t/03-cplusplus.t @@ -0,0 +1,63 @@ +#! perl -w + +use strict; +use Test::More; +BEGIN { + if ($^O eq 'VMS') { + # So we can get the return value of system() + require vmsish; + import vmsish; + } +} +use ExtUtils::CBuilder; +use File::Spec; + +# TEST does not like extraneous output +my $quiet = $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE}; +my ($source_file, $object_file, $lib_file); + +my $b = ExtUtils::CBuilder->new(quiet => $quiet); + +# test plan +if ( ! $b->have_cplusplus ) { + plan skip_all => "no compiler available for testing"; +} +else { + plan tests => 7; +} + +ok $b, "created EU::CB object"; + +ok $b->have_cplusplus, "have_cplusplus"; + +$source_file = File::Spec->catfile('t', 'compilet.cc'); +{ + open my $FH, "> $source_file" or die "Can't create $source_file: $!"; + print $FH "class Bogus { public: int boot_compilet() { return 1; } };\n"; + close $FH; +} +ok -e $source_file, "source file '$source_file' created"; + +$object_file = $b->object_file($source_file); +ok 1; + +is $object_file, $b->compile(source => $source_file, 'C++' => 1); + +$lib_file = $b->lib_file($object_file); +ok 1; + +my ($lib, @temps) = $b->link(objects => $object_file, + module_name => 'compilet'); +$lib =~ tr/"'//d; +is $lib_file, $lib; + +for ($source_file, $object_file, $lib_file) { + tr/"'//d; + 1 while unlink; +} + +if ($^O eq 'VMS') { + 1 while unlink 'COMPILET.LIS'; + 1 while unlink 'COMPILET.OPT'; +} + diff --git a/dist/ExtUtils-CBuilder/t/04-base.t b/dist/ExtUtils-CBuilder/t/04-base.t new file mode 100644 index 0000000000..988f7ae49e --- /dev/null +++ b/dist/ExtUtils-CBuilder/t/04-base.t @@ -0,0 +1,412 @@ +#! perl -w + +use strict; +use Test::More tests => 58; +BEGIN { + if ($^O eq 'VMS') { + # So we can get the return value of system() + require vmsish; + import vmsish; + } +} +use Config; +use Cwd; +use File::Path qw( mkpath ); +use File::Temp qw( tempdir ); +use ExtUtils::CBuilder::Base; + +# XXX protect from user CC as we mock everything here +local $ENV{CC}; + +my ( $base, $phony, $cwd ); +my ( $source_file, $object_file, $lib_file ); + +$base = ExtUtils::CBuilder::Base->new(); +ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); +isa_ok( $base, 'ExtUtils::CBuilder::Base' ); + +{ + $phony = 'foobar'; + $base = ExtUtils::CBuilder::Base->new( + config => { cc => $phony }, + ); + ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); + isa_ok( $base, 'ExtUtils::CBuilder::Base' ); + is( $base->{config}->{cc}, $phony, + "Got expected value when 'config' argument passed to new()" ); +} + +{ + $phony = 'barbaz'; + local $ENV{CC} = $phony; + $base = ExtUtils::CBuilder::Base->new(); + ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); + isa_ok( $base, 'ExtUtils::CBuilder::Base' ); + is( $base->{config}->{cc}, $phony, + "Got expected value \$ENV{CC} set" ); +} + +{ + my $path_to_perl = File::Spec->catfile( '', qw| usr bin perl | ); + local $^X = $path_to_perl; + is( + ExtUtils::CBuilder::Base::find_perl_interpreter(), + $path_to_perl, + "find_perl_interpreter() returned expected absolute path" + ); +} + +{ + my $path_to_perl = 'foobar'; + local $^X = $path_to_perl; + # %Config is read-only. We cannot assign to it and we therefore cannot + # simulate the condition that would occur were its value something other + # than an existing file. + if ( !$ENV{PERL_CORE} and $Config::Config{perlpath}) { + is( + ExtUtils::CBuilder::Base::find_perl_interpreter(), + $Config::Config{perlpath}, + "find_perl_interpreter() returned expected file" + ); + } + else { + local $^X = $path_to_perl = File::Spec->rel2abs($path_to_perl); + is( + ExtUtils::CBuilder::Base::find_perl_interpreter(), + $path_to_perl, + "find_perl_interpreter() returned expected name" + ); + } +} + +{ + $cwd = cwd(); + my $tdir = tempdir(); + chdir $tdir; + $base = ExtUtils::CBuilder::Base->new(); + ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); + isa_ok( $base, 'ExtUtils::CBuilder::Base' ); + is( scalar keys %{$base->{files_to_clean}}, 0, + "No files needing cleaning yet" ); + + my $file_for_cleaning = File::Spec->catfile( $tdir, 'foobar' ); + open my $IN, '>', $file_for_cleaning + or die "Unable to open dummy file: $!"; + print $IN "\n"; + close $IN or die "Unable to close dummy file: $!"; + + $base->add_to_cleanup( $file_for_cleaning ); + is( scalar keys %{$base->{files_to_clean}}, 1, + "One file needs cleaning" ); + + $base->cleanup(); + ok( ! -f $file_for_cleaning, "File was cleaned up" ); + + chdir $cwd; +} + +# fake compiler is perl and will always succeed +$base = ExtUtils::CBuilder::Base->new( + config => { + cc => File::Spec->rel2abs($^X) . " -e1 --", + ld => File::Spec->rel2abs($^X) . " -e1 --", + } +); +ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); +isa_ok( $base, 'ExtUtils::CBuilder::Base' ); +eval { + $base->compile(foo => 'bar'); +}; +like( + $@, + qr/Missing 'source' argument to compile/, + "Got expected error message when lacking 'source' argument to compile()" +); + +$base = ExtUtils::CBuilder::Base->new( quiet => 1 ); +ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); +isa_ok( $base, 'ExtUtils::CBuilder::Base' ); + +$source_file = File::Spec->catfile('t', 'compilet.c'); +create_c_source_file($source_file); +ok(-e $source_file, "source file '$source_file' created"); + +# object filename automatically assigned +my $obj_ext = $base->{config}{obj_ext}; +is( $base->object_file($source_file), + File::Spec->catfile('t', "compilet$obj_ext"), + "object_file(): got expected automatically assigned name for object file" +); + +# object filename explicitly assigned +$object_file = File::Spec->catfile('t', 'my_special_compilet.o' ); +is( $object_file, + $base->compile( + source => $source_file, + object_file => $object_file, + ), + "compile(): returned object file with specified name" +); + +$lib_file = $base->lib_file($object_file); +ok( $lib_file, "lib_file() returned true value" ); + +my ($lib, @temps); +($lib, @temps) = $base->link( + objects => $object_file, + module_name => 'compilet', +); +$lib =~ tr/"'//d; #" +is($lib_file, $lib, "lib_file(): got expected value for $lib"); + +($lib, @temps) = $base->link( + objects => [ $object_file ], + module_name => 'compilet', +); +$lib =~ tr/"'//d; #" +is($lib_file, $lib, "lib_file(): got expected value for $lib"); + +($lib, @temps) = $base->link( + lib_file => $lib_file, + objects => [ $object_file ], + module_name => 'compilet', +); +$lib =~ tr/"'//d; #" +is($lib_file, $lib, "lib_file(): got expected value for $lib"); + +$lib = $base->link( + objects => $object_file, + module_name => 'compilet', +); +$lib =~ tr/"'//d; #" +is($lib_file, $lib, "lib_file(): got expected value for $lib"); + +{ + local $ENV{PERL_CORE} = '' unless $ENV{PERL_CORE}; + my $include_dir = $base->perl_inc(); + ok( $include_dir, "perl_inc() returned true value" ); + ok( -d $include_dir, "perl_inc() returned directory" ); +} + +# +$base = ExtUtils::CBuilder::Base->new( quiet => 1 ); +ok( $base, "ExtUtils::CBuilder::Base->new() returned true value" ); +isa_ok( $base, 'ExtUtils::CBuilder::Base' ); + +$source_file = File::Spec->catfile('t', 'compilet.c'); +create_c_source_file($source_file); +ok(-e $source_file, "source file '$source_file' created"); +$object_file = File::Spec->catfile('t', 'my_special_compilet.o' ); +is( $object_file, + $base->compile( + source => $source_file, + object_file => $object_file, + defines => { alpha => 'beta', gamma => 'delta' }, + ), + "compile() completed when 'defines' provided; returned object file with specified name" +); + +my $exe_file = $base->exe_file($object_file); +my $ext = $base->{config}{_exe}; +my $expected = File::Spec->catfile('t', qq|my_special_compilet$ext| ); +is( + $exe_file, + $expected, + "exe_file(): returned expected name of executable" +); + +my %args = (); +my @defines = $base->arg_defines( %args ); +ok( ! @defines, "Empty hash passed to arg_defines() returns empty list" ); + +%args = ( alpha => 'beta', gamma => 'delta' ); +my $defines_seen_ref = { map { $_ => 1 } $base->arg_defines( %args ) }; +is_deeply( + $defines_seen_ref, + { '-Dalpha=beta' => 1, '-Dgamma=delta' => 1 }, + "arg_defines(): got expected defines", +); + +my $include_dirs_seen_ref = + { map {$_ => 1} $base->arg_include_dirs( qw| alpha beta gamma | ) }; +is_deeply( + $include_dirs_seen_ref, + { '-Ialpha' => 1, '-Ibeta' => 1, '-Igamma' => 1 }, + "arg_include_dirs(): got expected include_dirs", +); + +is( '-c', $base->arg_nolink(), "arg_nolink(): got expected value" ); + +my $seen_ref = + { map {$_ => 1} $base->arg_object_file('alpha') }; +is_deeply( + $seen_ref, + { '-o' => 1, 'alpha' => 1 }, + "arg_object_file(): got expected option flag and value", +); + +$seen_ref = { map {$_ => 1} $base->arg_share_object_file('alpha') }; +my %exp = map {$_ => 1} $base->split_like_shell($base->{config}{lddlflags}); +$exp{'-o'} = 1; +$exp{'alpha'} = 1; + +is_deeply( + $seen_ref, + \%exp, + "arg_share_object_file(): got expected option flag and value", +); + +$seen_ref = + { map {$_ => 1} $base->arg_exec_file('alpha') }; +is_deeply( + $seen_ref, + { '-o' => 1, 'alpha' => 1 }, + "arg_exec_file(): got expected option flag and value", +); + +ok(! $base->split_like_shell(undef), + "split_like_shell(): handled undefined argument as expected" ); + +my $array_ref = [ qw| alpha beta gamma | ]; +my %split_seen = map { $_ => 1 } $base->split_like_shell($array_ref); +%exp = ( alpha => 1, beta => 1, gamma => 1 ); +is_deeply( \%split_seen, \%exp, + "split_like_shell(): handled array ref as expected" ); + +{ + $cwd = cwd(); + my $tdir = tempdir(); + my $subdir = File::Spec->catdir( + $tdir, qw| alpha beta gamma delta epsilon + zeta eta theta iota kappa lambda | + ); + mkpath($subdir, { mode => 0711 } ); + chdir $subdir + or die "Unable to change to temporary directory for testing"; + local $ENV{PERL_CORE} = 1; + my $capture = q{}; + local $SIG{__WARN__} = sub { $capture = $_[0] }; + my $expected_message = + qr/PERL_CORE is set but I can't find your perl source!/; #' + my $rv; + + $rv = $base->perl_src(); + is( $rv, q{}, "perl_src(): returned empty string as expected" ); + like( $capture, $expected_message, + "perl_src(): got expected warning" ); + $capture = q{}; + + my $config = File::Spec->catfile( $subdir, 'config_h.SH' ); + touch_file($config); + $rv = $base->perl_src(); + is( $rv, q{}, "perl_src(): returned empty string as expected" ); + like( $capture, $expected_message, + "perl_src(): got expected warning" ); + $capture = q{}; + + my $perlh = File::Spec->catfile( $subdir, 'perl.h' ); + touch_file($perlh); + $rv = $base->perl_src(); + is( $rv, q{}, "perl_src(): returned empty string as expected" ); + like( $capture, $expected_message, + "perl_src(): got expected warning" ); + $capture = q{}; + + my $libsubdir = File::Spec->catdir( $subdir, 'lib' ); + mkpath($libsubdir, { mode => 0711 } ); + my $exporter = File::Spec->catfile( $libsubdir, 'Exporter.pm' ); + touch_file($exporter); + $rv = $base->perl_src(); + ok( -d $rv, "perl_src(): returned a directory" ); + is( $rv, Cwd::realpath($subdir), "perl_src(): identified directory" ); + is( $capture, q{}, "perl_src(): no warning, as expected" ); + + chdir $cwd + or die "Unable to change from temporary directory after testing"; +} + +my ($dl_file_out, $mksymlists_args); +my $dlf = 'Kappa'; +%args = ( + dl_vars => [ qw| alpha beta gamma | ], + dl_funcs => { + 'Homer::Iliad' => [ qw(trojans greeks) ], + 'Homer::Odyssey' => [ qw(travellers family suitors) ], + }, + dl_func_list => [ qw| delta epsilon | ], + dl_imports => { zeta => 'eta', theta => 'iota' }, + dl_name => 'Tk::Canvas', + dl_base => 'Tk::Canvas.ext', + dl_file => $dlf, + dl_version => '7.7', +); +($dl_file_out, $mksymlists_args) = + ExtUtils::CBuilder::Base::_prepare_mksymlists_args(\%args); +is( $dl_file_out, $dlf, "_prepare_mksymlists_args(): Got expected name for dl_file" ); +is_deeply( $mksymlists_args, + { + DL_VARS => [ qw| alpha beta gamma | ], + DL_FUNCS => { + 'Homer::Iliad' => [ qw(trojans greeks) ], + 'Homer::Odyssey' => [ qw(travellers family suitors) ], + }, + FUNCLIST => [ qw| delta epsilon | ], + IMPORTS => { zeta => 'eta', theta => 'iota' }, + NAME => 'Tk::Canvas', + DLBASE => 'Tk::Canvas.ext', + FILE => $dlf, + VERSION => '7.7', + }, + "_prepare_mksymlists_args(): got expected arguments for Mksymlists", +); + +$dlf = 'Canvas'; +%args = ( + dl_name => 'Tk::Canvas', + dl_base => 'Tk::Canvas.ext', +); +($dl_file_out, $mksymlists_args) = + ExtUtils::CBuilder::Base::_prepare_mksymlists_args(\%args); +is( $dl_file_out, $dlf, "_prepare_mksymlists_args(): got expected name for dl_file" ); +is_deeply( $mksymlists_args, + { + DL_VARS => [], + DL_FUNCS => {}, + FUNCLIST => [], + IMPORTS => {}, + NAME => 'Tk::Canvas', + DLBASE => 'Tk::Canvas.ext', + FILE => $dlf, + VERSION => '0.0', + }, + "_prepare_mksymlists_args(): got expected arguments for Mksymlists", +); + +##### + +for ($source_file, $object_file, $lib_file) { + tr/"'//d; #" + 1 while unlink; +} + +pass("Completed all tests in $0"); + +if ($^O eq 'VMS') { + 1 while unlink 'COMPILET.LIS'; + 1 while unlink 'COMPILET.OPT'; +} + +sub create_c_source_file { + my $source_file = shift; + open my $FH, '>', $source_file or die "Can't create $source_file: $!"; + print $FH "int boot_compilet(void) { return 1; }\n"; + close $FH; +} + +sub touch_file { + my $f = shift; + open my $FH, '>', $f or die "Can't create $f: $!"; + print $FH "\n"; + close $FH; + return $f; +} |