This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Embed manifest files in DLLs built with Module-Build when using VC8
[perl5.git] / lib / ExtUtils / CBuilder / Platform / Windows.pm
1 package ExtUtils::CBuilder::Platform::Windows;
2
3 use strict;
4 use warnings;
5
6 use File::Basename;
7 use File::Spec;
8
9 use ExtUtils::CBuilder::Base;
10
11 use vars qw($VERSION @ISA);
12 $VERSION = '0.12_01';
13 @ISA = qw(ExtUtils::CBuilder::Base);
14
15 sub new {
16   my $class = shift;
17   my $self = $class->SUPER::new(@_);
18   my $cf = $self->{config};
19
20   # Inherit from an appropriate compiler driver class
21   unshift @ISA, "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type;
22
23   return $self;
24 }
25
26 sub _compiler_type {
27   my $self = shift;
28   my $cc = $self->{config}{cc};
29
30   return (  $cc =~ /cl(\.exe)?$/ ? 'MSVC'
31           : $cc =~ /bcc32(\.exe)?$/ ? 'BCC'
32           : 'GCC');
33 }
34
35 sub split_like_shell {
36   # As it turns out, Windows command-parsing is very different from
37   # Unix command-parsing.  Double-quotes mean different things,
38   # backslashes don't necessarily mean escapes, and so on.  So we
39   # can't use Text::ParseWords::shellwords() to break a command string
40   # into words.  The algorithm below was bashed out by Randy and Ken
41   # (mostly Randy), and there are a lot of regression tests, so we
42   # should feel free to adjust if desired.
43   
44   (my $self, local $_) = @_;
45   
46   return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY');
47   
48   my @argv;
49   return @argv unless defined() && length();
50   
51   my $arg = '';
52   my( $i, $quote_mode ) = ( 0, 0 );
53   
54   while ( $i < length() ) {
55     
56     my $ch      = substr( $_, $i  , 1 );
57     my $next_ch = substr( $_, $i+1, 1 );
58     
59     if ( $ch eq '\\' && $next_ch eq '"' ) {
60       $arg .= '"';
61       $i++;
62     } elsif ( $ch eq '\\' && $next_ch eq '\\' ) {
63       $arg .= '\\';
64       $i++;
65     } elsif ( $ch eq '"' && $next_ch eq '"' && $quote_mode ) {
66       $quote_mode = !$quote_mode;
67       $arg .= '"';
68       $i++;
69     } elsif ( $ch eq '"' && $next_ch eq '"' && !$quote_mode &&
70               ( $i + 2 == length()  ||
71                 substr( $_, $i + 2, 1 ) eq ' ' )
72             ) { # for cases like: a"" => [ 'a' ]
73       push( @argv, $arg );
74       $arg = '';
75       $i += 2;
76     } elsif ( $ch eq '"' ) {
77       $quote_mode = !$quote_mode;
78     } elsif ( $ch eq ' ' && !$quote_mode ) {
79       push( @argv, $arg ) if $arg;
80       $arg = '';
81       ++$i while substr( $_, $i + 1, 1 ) eq ' ';
82     } else {
83       $arg .= $ch;
84     }
85     
86     $i++;
87   }
88   
89   push( @argv, $arg ) if defined( $arg ) && length( $arg );
90   return @argv;
91 }
92
93 sub arg_defines {
94   my ($self, %args) = @_;
95   s/"/\\"/g foreach values %args;
96   return map qq{"-D$_=$args{$_}"}, keys %args;
97 }
98
99 sub compile {
100   my ($self, %args) = @_;
101   my $cf = $self->{config};
102
103   die "Missing 'source' argument to compile()" unless defined $args{source};
104
105   my ($basename, $srcdir) =
106     ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1];
107
108   $srcdir ||= File::Spec->curdir();
109
110   my @defines = $self->arg_defines( %{ $args{defines} || {} } );
111
112   my %spec = (
113     srcdir      => $srcdir,
114     builddir    => $srcdir,
115     basename    => $basename,
116     source      => $args{source},
117     output      => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext},
118     cc          => $cf->{cc},
119     cflags      => [
120                      $self->split_like_shell($cf->{ccflags}),
121                      $self->split_like_shell($cf->{cccdlflags}),
122                      $self->split_like_shell($cf->{extra_compiler_flags}),
123                    ],
124     optimize    => [ $self->split_like_shell($cf->{optimize})    ],
125     defines     => \@defines,
126     includes    => [ @{$args{include_dirs} || []} ],
127     perlinc     => [
128                      $self->perl_inc(),
129                      $self->split_like_shell($cf->{incpath}),
130                    ],
131     use_scripts => 1, # XXX provide user option to change this???
132   );
133
134   $self->normalize_filespecs(
135     \$spec{source},
136     \$spec{output},
137      $spec{includes},
138      $spec{perlinc},
139   );
140
141   my @cmds = $self->format_compiler_cmd(%spec);
142   while ( my $cmd = shift @cmds ) {
143     $self->do_system( @$cmd )
144       or die "error building $cf->{dlext} file from '$args{source}'";
145   }
146
147   (my $out = $spec{output}) =~ tr/'"//d;
148   return $out;
149 }
150
151 sub need_prelink { 1 }
152
153 sub link {
154   my ($self, %args) = @_;
155   my $cf = $self->{config};
156
157   my @objects = ( ref $args{objects} eq 'ARRAY' ? @{$args{objects}} : $args{objects} );
158   my $to = join '', (File::Spec->splitpath($objects[0]))[0,1];
159   $to ||= File::Spec->curdir();
160
161   (my $file_base = $args{module_name}) =~ s/.*:://;
162   my $output = $args{lib_file} ||
163     File::Spec->catfile($to, "$file_base.$cf->{dlext}");
164
165   # if running in perl source tree, look for libs there, not installed
166   my $lddlflags = $cf->{lddlflags};
167   my $perl_src = $self->perl_src();
168   $lddlflags =~ s/\Q$cf->{archlibexp}\E[\\\/]CORE/$perl_src/ if $perl_src;
169
170   my %spec = (
171     srcdir        => $to,
172     builddir      => $to,
173     startup       => [ ],
174     objects       => \@objects,
175     libs          => [ ],
176     output        => $output,
177     ld            => $cf->{ld},
178     libperl       => $cf->{libperl},
179     perllibs      => [ $self->split_like_shell($cf->{perllibs})  ],
180     libpath       => [ $self->split_like_shell($cf->{libpth})    ],
181     lddlflags     => [ $self->split_like_shell($lddlflags) ],
182     other_ldflags => [ $self->split_like_shell($args{extra_linker_flags} || '') ],
183     use_scripts   => 1, # XXX provide user option to change this???
184   );
185
186   unless ( $spec{basename} ) {
187     ($spec{basename} = $args{module_name}) =~ s/.*:://;
188   }
189
190   $spec{srcdir}   = File::Spec->canonpath( $spec{srcdir}   );
191   $spec{builddir} = File::Spec->canonpath( $spec{builddir} );
192
193   $spec{output}    ||= File::Spec->catfile( $spec{builddir},
194                                             $spec{basename}  . '.'.$cf->{dlext}   );
195   $spec{manifest}  ||= File::Spec->catfile( $spec{builddir},
196                                             $spec{basename}  . '.'.$cf->{dlext}.'.manifest');
197   $spec{implib}    ||= File::Spec->catfile( $spec{builddir},
198                                             $spec{basename}  . $cf->{lib_ext} );
199   $spec{explib}    ||= File::Spec->catfile( $spec{builddir},
200                                             $spec{basename}  . '.exp'  );
201   $spec{def_file}  ||= File::Spec->catfile( $spec{srcdir}  ,
202                                             $spec{basename}  . '.def'  );
203   $spec{base_file} ||= File::Spec->catfile( $spec{srcdir}  ,
204                                             $spec{basename}  . '.base' );
205
206   $self->add_to_cleanup(
207     grep defined,
208     @{[ @spec{qw(manifest implib explib def_file base_file map_file)} ]}
209   );
210
211   foreach my $opt ( qw(output manifest implib explib def_file map_file base_file) ) {
212     $self->normalize_filespecs( \$spec{$opt} );
213   }
214
215   foreach my $opt ( qw(libpath startup objects) ) {
216     $self->normalize_filespecs( $spec{$opt} );
217   }
218
219   (my $def_base = $spec{def_file}) =~ tr/'"//d;
220   $def_base =~ s/\.def$//;
221   $self->prelink( dl_name => $args{module_name},
222                   dl_file => $def_base,
223                   dl_base => $spec{basename} );
224
225   my @cmds = $self->format_linker_cmd(%spec);
226   while ( my $cmd = shift @cmds ) {
227     $self->do_system( @$cmd );
228   }
229
230   $spec{output} =~ tr/'"//d;
231   return wantarray
232     ? grep defined, @spec{qw[output manifest implib explib def_file map_file base_file]}
233     : $spec{output};
234 }
235
236 # canonize & quote paths
237 sub normalize_filespecs {
238   my ($self, @specs) = @_;
239   foreach my $spec ( grep defined, @specs ) {
240     if ( ref $spec eq 'ARRAY') {
241       $self->normalize_filespecs( map {\$_} grep defined, @$spec )
242     } elsif ( ref $spec eq 'SCALAR' ) {
243       $$spec =~ tr/"//d if $$spec;
244       next unless $$spec;
245       $$spec = '"' . File::Spec->canonpath($$spec) . '"';
246     } elsif ( ref $spec eq '' ) {
247       $spec = '"' . File::Spec->canonpath($spec) . '"';
248     } else {
249       die "Don't know how to normalize " . (ref $spec || $spec) . "\n";
250     }
251   }
252 }
253
254 # directory of perl's include files
255 sub perl_inc {
256   my $self = shift;
257
258   my $perl_src = $self->perl_src();
259
260   if ($perl_src) {
261     File::Spec->catdir($perl_src, "lib", "CORE");
262   } else {
263     File::Spec->catdir($self->{config}{archlibexp},"CORE");
264   }
265 }
266
267 1;
268
269 ########################################################################
270
271 =begin comment
272
273 The packages below implement functions for generating properly
274 formatted commandlines for the compiler being used. Each package
275 defines two primary functions 'format_linker_cmd()' &
276 'format_compiler_cmd()' that accepts a list of named arguments (a
277 hash) and returns a list of formatted options suitable for invoking the
278 compiler. By default, if the compiler supports scripting of its
279 operation then a script file is built containing the options while
280 those options are removed from the commandline, and a reference to the
281 script is pushed onto the commandline in their place. Scripting the
282 compiler in this way helps to avoid the problems associated with long
283 commandlines under some shells.
284
285 =end comment
286
287 =cut
288
289 ########################################################################
290 package ExtUtils::CBuilder::Platform::Windows::MSVC;
291
292 sub format_compiler_cmd {
293   my ($self, %spec) = @_;
294
295   foreach my $path ( @{ $spec{includes} || [] },
296                      @{ $spec{perlinc}  || [] } ) {
297     $path = '-I' . $path;
298   }
299
300   %spec = $self->write_compiler_script(%spec)
301     if $spec{use_scripts};
302
303   return [ grep {defined && length} (
304     $spec{cc},'-nologo','-c',
305     @{$spec{includes}}      ,
306     @{$spec{cflags}}        ,
307     @{$spec{optimize}}      ,
308     @{$spec{defines}}       ,
309     @{$spec{perlinc}}       ,
310     "-Fo$spec{output}"      ,
311     $spec{source}           ,
312   ) ];
313 }
314
315 sub write_compiler_script {
316   my ($self, %spec) = @_;
317
318   my $script = File::Spec->catfile( $spec{srcdir},
319                                     $spec{basename} . '.ccs' );
320
321   $self->add_to_cleanup($script);
322   print "Generating script '$script'\n" if !$self->{quiet};
323
324   open( SCRIPT, ">$script" )
325     or die( "Could not create script '$script': $!" );
326
327   print SCRIPT join( "\n",
328     map { ref $_ ? @{$_} : $_ }
329     grep defined,
330     delete(
331       @spec{ qw(includes cflags optimize defines perlinc) } )
332   );
333
334   close SCRIPT;
335
336   push @{$spec{includes}}, '@"' . $script . '"';
337
338   return %spec;
339 }
340
341 sub format_linker_cmd {
342   my ($self, %spec) = @_;
343   my $cf = $self->{config};
344
345   foreach my $path ( @{$spec{libpath}} ) {
346     $path = "-libpath:$path";
347   }
348
349   my $output = $spec{output};
350
351   $spec{def_file}  &&= '-def:'      . $spec{def_file};
352   $spec{output}    &&= '-out:'      . $spec{output};
353   $spec{manifest}  &&= '-manifest ' . $spec{manifest};
354   $spec{implib}    &&= '-implib:'   . $spec{implib};
355   $spec{map_file}  &&= '-map:'      . $spec{map_file};
356
357   %spec = $self->write_linker_script(%spec)
358     if $spec{use_scripts};
359
360   my @cmds; # Stores the series of commands needed to build the module.
361
362   push @cmds, [ grep {defined && length} (
363     $spec{ld}               ,
364     @{$spec{lddlflags}}     ,
365     @{$spec{libpath}}       ,
366     @{$spec{other_ldflags}} ,
367     @{$spec{startup}}       ,
368     @{$spec{objects}}       ,
369     $spec{map_file}         ,
370     $spec{libperl}          ,
371     @{$spec{perllibs}}      ,
372     $spec{def_file}         ,
373     $spec{implib}           ,
374     $spec{output}           ,
375   ) ];
376
377   if ($cf->{cc} eq 'cl' and $cf->{ccversion} =~ /^(\d+)/ and $1 >= 14) {
378     # Embed the manifest file for VC 2005 (aka VC 8) or higher
379     push @cmds, [
380       'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2"
381     ];
382   }
383
384   return @cmds;
385 }
386
387 sub write_linker_script {
388   my ($self, %spec) = @_;
389
390   my $script = File::Spec->catfile( $spec{srcdir},
391                                     $spec{basename} . '.lds' );
392
393   $self->add_to_cleanup($script);
394
395   print "Generating script '$script'\n" if !$self->{quiet};
396
397   open( SCRIPT, ">$script" )
398     or die( "Could not create script '$script': $!" );
399
400   print SCRIPT join( "\n",
401     map { ref $_ ? @{$_} : $_ }
402     grep defined,
403     delete(
404       @spec{ qw(lddlflags libpath other_ldflags
405                 startup objects libperl perllibs
406                 def_file implib map_file)            } )
407   );
408
409   close SCRIPT;
410
411   push @{$spec{lddlflags}}, '@"' . $script . '"';
412
413   return %spec;
414 }
415
416 1;
417
418 ########################################################################
419 package ExtUtils::CBuilder::Platform::Windows::BCC;
420
421 sub format_compiler_cmd {
422   my ($self, %spec) = @_;
423
424   foreach my $path ( @{ $spec{includes} || [] },
425                      @{ $spec{perlinc}  || [] } ) {
426     $path = '-I' . $path;
427   }
428
429   %spec = $self->write_compiler_script(%spec)
430     if $spec{use_scripts};
431
432   return [ grep {defined && length} (
433     $spec{cc}, '-c'         ,
434     @{$spec{includes}}      ,
435     @{$spec{cflags}}        ,
436     @{$spec{optimize}}      ,
437     @{$spec{defines}}       ,
438     @{$spec{perlinc}}       ,
439     "-o$spec{output}"       ,
440     $spec{source}           ,
441   ) ];
442 }
443
444 sub write_compiler_script {
445   my ($self, %spec) = @_;
446
447   my $script = File::Spec->catfile( $spec{srcdir},
448                                     $spec{basename} . '.ccs' );
449
450   $self->add_to_cleanup($script);
451
452   print "Generating script '$script'\n" if !$self->{quiet};
453
454   open( SCRIPT, ">$script" )
455     or die( "Could not create script '$script': $!" );
456
457   # XXX Borland "response files" seem to be unable to accept macro
458   # definitions containing quoted strings. Escaping strings with
459   # backslash doesn't work, and any level of quotes are stripped. The
460   # result is is a floating point number in the source file where a
461   # string is expected. So we leave the macros on the command line.
462   print SCRIPT join( "\n",
463     map { ref $_ ? @{$_} : $_ }
464     grep defined,
465     delete(
466       @spec{ qw(includes cflags optimize perlinc) } )
467   );
468
469   close SCRIPT;
470
471   push @{$spec{includes}}, '@"' . $script . '"';
472
473   return %spec;
474 }
475
476 sub format_linker_cmd {
477   my ($self, %spec) = @_;
478
479   foreach my $path ( @{$spec{libpath}} ) {
480     $path = "-L$path";
481   }
482
483   push( @{$spec{startup}}, 'c0d32.obj' )
484     unless ( $spec{starup} && @{$spec{startup}} );
485
486   %spec = $self->write_linker_script(%spec)
487     if $spec{use_scripts};
488
489   return [ grep {defined && length} (
490     $spec{ld}               ,
491     @{$spec{lddlflags}}     ,
492     @{$spec{libpath}}       ,
493     @{$spec{other_ldflags}} ,
494     @{$spec{startup}}       ,
495     @{$spec{objects}}       , ',',
496     $spec{output}           , ',',
497     $spec{map_file}         , ',',
498     $spec{libperl}          ,
499     @{$spec{perllibs}}      , ',',
500     $spec{def_file}
501   ) ];
502 }
503
504 sub write_linker_script {
505   my ($self, %spec) = @_;
506
507   # To work around Borlands "unique" commandline syntax,
508   # two scripts are used:
509
510   my $ld_script = File::Spec->catfile( $spec{srcdir},
511                                        $spec{basename} . '.lds' );
512   my $ld_libs   = File::Spec->catfile( $spec{srcdir},
513                                        $spec{basename} . '.lbs' );
514
515   $self->add_to_cleanup($ld_script, $ld_libs);
516
517   print "Generating scripts '$ld_script' and '$ld_libs'.\n" if !$self->{quiet};
518
519   # Script 1: contains options & names of object files.
520   open( LD_SCRIPT, ">$ld_script" )
521     or die( "Could not create linker script '$ld_script': $!" );
522
523   print LD_SCRIPT join( " +\n",
524     map { @{$_} }
525     grep defined,
526     delete(
527       @spec{ qw(lddlflags libpath other_ldflags startup objects) } )
528   );
529
530   close LD_SCRIPT;
531
532   # Script 2: contains name of libs to link against.
533   open( LD_LIBS, ">$ld_libs" )
534     or die( "Could not create linker script '$ld_libs': $!" );
535
536   print LD_LIBS join( " +\n",
537      (delete $spec{libperl}  || ''),
538     @{delete $spec{perllibs} || []},
539   );
540
541   close LD_LIBS;
542
543   push @{$spec{lddlflags}}, '@"' . $ld_script  . '"';
544   push @{$spec{perllibs}},  '@"' . $ld_libs    . '"';
545
546   return %spec;
547 }
548
549 1;
550
551 ########################################################################
552 package ExtUtils::CBuilder::Platform::Windows::GCC;
553
554 sub format_compiler_cmd {
555   my ($self, %spec) = @_;
556
557   foreach my $path ( @{ $spec{includes} || [] },
558                      @{ $spec{perlinc}  || [] } ) {
559     $path = '-I' . $path;
560   }
561
562   # split off any -arguments included in cc
563   my @cc = split / (?=-)/, $spec{cc};
564
565   return [ grep {defined && length} (
566     @cc, '-c'               ,
567     @{$spec{includes}}      ,
568     @{$spec{cflags}}        ,
569     @{$spec{optimize}}      ,
570     @{$spec{defines}}       ,
571     @{$spec{perlinc}}       ,
572     '-o', $spec{output}     ,
573     $spec{source}           ,
574   ) ];
575 }
576
577 sub format_linker_cmd {
578   my ($self, %spec) = @_;
579
580   # The Config.pm variable 'libperl' is hardcoded to the full name
581   # of the perl import library (i.e. 'libperl56.a'). GCC will not
582   # find it unless the 'lib' prefix & the extension are stripped.
583   $spec{libperl} =~ s/^(?:lib)?([^.]+).*$/-l$1/;
584
585   unshift( @{$spec{other_ldflags}}, '-nostartfiles' )
586     if ( $spec{startup} && @{$spec{startup}} );
587
588   # From ExtUtils::MM_Win32:
589   #
590   ## one thing for GCC/Mingw32:
591   ## we try to overcome non-relocateable-DLL problems by generating
592   ##    a (hopefully unique) image-base from the dll's name
593   ## -- BKS, 10-19-1999
594   File::Basename::basename( $spec{output} ) =~ /(....)(.{0,4})/;
595   $spec{image_base} = sprintf( "0x%x0000", unpack('n', $1 ^ $2) );
596
597   %spec = $self->write_linker_script(%spec)
598     if $spec{use_scripts};
599
600   foreach my $path ( @{$spec{libpath}} ) {
601     $path = "-L$path";
602   }
603
604   my @cmds; # Stores the series of commands needed to build the module.
605
606   push @cmds, [
607     'dlltool', '--def'        , $spec{def_file},
608                '--output-exp' , $spec{explib}
609   ];
610
611   # split off any -arguments included in ld
612   my @ld = split / (?=-)/, $spec{ld};
613
614   push @cmds, [ grep {defined && length} (
615     @ld                       ,
616     '-o', $spec{output}       ,
617     "-Wl,--base-file,$spec{base_file}"   ,
618     "-Wl,--image-base,$spec{image_base}" ,
619     @{$spec{lddlflags}}       ,
620     @{$spec{libpath}}         ,
621     @{$spec{startup}}         ,
622     @{$spec{objects}}         ,
623     @{$spec{other_ldflags}}   ,
624     $spec{libperl}            ,
625     @{$spec{perllibs}}        ,
626     $spec{explib}             ,
627     $spec{map_file} ? ('-Map', $spec{map_file}) : ''
628   ) ];
629
630   push @cmds, [
631     'dlltool', '--def'        , $spec{def_file},
632                '--output-exp' , $spec{explib},
633                '--base-file'  , $spec{base_file}
634   ];
635
636   push @cmds, [ grep {defined && length} (
637     @ld                       ,
638     '-o', $spec{output}       ,
639     "-Wl,--image-base,$spec{image_base}" ,
640     @{$spec{lddlflags}}       ,
641     @{$spec{libpath}}         ,
642     @{$spec{startup}}         ,
643     @{$spec{objects}}         ,
644     @{$spec{other_ldflags}}   ,
645     $spec{libperl}            ,
646     @{$spec{perllibs}}        ,
647     $spec{explib}             ,
648     $spec{map_file} ? ('-Map', $spec{map_file}) : ''
649   ) ];
650
651   return @cmds;
652 }
653
654 sub write_linker_script {
655   my ($self, %spec) = @_;
656
657   my $script = File::Spec->catfile( $spec{srcdir},
658                                     $spec{basename} . '.lds' );
659
660   $self->add_to_cleanup($script);
661
662   print "Generating script '$script'\n" if !$self->{quiet};
663
664   open( SCRIPT, ">$script" )
665     or die( "Could not create script '$script': $!" );
666
667   print( SCRIPT 'SEARCH_DIR(' . $_ . ")\n" )
668     for @{delete $spec{libpath} || []};
669
670   # gcc takes only one startup file, so the first object in startup is
671   # specified as the startup file and any others are shifted into the
672   # beginning of the list of objects.
673   if ( $spec{startup} && @{$spec{startup}} ) {
674     print SCRIPT 'STARTUP(' . shift( @{$spec{startup}} ) . ")\n";
675     unshift @{$spec{objects}},
676       @{delete $spec{startup} || []};
677   }
678
679   print SCRIPT 'INPUT(' . join( ',',
680     @{delete $spec{objects}  || []}
681   ) . ")\n";
682
683   print SCRIPT 'INPUT(' . join( ' ',
684      (delete $spec{libperl}  || ''),
685     @{delete $spec{perllibs} || []},
686   ) . ")\n";
687
688   close SCRIPT;
689
690   push @{$spec{other_ldflags}}, '"' . $script . '"';
691
692   return %spec;
693 }
694
695 1;
696
697 __END__
698
699 =head1 NAME
700
701 ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms
702
703 =head1 DESCRIPTION
704
705 This module implements the Windows-specific parts of ExtUtils::CBuilder.
706 Most of the Windows-specific stuff has to do with compiling and
707 linking C code.  Currently we support the 3 compilers perl itself
708 supports: MSVC, BCC, and GCC.
709
710 This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality
711 not implemented here will be implemented there.  The interfaces are
712 defined by the L<ExtUtils::CBuilder> documentation.
713
714 =head1 AUTHOR
715
716 Ken Williams <ken@mathforum.org>
717
718 Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>.
719
720 =head1 SEE ALSO
721
722 perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3)
723
724 =cut