This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
RE: [PATCH] Restore Win64 compilation with the Windows Platform SDK
[perl5.git] / lib / ExtUtils / CBuilder / Platform / Windows.pm
CommitLineData
6b09c160
YST
1package ExtUtils::CBuilder::Platform::Windows;
2
3use strict;
4use warnings;
5
6use File::Basename;
7use File::Spec;
8
9use ExtUtils::CBuilder::Base;
10
11use vars qw($VERSION @ISA);
3b91ae7a 12$VERSION = '0.12_01';
6b09c160
YST
13@ISA = qw(ExtUtils::CBuilder::Base);
14
15sub 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
26sub _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
35sub 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
d1cf867f
SP
93sub arg_defines {
94 my ($self, %args) = @_;
95 s/"/\\"/g foreach values %args;
ea2e6518 96 return map qq{"-D$_=$args{$_}"}, keys %args;
d1cf867f
SP
97}
98
6b09c160
YST
99sub 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
d1cf867f
SP
110 my @defines = $self->arg_defines( %{ $args{defines} || {} } );
111
6b09c160
YST
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}),
d1cf867f 122 $self->split_like_shell($cf->{extra_compiler_flags}),
6b09c160
YST
123 ],
124 optimize => [ $self->split_like_shell($cf->{optimize}) ],
d1cf867f 125 defines => \@defines,
6b09c160
YST
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
6b09c160
YST
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
151sub need_prelink { 1 }
152
153sub 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();
345dbb93 168 $lddlflags =~ s/\Q$cf->{archlibexp}\E[\\\/]CORE/$perl_src/ if $perl_src;
6b09c160
YST
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} );
3172152a
SH
195 $spec{manifest} ||= File::Spec->catfile( $spec{builddir},
196 $spec{basename} . '.'.$cf->{dlext}.'.manifest');
6b09c160
YST
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,
3172152a 208 @{[ @spec{qw(manifest implib explib def_file base_file map_file)} ]}
6b09c160
YST
209 );
210
3172152a 211 foreach my $opt ( qw(output manifest implib explib def_file map_file base_file) ) {
6b09c160
YST
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
3172152a 232 ? grep defined, @spec{qw[output manifest implib explib def_file map_file base_file]}
6b09c160
YST
233 : $spec{output};
234}
235
236# canonize & quote paths
237sub 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
255sub 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
2671;
268
269########################################################################
270
271=begin comment
272
273The packages below implement functions for generating properly
3c4b39be 274formatted commandlines for the compiler being used. Each package
6b09c160
YST
275defines two primary functions 'format_linker_cmd()' &
276'format_compiler_cmd()' that accepts a list of named arguments (a
3c4b39be 277hash) and returns a list of formatted options suitable for invoking the
6b09c160
YST
278compiler. By default, if the compiler supports scripting of its
279operation then a script file is built containing the options while
280those options are removed from the commandline, and a reference to the
281script is pushed onto the commandline in their place. Scripting the
282compiler in this way helps to avoid the problems associated with long
283commandlines under some shells.
284
285=end comment
286
287=cut
288
289########################################################################
290package ExtUtils::CBuilder::Platform::Windows::MSVC;
291
292sub 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
315sub 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);
6b09c160
YST
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
341sub format_linker_cmd {
342 my ($self, %spec) = @_;
3172152a 343 my $cf = $self->{config};
6b09c160
YST
344
345 foreach my $path ( @{$spec{libpath}} ) {
346 $path = "-libpath:$path";
347 }
348
3172152a
SH
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};
6b09c160
YST
356
357 %spec = $self->write_linker_script(%spec)
358 if $spec{use_scripts};
359
3172152a
SH
360 my @cmds; # Stores the series of commands needed to build the module.
361
362 push @cmds, [ grep {defined && length} (
6b09c160
YST
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 ) ];
3172152a 376
f6397ea5
JD
377 # Embed the manifest file for VC 2005 (aka VC 8) or higher, but not for the 64-bit Platform SDK compiler
378 if ($cf->{ivsize} == 4 && $cf->{cc} eq 'cl' and $cf->{ccversion} =~ /^(\d+)/ and $1 >= 14) {
3172152a
SH
379 push @cmds, [
380 'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2"
381 ];
382 }
383
384 return @cmds;
6b09c160
YST
385}
386
387sub 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
4161;
417
418########################################################################
419package ExtUtils::CBuilder::Platform::Windows::BCC;
420
421sub 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
444sub 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
3b91ae7a
RS
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.
6b09c160
YST
462 print SCRIPT join( "\n",
463 map { ref $_ ? @{$_} : $_ }
464 grep defined,
465 delete(
3b91ae7a 466 @spec{ qw(includes cflags optimize perlinc) } )
6b09c160
YST
467 );
468
469 close SCRIPT;
470
471 push @{$spec{includes}}, '@"' . $script . '"';
472
473 return %spec;
474}
475
476sub 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
504sub 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
5491;
550
551########################################################################
552package ExtUtils::CBuilder::Platform::Windows::GCC;
553
554sub 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
577sub 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
654sub 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
6951;
696
697__END__
698
699=head1 NAME
700
701ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms
702
703=head1 DESCRIPTION
704
705This module implements the Windows-specific parts of ExtUtils::CBuilder.
706Most of the Windows-specific stuff has to do with compiling and
707linking C code. Currently we support the 3 compilers perl itself
708supports: MSVC, BCC, and GCC.
709
710This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality
711not implemented here will be implemented there. The interfaces are
712defined by the L<ExtUtils::CBuilder> documentation.
713
714=head1 AUTHOR
715
716Ken Williams <ken@mathforum.org>
717
718Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>.
719
720=head1 SEE ALSO
721
722perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3)
723
724=cut