1 package ExtUtils::CBuilder::Platform::Windows;
9 use ExtUtils::CBuilder::Base;
12 use vars qw($VERSION @ISA);
14 @ISA = qw(ExtUtils::CBuilder::Base);
18 my $self = $class->SUPER::new(@_);
19 my $cf = $self->{config};
21 # Inherit from an appropriate compiler driver class
22 unshift @ISA, "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type;
29 my $cc = $self->{config}{cc};
31 return ( $cc =~ /cl(\.exe)?$/ ? 'MSVC'
32 : $cc =~ /bcc32(\.exe)?$/ ? 'BCC'
36 sub split_like_shell {
37 # Since Windows will pass the whole command string (not an argument
38 # array) to the target program and make the program parse it itself,
39 # we don't actually need to do any processing here.
40 (my $self, local $_) = @_;
42 return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY');
43 return unless defined() && length();
52 map {$a=$_;$a=~s/\t/ /g;$a=~s/^\s+|\s+$//;$a}
54 return $self->SUPER::do_system($cmd);
58 my ($self, %args) = @_;
59 s/"/\\"/g foreach values %args;
60 return map qq{"-D$_=$args{$_}"}, keys %args;
64 my ($self, %args) = @_;
65 my $cf = $self->{config};
67 die "Missing 'source' argument to compile()" unless defined $args{source};
69 my ($basename, $srcdir) =
70 ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1];
72 $srcdir ||= File::Spec->curdir();
74 my @defines = $self->arg_defines( %{ $args{defines} || {} } );
79 basename => $basename,
80 source => $args{source},
81 output => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext},
84 $self->split_like_shell($cf->{ccflags}),
85 $self->split_like_shell($cf->{cccdlflags}),
86 $self->split_like_shell($args{extra_compiler_flags}),
88 optimize => [ $self->split_like_shell($cf->{optimize}) ],
90 includes => [ @{$args{include_dirs} || []} ],
93 $self->split_like_shell($cf->{incpath}),
95 use_scripts => 1, # XXX provide user option to change this???
98 $self->normalize_filespecs(
105 my @cmds = $self->format_compiler_cmd(%spec);
106 while ( my $cmd = shift @cmds ) {
107 $self->do_system( @$cmd )
108 or die "error building $cf->{dlext} file from '$args{source}'";
111 (my $out = $spec{output}) =~ tr/'"//d;
115 sub need_prelink { 1 }
118 my ($self, %args) = @_;
119 my $cf = $self->{config};
121 my @objects = ( ref $args{objects} eq 'ARRAY' ? @{$args{objects}} : $args{objects} );
122 my $to = join '', (File::Spec->splitpath($objects[0]))[0,1];
123 $to ||= File::Spec->curdir();
125 (my $file_base = $args{module_name}) =~ s/.*:://;
126 my $output = $args{lib_file} ||
127 File::Spec->catfile($to, "$file_base.$cf->{dlext}");
129 # if running in perl source tree, look for libs there, not installed
130 my $lddlflags = $cf->{lddlflags};
131 my $perl_src = $self->perl_src();
132 $lddlflags =~ s/\Q$cf->{archlibexp}\E[\\\/]CORE/$perl_src/ if $perl_src;
138 objects => \@objects,
142 libperl => $cf->{libperl},
143 perllibs => [ $self->split_like_shell($cf->{perllibs}) ],
144 libpath => [ $self->split_like_shell($cf->{libpth}) ],
145 lddlflags => [ $self->split_like_shell($lddlflags) ],
146 other_ldflags => [ $self->split_like_shell($args{extra_linker_flags} || '') ],
147 use_scripts => 1, # XXX provide user option to change this???
150 unless ( $spec{basename} ) {
151 ($spec{basename} = $args{module_name}) =~ s/.*:://;
154 $spec{srcdir} = File::Spec->canonpath( $spec{srcdir} );
155 $spec{builddir} = File::Spec->canonpath( $spec{builddir} );
157 $spec{output} ||= File::Spec->catfile( $spec{builddir},
158 $spec{basename} . '.'.$cf->{dlext} );
159 $spec{manifest} ||= File::Spec->catfile( $spec{builddir},
160 $spec{basename} . '.'.$cf->{dlext}.'.manifest');
161 $spec{implib} ||= File::Spec->catfile( $spec{builddir},
162 $spec{basename} . $cf->{lib_ext} );
163 $spec{explib} ||= File::Spec->catfile( $spec{builddir},
164 $spec{basename} . '.exp' );
165 if ($cf->{cc} eq 'cl') {
166 $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir},
167 $spec{basename} . '.pdb' );
169 elsif ($cf->{cc} eq 'bcc32') {
170 $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir},
171 $spec{basename} . '.tds' );
173 $spec{def_file} ||= File::Spec->catfile( $spec{srcdir} ,
174 $spec{basename} . '.def' );
175 $spec{base_file} ||= File::Spec->catfile( $spec{srcdir} ,
176 $spec{basename} . '.base' );
178 $self->add_to_cleanup(
180 @{[ @spec{qw(manifest implib explib dbg_file def_file base_file map_file)} ]}
183 foreach my $opt ( qw(output manifest implib explib dbg_file def_file map_file base_file) ) {
184 $self->normalize_filespecs( \$spec{$opt} );
187 foreach my $opt ( qw(libpath startup objects) ) {
188 $self->normalize_filespecs( $spec{$opt} );
191 (my $def_base = $spec{def_file}) =~ tr/'"//d;
192 $def_base =~ s/\.def$//;
193 $self->prelink( dl_name => $args{module_name},
194 dl_file => $def_base,
195 dl_base => $spec{basename} );
197 my @cmds = $self->format_linker_cmd(%spec);
198 while ( my $cmd = shift @cmds ) {
199 $self->do_system( @$cmd );
202 $spec{output} =~ tr/'"//d;
204 ? grep defined, @spec{qw[output manifest implib explib dbg_file def_file map_file base_file]}
208 # canonize & quote paths
209 sub normalize_filespecs {
210 my ($self, @specs) = @_;
211 foreach my $spec ( grep defined, @specs ) {
212 if ( ref $spec eq 'ARRAY') {
213 $self->normalize_filespecs( map {\$_} grep defined, @$spec )
214 } elsif ( ref $spec eq 'SCALAR' ) {
215 $$spec =~ tr/"//d if $$spec;
217 $$spec = '"' . File::Spec->canonpath($$spec) . '"';
218 } elsif ( ref $spec eq '' ) {
219 $spec = '"' . File::Spec->canonpath($spec) . '"';
221 die "Don't know how to normalize " . (ref $spec || $spec) . "\n";
226 # directory of perl's include files
230 my $perl_src = $self->perl_src();
233 File::Spec->catdir($perl_src, "lib", "CORE");
235 File::Spec->catdir($self->{config}{archlibexp},"CORE");
241 ########################################################################
245 The packages below implement functions for generating properly
246 formatted commandlines for the compiler being used. Each package
247 defines two primary functions 'format_linker_cmd()' &
248 'format_compiler_cmd()' that accepts a list of named arguments (a
249 hash) and returns a list of formatted options suitable for invoking the
250 compiler. By default, if the compiler supports scripting of its
251 operation then a script file is built containing the options while
252 those options are removed from the commandline, and a reference to the
253 script is pushed onto the commandline in their place. Scripting the
254 compiler in this way helps to avoid the problems associated with long
255 commandlines under some shells.
261 ########################################################################
262 package ExtUtils::CBuilder::Platform::Windows::MSVC;
264 sub format_compiler_cmd {
265 my ($self, %spec) = @_;
267 foreach my $path ( @{ $spec{includes} || [] },
268 @{ $spec{perlinc} || [] } ) {
269 $path = '-I' . $path;
272 %spec = $self->write_compiler_script(%spec)
273 if $spec{use_scripts};
275 return [ grep {defined && length} (
276 $spec{cc},'-nologo','-c',
287 sub write_compiler_script {
288 my ($self, %spec) = @_;
290 my $script = File::Spec->catfile( $spec{srcdir},
291 $spec{basename} . '.ccs' );
293 $self->add_to_cleanup($script);
294 print "Generating script '$script'\n" if !$self->{quiet};
296 my $SCRIPT = IO::File->new( ">$script" )
297 or die( "Could not create script '$script': $!" );
299 print $SCRIPT join( "\n",
300 map { ref $_ ? @{$_} : $_ }
303 @spec{ qw(includes cflags optimize defines perlinc) } )
306 push @{$spec{includes}}, '@"' . $script . '"';
311 sub format_linker_cmd {
312 my ($self, %spec) = @_;
313 my $cf = $self->{config};
315 foreach my $path ( @{$spec{libpath}} ) {
316 $path = "-libpath:$path";
319 my $output = $spec{output};
321 $spec{def_file} &&= '-def:' . $spec{def_file};
322 $spec{output} &&= '-out:' . $spec{output};
323 $spec{manifest} &&= '-manifest ' . $spec{manifest};
324 $spec{implib} &&= '-implib:' . $spec{implib};
325 $spec{map_file} &&= '-map:' . $spec{map_file};
327 %spec = $self->write_linker_script(%spec)
328 if $spec{use_scripts};
330 my @cmds; # Stores the series of commands needed to build the module.
332 push @cmds, [ grep {defined && length} (
334 @{$spec{lddlflags}} ,
336 @{$spec{other_ldflags}} ,
347 # Embed the manifest file for VC 2005 (aka VC 8) or higher, but not for the 64-bit Platform SDK compiler
348 if ($cf->{ivsize} == 4 && $cf->{cc} eq 'cl' and $cf->{ccversion} =~ /^(\d+)/ and $1 >= 14) {
350 'if', 'exist', $spec{manifest}, 'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2"
357 sub write_linker_script {
358 my ($self, %spec) = @_;
360 my $script = File::Spec->catfile( $spec{srcdir},
361 $spec{basename} . '.lds' );
363 $self->add_to_cleanup($script);
365 print "Generating script '$script'\n" if !$self->{quiet};
367 my $SCRIPT = IO::File->new( ">$script" )
368 or die( "Could not create script '$script': $!" );
370 print $SCRIPT join( "\n",
371 map { ref $_ ? @{$_} : $_ }
374 @spec{ qw(lddlflags libpath other_ldflags
375 startup objects libperl perllibs
376 def_file implib map_file) } )
379 push @{$spec{lddlflags}}, '@"' . $script . '"';
386 ########################################################################
387 package ExtUtils::CBuilder::Platform::Windows::BCC;
389 sub format_compiler_cmd {
390 my ($self, %spec) = @_;
392 foreach my $path ( @{ $spec{includes} || [] },
393 @{ $spec{perlinc} || [] } ) {
394 $path = '-I' . $path;
397 %spec = $self->write_compiler_script(%spec)
398 if $spec{use_scripts};
400 return [ grep {defined && length} (
412 sub write_compiler_script {
413 my ($self, %spec) = @_;
415 my $script = File::Spec->catfile( $spec{srcdir},
416 $spec{basename} . '.ccs' );
418 $self->add_to_cleanup($script);
420 print "Generating script '$script'\n" if !$self->{quiet};
422 my $SCRIPT = IO::File->new( ">$script" )
423 or die( "Could not create script '$script': $!" );
425 # XXX Borland "response files" seem to be unable to accept macro
426 # definitions containing quoted strings. Escaping strings with
427 # backslash doesn't work, and any level of quotes are stripped. The
428 # result is is a floating point number in the source file where a
429 # string is expected. So we leave the macros on the command line.
430 print $SCRIPT join( "\n",
431 map { ref $_ ? @{$_} : $_ }
434 @spec{ qw(includes cflags optimize perlinc) } )
437 push @{$spec{includes}}, '@"' . $script . '"';
442 sub format_linker_cmd {
443 my ($self, %spec) = @_;
445 foreach my $path ( @{$spec{libpath}} ) {
449 push( @{$spec{startup}}, 'c0d32.obj' )
450 unless ( $spec{starup} && @{$spec{startup}} );
452 %spec = $self->write_linker_script(%spec)
453 if $spec{use_scripts};
455 return [ grep {defined && length} (
457 @{$spec{lddlflags}} ,
459 @{$spec{other_ldflags}} ,
461 @{$spec{objects}} , ',',
463 $spec{map_file} , ',',
465 @{$spec{perllibs}} , ',',
470 sub write_linker_script {
471 my ($self, %spec) = @_;
473 # To work around Borlands "unique" commandline syntax,
474 # two scripts are used:
476 my $ld_script = File::Spec->catfile( $spec{srcdir},
477 $spec{basename} . '.lds' );
478 my $ld_libs = File::Spec->catfile( $spec{srcdir},
479 $spec{basename} . '.lbs' );
481 $self->add_to_cleanup($ld_script, $ld_libs);
483 print "Generating scripts '$ld_script' and '$ld_libs'.\n" if !$self->{quiet};
485 # Script 1: contains options & names of object files.
486 my $LD_SCRIPT = IO::File->new( ">$ld_script" )
487 or die( "Could not create linker script '$ld_script': $!" );
489 print $LD_SCRIPT join( " +\n",
493 @spec{ qw(lddlflags libpath other_ldflags startup objects) } )
496 # Script 2: contains name of libs to link against.
497 my $LD_LIBS = IO::File->new( ">$ld_libs" )
498 or die( "Could not create linker script '$ld_libs': $!" );
500 print $LD_LIBS join( " +\n",
501 (delete $spec{libperl} || ''),
502 @{delete $spec{perllibs} || []},
505 push @{$spec{lddlflags}}, '@"' . $ld_script . '"';
506 push @{$spec{perllibs}}, '@"' . $ld_libs . '"';
513 ########################################################################
514 package ExtUtils::CBuilder::Platform::Windows::GCC;
516 sub format_compiler_cmd {
517 my ($self, %spec) = @_;
519 foreach my $path ( @{ $spec{includes} || [] },
520 @{ $spec{perlinc} || [] } ) {
521 $path = '-I' . $path;
524 # split off any -arguments included in cc
525 my @cc = split / (?=-)/, $spec{cc};
527 return [ grep {defined && length} (
534 '-o', $spec{output} ,
539 sub format_linker_cmd {
540 my ($self, %spec) = @_;
542 # The Config.pm variable 'libperl' is hardcoded to the full name
543 # of the perl import library (i.e. 'libperl56.a'). GCC will not
544 # find it unless the 'lib' prefix & the extension are stripped.
545 $spec{libperl} =~ s/^(?:lib)?([^.]+).*$/-l$1/;
547 unshift( @{$spec{other_ldflags}}, '-nostartfiles' )
548 if ( $spec{startup} && @{$spec{startup}} );
550 # From ExtUtils::MM_Win32:
552 ## one thing for GCC/Mingw32:
553 ## we try to overcome non-relocateable-DLL problems by generating
554 ## a (hopefully unique) image-base from the dll's name
555 ## -- BKS, 10-19-1999
556 File::Basename::basename( $spec{output} ) =~ /(....)(.{0,4})/;
557 $spec{image_base} = sprintf( "0x%x0000", unpack('n', $1 ^ $2) );
559 %spec = $self->write_linker_script(%spec)
560 if $spec{use_scripts};
562 foreach my $path ( @{$spec{libpath}} ) {
566 my @cmds; # Stores the series of commands needed to build the module.
569 'dlltool', '--def' , $spec{def_file},
570 '--output-exp' , $spec{explib}
573 # split off any -arguments included in ld
574 my @ld = split / (?=-)/, $spec{ld};
576 push @cmds, [ grep {defined && length} (
578 '-o', $spec{output} ,
579 "-Wl,--base-file,$spec{base_file}" ,
580 "-Wl,--image-base,$spec{image_base}" ,
581 @{$spec{lddlflags}} ,
585 @{$spec{other_ldflags}} ,
589 $spec{map_file} ? ('-Map', $spec{map_file}) : ''
593 'dlltool', '--def' , $spec{def_file},
594 '--output-exp' , $spec{explib},
595 '--base-file' , $spec{base_file}
598 push @cmds, [ grep {defined && length} (
600 '-o', $spec{output} ,
601 "-Wl,--image-base,$spec{image_base}" ,
602 @{$spec{lddlflags}} ,
606 @{$spec{other_ldflags}} ,
610 $spec{map_file} ? ('-Map', $spec{map_file}) : ''
616 sub write_linker_script {
617 my ($self, %spec) = @_;
619 my $script = File::Spec->catfile( $spec{srcdir},
620 $spec{basename} . '.lds' );
622 $self->add_to_cleanup($script);
624 print "Generating script '$script'\n" if !$self->{quiet};
626 my $SCRIPT = IO::File->new( ">$script" )
627 or die( "Could not create script '$script': $!" );
629 print $SCRIPT ( 'SEARCH_DIR(' . $_ . ")\n" )
630 for @{delete $spec{libpath} || []};
632 # gcc takes only one startup file, so the first object in startup is
633 # specified as the startup file and any others are shifted into the
634 # beginning of the list of objects.
635 if ( $spec{startup} && @{$spec{startup}} ) {
636 print $SCRIPT 'STARTUP(' . shift( @{$spec{startup}} ) . ")\n";
637 unshift @{$spec{objects}},
638 @{delete $spec{startup} || []};
641 print $SCRIPT 'INPUT(' . join( ',',
642 @{delete $spec{objects} || []}
645 print $SCRIPT 'INPUT(' . join( ' ',
646 (delete $spec{libperl} || ''),
647 @{delete $spec{perllibs} || []},
650 # push @{$spec{other_ldflags}}, '"' . $script . '"';
651 #it is important to keep the order 1.linker_script - 2.other_ldflags
652 @{$spec{other_ldflags}} = ( '"' . $script . '"',@{$spec{other_ldflags}} );
663 ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms
667 This module implements the Windows-specific parts of ExtUtils::CBuilder.
668 Most of the Windows-specific stuff has to do with compiling and
669 linking C code. Currently we support the 3 compilers perl itself
670 supports: MSVC, BCC, and GCC.
672 This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality
673 not implemented here will be implemented there. The interfaces are
674 defined by the L<ExtUtils::CBuilder> documentation.
678 Ken Williams <ken@mathforum.org>
680 Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>.
684 perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3)