1 package ExtUtils::CBuilder::Platform::Windows;
9 use ExtUtils::CBuilder::Base;
11 use vars qw($VERSION @ISA);
13 @ISA = qw(ExtUtils::CBuilder::Base);
17 my $self = $class->SUPER::new(@_);
18 my $cf = $self->{config};
20 # Inherit from an appropriate compiler driver class
21 unshift @ISA, "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type;
28 my $cc = $self->{config}{cc};
30 return ( $cc =~ /cl(\.exe)?$/ ? 'MSVC'
31 : $cc =~ /bcc32(\.exe)?$/ ? 'BCC'
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.
44 (my $self, local $_) = @_;
46 return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY');
49 return @argv unless defined() && length();
52 my( $i, $quote_mode ) = ( 0, 0 );
54 while ( $i < length() ) {
56 my $ch = substr( $_, $i , 1 );
57 my $next_ch = substr( $_, $i+1, 1 );
59 if ( $ch eq '\\' && $next_ch eq '"' ) {
62 } elsif ( $ch eq '\\' && $next_ch eq '\\' ) {
65 } elsif ( $ch eq '"' && $next_ch eq '"' && $quote_mode ) {
66 $quote_mode = !$quote_mode;
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' ]
76 } elsif ( $ch eq '"' ) {
77 $quote_mode = !$quote_mode;
78 } elsif ( $ch eq ' ' && !$quote_mode ) {
79 push( @argv, $arg ) if $arg;
81 ++$i while substr( $_, $i + 1, 1 ) eq ' ';
89 push( @argv, $arg ) if defined( $arg ) && length( $arg );
94 my ($self, %args) = @_;
95 s/"/\\"/g foreach values %args;
96 return map qq{"-D$_=$args{$_}"}, keys %args;
100 my ($self, %args) = @_;
101 my $cf = $self->{config};
103 die "Missing 'source' argument to compile()" unless defined $args{source};
105 my ($basename, $srcdir) =
106 ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1];
108 $srcdir ||= File::Spec->curdir();
110 my @defines = $self->arg_defines( %{ $args{defines} || {} } );
115 basename => $basename,
116 source => $args{source},
117 output => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext},
120 $self->split_like_shell($cf->{ccflags}),
121 $self->split_like_shell($cf->{cccdlflags}),
122 $self->split_like_shell($cf->{extra_compiler_flags}),
124 optimize => [ $self->split_like_shell($cf->{optimize}) ],
125 defines => \@defines,
126 includes => [ @{$args{include_dirs} || []} ],
129 $self->split_like_shell($cf->{incpath}),
131 use_scripts => 1, # XXX provide user option to change this???
134 $self->normalize_filespecs(
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}'";
147 (my $out = $spec{output}) =~ tr/'"//d;
151 sub need_prelink { 1 }
154 my ($self, %args) = @_;
155 my $cf = $self->{config};
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();
161 (my $file_base = $args{module_name}) =~ s/.*:://;
162 my $output = $args{lib_file} ||
163 File::Spec->catfile($to, "$file_base.$cf->{dlext}");
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;
174 objects => \@objects,
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???
186 unless ( $spec{basename} ) {
187 ($spec{basename} = $args{module_name}) =~ s/.*:://;
190 $spec{srcdir} = File::Spec->canonpath( $spec{srcdir} );
191 $spec{builddir} = File::Spec->canonpath( $spec{builddir} );
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 if ($cf->{cc} eq 'cl') {
202 $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir},
203 $spec{basename} . '.pdb' );
205 elsif ($cf->{cc} eq 'bcc32') {
206 $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir},
207 $spec{basename} . '.tds' );
209 $spec{def_file} ||= File::Spec->catfile( $spec{srcdir} ,
210 $spec{basename} . '.def' );
211 $spec{base_file} ||= File::Spec->catfile( $spec{srcdir} ,
212 $spec{basename} . '.base' );
214 $self->add_to_cleanup(
216 @{[ @spec{qw(manifest implib explib dbg_file def_file base_file map_file)} ]}
219 foreach my $opt ( qw(output manifest implib explib dbg_file def_file map_file base_file) ) {
220 $self->normalize_filespecs( \$spec{$opt} );
223 foreach my $opt ( qw(libpath startup objects) ) {
224 $self->normalize_filespecs( $spec{$opt} );
227 (my $def_base = $spec{def_file}) =~ tr/'"//d;
228 $def_base =~ s/\.def$//;
229 $self->prelink( dl_name => $args{module_name},
230 dl_file => $def_base,
231 dl_base => $spec{basename} );
233 my @cmds = $self->format_linker_cmd(%spec);
234 while ( my $cmd = shift @cmds ) {
235 $self->do_system( @$cmd );
238 $spec{output} =~ tr/'"//d;
240 ? grep defined, @spec{qw[output manifest implib explib dbg_file def_file map_file base_file]}
244 # canonize & quote paths
245 sub normalize_filespecs {
246 my ($self, @specs) = @_;
247 foreach my $spec ( grep defined, @specs ) {
248 if ( ref $spec eq 'ARRAY') {
249 $self->normalize_filespecs( map {\$_} grep defined, @$spec )
250 } elsif ( ref $spec eq 'SCALAR' ) {
251 $$spec =~ tr/"//d if $$spec;
253 $$spec = '"' . File::Spec->canonpath($$spec) . '"';
254 } elsif ( ref $spec eq '' ) {
255 $spec = '"' . File::Spec->canonpath($spec) . '"';
257 die "Don't know how to normalize " . (ref $spec || $spec) . "\n";
262 # directory of perl's include files
266 my $perl_src = $self->perl_src();
269 File::Spec->catdir($perl_src, "lib", "CORE");
271 File::Spec->catdir($self->{config}{archlibexp},"CORE");
277 ########################################################################
281 The packages below implement functions for generating properly
282 formatted commandlines for the compiler being used. Each package
283 defines two primary functions 'format_linker_cmd()' &
284 'format_compiler_cmd()' that accepts a list of named arguments (a
285 hash) and returns a list of formatted options suitable for invoking the
286 compiler. By default, if the compiler supports scripting of its
287 operation then a script file is built containing the options while
288 those options are removed from the commandline, and a reference to the
289 script is pushed onto the commandline in their place. Scripting the
290 compiler in this way helps to avoid the problems associated with long
291 commandlines under some shells.
297 ########################################################################
298 package ExtUtils::CBuilder::Platform::Windows::MSVC;
300 sub format_compiler_cmd {
301 my ($self, %spec) = @_;
303 foreach my $path ( @{ $spec{includes} || [] },
304 @{ $spec{perlinc} || [] } ) {
305 $path = '-I' . $path;
308 %spec = $self->write_compiler_script(%spec)
309 if $spec{use_scripts};
311 return [ grep {defined && length} (
312 $spec{cc},'-nologo','-c',
323 sub write_compiler_script {
324 my ($self, %spec) = @_;
326 my $script = File::Spec->catfile( $spec{srcdir},
327 $spec{basename} . '.ccs' );
329 $self->add_to_cleanup($script);
330 print "Generating script '$script'\n" if !$self->{quiet};
332 open( SCRIPT, ">$script" )
333 or die( "Could not create script '$script': $!" );
335 print SCRIPT join( "\n",
336 map { ref $_ ? @{$_} : $_ }
339 @spec{ qw(includes cflags optimize defines perlinc) } )
344 push @{$spec{includes}}, '@"' . $script . '"';
349 sub format_linker_cmd {
350 my ($self, %spec) = @_;
351 my $cf = $self->{config};
353 foreach my $path ( @{$spec{libpath}} ) {
354 $path = "-libpath:$path";
357 my $output = $spec{output};
359 $spec{def_file} &&= '-def:' . $spec{def_file};
360 $spec{output} &&= '-out:' . $spec{output};
361 $spec{manifest} &&= '-manifest ' . $spec{manifest};
362 $spec{implib} &&= '-implib:' . $spec{implib};
363 $spec{map_file} &&= '-map:' . $spec{map_file};
365 %spec = $self->write_linker_script(%spec)
366 if $spec{use_scripts};
368 my @cmds; # Stores the series of commands needed to build the module.
370 push @cmds, [ grep {defined && length} (
372 @{$spec{lddlflags}} ,
374 @{$spec{other_ldflags}} ,
385 # Embed the manifest file for VC 2005 (aka VC 8) or higher, but not for the 64-bit Platform SDK compiler
386 if ($cf->{ivsize} == 4 && $cf->{cc} eq 'cl' and $cf->{ccversion} =~ /^(\d+)/ and $1 >= 14) {
388 'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2"
395 sub write_linker_script {
396 my ($self, %spec) = @_;
398 my $script = File::Spec->catfile( $spec{srcdir},
399 $spec{basename} . '.lds' );
401 $self->add_to_cleanup($script);
403 print "Generating script '$script'\n" if !$self->{quiet};
405 open( SCRIPT, ">$script" )
406 or die( "Could not create script '$script': $!" );
408 print SCRIPT join( "\n",
409 map { ref $_ ? @{$_} : $_ }
412 @spec{ qw(lddlflags libpath other_ldflags
413 startup objects libperl perllibs
414 def_file implib map_file) } )
419 push @{$spec{lddlflags}}, '@"' . $script . '"';
426 ########################################################################
427 package ExtUtils::CBuilder::Platform::Windows::BCC;
429 sub format_compiler_cmd {
430 my ($self, %spec) = @_;
432 foreach my $path ( @{ $spec{includes} || [] },
433 @{ $spec{perlinc} || [] } ) {
434 $path = '-I' . $path;
437 %spec = $self->write_compiler_script(%spec)
438 if $spec{use_scripts};
440 return [ grep {defined && length} (
452 sub write_compiler_script {
453 my ($self, %spec) = @_;
455 my $script = File::Spec->catfile( $spec{srcdir},
456 $spec{basename} . '.ccs' );
458 $self->add_to_cleanup($script);
460 print "Generating script '$script'\n" if !$self->{quiet};
462 open( SCRIPT, ">$script" )
463 or die( "Could not create script '$script': $!" );
465 # XXX Borland "response files" seem to be unable to accept macro
466 # definitions containing quoted strings. Escaping strings with
467 # backslash doesn't work, and any level of quotes are stripped. The
468 # result is is a floating point number in the source file where a
469 # string is expected. So we leave the macros on the command line.
470 print SCRIPT join( "\n",
471 map { ref $_ ? @{$_} : $_ }
474 @spec{ qw(includes cflags optimize perlinc) } )
479 push @{$spec{includes}}, '@"' . $script . '"';
484 sub format_linker_cmd {
485 my ($self, %spec) = @_;
487 foreach my $path ( @{$spec{libpath}} ) {
491 push( @{$spec{startup}}, 'c0d32.obj' )
492 unless ( $spec{starup} && @{$spec{startup}} );
494 %spec = $self->write_linker_script(%spec)
495 if $spec{use_scripts};
497 return [ grep {defined && length} (
499 @{$spec{lddlflags}} ,
501 @{$spec{other_ldflags}} ,
503 @{$spec{objects}} , ',',
505 $spec{map_file} , ',',
507 @{$spec{perllibs}} , ',',
512 sub write_linker_script {
513 my ($self, %spec) = @_;
515 # To work around Borlands "unique" commandline syntax,
516 # two scripts are used:
518 my $ld_script = File::Spec->catfile( $spec{srcdir},
519 $spec{basename} . '.lds' );
520 my $ld_libs = File::Spec->catfile( $spec{srcdir},
521 $spec{basename} . '.lbs' );
523 $self->add_to_cleanup($ld_script, $ld_libs);
525 print "Generating scripts '$ld_script' and '$ld_libs'.\n" if !$self->{quiet};
527 # Script 1: contains options & names of object files.
528 open( LD_SCRIPT, ">$ld_script" )
529 or die( "Could not create linker script '$ld_script': $!" );
531 print LD_SCRIPT join( " +\n",
535 @spec{ qw(lddlflags libpath other_ldflags startup objects) } )
540 # Script 2: contains name of libs to link against.
541 open( LD_LIBS, ">$ld_libs" )
542 or die( "Could not create linker script '$ld_libs': $!" );
544 print LD_LIBS join( " +\n",
545 (delete $spec{libperl} || ''),
546 @{delete $spec{perllibs} || []},
551 push @{$spec{lddlflags}}, '@"' . $ld_script . '"';
552 push @{$spec{perllibs}}, '@"' . $ld_libs . '"';
559 ########################################################################
560 package ExtUtils::CBuilder::Platform::Windows::GCC;
562 sub format_compiler_cmd {
563 my ($self, %spec) = @_;
565 foreach my $path ( @{ $spec{includes} || [] },
566 @{ $spec{perlinc} || [] } ) {
567 $path = '-I' . $path;
570 # split off any -arguments included in cc
571 my @cc = split / (?=-)/, $spec{cc};
573 return [ grep {defined && length} (
580 '-o', $spec{output} ,
585 sub format_linker_cmd {
586 my ($self, %spec) = @_;
588 # The Config.pm variable 'libperl' is hardcoded to the full name
589 # of the perl import library (i.e. 'libperl56.a'). GCC will not
590 # find it unless the 'lib' prefix & the extension are stripped.
591 $spec{libperl} =~ s/^(?:lib)?([^.]+).*$/-l$1/;
593 unshift( @{$spec{other_ldflags}}, '-nostartfiles' )
594 if ( $spec{startup} && @{$spec{startup}} );
596 # From ExtUtils::MM_Win32:
598 ## one thing for GCC/Mingw32:
599 ## we try to overcome non-relocateable-DLL problems by generating
600 ## a (hopefully unique) image-base from the dll's name
601 ## -- BKS, 10-19-1999
602 File::Basename::basename( $spec{output} ) =~ /(....)(.{0,4})/;
603 $spec{image_base} = sprintf( "0x%x0000", unpack('n', $1 ^ $2) );
605 %spec = $self->write_linker_script(%spec)
606 if $spec{use_scripts};
608 foreach my $path ( @{$spec{libpath}} ) {
612 my @cmds; # Stores the series of commands needed to build the module.
615 'dlltool', '--def' , $spec{def_file},
616 '--output-exp' , $spec{explib}
619 # split off any -arguments included in ld
620 my @ld = split / (?=-)/, $spec{ld};
622 push @cmds, [ grep {defined && length} (
624 '-o', $spec{output} ,
625 "-Wl,--base-file,$spec{base_file}" ,
626 "-Wl,--image-base,$spec{image_base}" ,
627 @{$spec{lddlflags}} ,
631 @{$spec{other_ldflags}} ,
635 $spec{map_file} ? ('-Map', $spec{map_file}) : ''
639 'dlltool', '--def' , $spec{def_file},
640 '--output-exp' , $spec{explib},
641 '--base-file' , $spec{base_file}
644 push @cmds, [ grep {defined && length} (
646 '-o', $spec{output} ,
647 "-Wl,--image-base,$spec{image_base}" ,
648 @{$spec{lddlflags}} ,
652 @{$spec{other_ldflags}} ,
656 $spec{map_file} ? ('-Map', $spec{map_file}) : ''
662 sub write_linker_script {
663 my ($self, %spec) = @_;
665 my $script = File::Spec->catfile( $spec{srcdir},
666 $spec{basename} . '.lds' );
668 $self->add_to_cleanup($script);
670 print "Generating script '$script'\n" if !$self->{quiet};
672 open( SCRIPT, ">$script" )
673 or die( "Could not create script '$script': $!" );
675 print( SCRIPT 'SEARCH_DIR(' . $_ . ")\n" )
676 for @{delete $spec{libpath} || []};
678 # gcc takes only one startup file, so the first object in startup is
679 # specified as the startup file and any others are shifted into the
680 # beginning of the list of objects.
681 if ( $spec{startup} && @{$spec{startup}} ) {
682 print SCRIPT 'STARTUP(' . shift( @{$spec{startup}} ) . ")\n";
683 unshift @{$spec{objects}},
684 @{delete $spec{startup} || []};
687 print SCRIPT 'INPUT(' . join( ',',
688 @{delete $spec{objects} || []}
691 print SCRIPT 'INPUT(' . join( ' ',
692 (delete $spec{libperl} || ''),
693 @{delete $spec{perllibs} || []},
698 push @{$spec{other_ldflags}}, '"' . $script . '"';
709 ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms
713 This module implements the Windows-specific parts of ExtUtils::CBuilder.
714 Most of the Windows-specific stuff has to do with compiling and
715 linking C code. Currently we support the 3 compilers perl itself
716 supports: MSVC, BCC, and GCC.
718 This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality
719 not implemented here will be implemented there. The interfaces are
720 defined by the L<ExtUtils::CBuilder> documentation.
724 Ken Williams <ken@mathforum.org>
726 Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>.
730 perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3)