1 package ExtUtils::CBuilder::Platform::Windows;
9 use ExtUtils::CBuilder::Base;
12 use vars qw($VERSION @ISA);
14 @ISA = qw(ExtUtils::CBuilder::Base);
18 The compiler-specific packages implement functions for generating properly
19 formatted commandlines for the compiler being used. Each package
20 defines two primary functions 'format_linker_cmd()' &
21 'format_compiler_cmd()' that accepts a list of named arguments (a
22 hash) and returns a list of formatted options suitable for invoking the
23 compiler. By default, if the compiler supports scripting of its
24 operation then a script file is built containing the options while
25 those options are removed from the commandline, and a reference to the
26 script is pushed onto the commandline in their place. Scripting the
27 compiler in this way helps to avoid the problems associated with long
28 commandlines under some shells.
36 my $self = $class->SUPER::new(@_);
37 my $cf = $self->{config};
39 # Inherit from an appropriate compiler driver class
40 my $driver = "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type;
41 eval "require $driver" or die "Could not load compiler driver: $@";
42 unshift @ISA, $driver;
49 my $cc = $self->{config}{cc};
51 return ( $cc =~ /cl(\.exe)?$/ ? 'MSVC'
52 : $cc =~ /bcc32(\.exe)?$/ ? 'BCC'
56 sub split_like_shell {
57 # Since Windows will pass the whole command string (not an argument
58 # array) to the target program and make the program parse it itself,
59 # we don't actually need to do any processing here.
60 (my $self, local $_) = @_;
62 return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY');
63 return unless defined() && length();
72 map {$a=$_;$a=~s/\t/ /g;$a=~s/^\s+|\s+$//;$a}
74 return $self->SUPER::do_system($cmd);
78 my ($self, %args) = @_;
79 s/"/\\"/g foreach values %args;
80 return map qq{"-D$_=$args{$_}"}, keys %args;
84 my ($self, %args) = @_;
85 my $cf = $self->{config};
87 die "Missing 'source' argument to compile()" unless defined $args{source};
89 my ($basename, $srcdir) =
90 ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1];
92 $srcdir ||= File::Spec->curdir();
94 my @defines = $self->arg_defines( %{ $args{defines} || {} } );
99 basename => $basename,
100 source => $args{source},
101 output => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext},
104 $self->split_like_shell($cf->{ccflags}),
105 $self->split_like_shell($cf->{cccdlflags}),
106 $self->split_like_shell($args{extra_compiler_flags}),
108 optimize => [ $self->split_like_shell($cf->{optimize}) ],
109 defines => \@defines,
110 includes => [ @{$args{include_dirs} || []} ],
113 $self->split_like_shell($cf->{incpath}),
115 use_scripts => 1, # XXX provide user option to change this???
118 $self->normalize_filespecs(
125 my @cmds = $self->format_compiler_cmd(%spec);
126 while ( my $cmd = shift @cmds ) {
127 $self->do_system( @$cmd )
128 or die "error building $cf->{dlext} file from '$args{source}'";
131 (my $out = $spec{output}) =~ tr/'"//d;
135 sub need_prelink { 1 }
138 my ($self, %args) = @_;
139 my $cf = $self->{config};
141 my @objects = ( ref $args{objects} eq 'ARRAY' ? @{$args{objects}} : $args{objects} );
142 my $to = join '', (File::Spec->splitpath($objects[0]))[0,1];
143 $to ||= File::Spec->curdir();
145 (my $file_base = $args{module_name}) =~ s/.*:://;
146 my $output = $args{lib_file} ||
147 File::Spec->catfile($to, "$file_base.$cf->{dlext}");
149 # if running in perl source tree, look for libs there, not installed
150 my $lddlflags = $cf->{lddlflags};
151 my $perl_src = $self->perl_src();
152 $lddlflags =~ s/\Q$cf->{archlibexp}\E[\\\/]CORE/$perl_src/ if $perl_src;
158 objects => \@objects,
162 libperl => $cf->{libperl},
163 perllibs => [ $self->split_like_shell($cf->{perllibs}) ],
164 libpath => [ $self->split_like_shell($cf->{libpth}) ],
165 lddlflags => [ $self->split_like_shell($lddlflags) ],
166 other_ldflags => [ $self->split_like_shell($args{extra_linker_flags} || '') ],
167 use_scripts => 1, # XXX provide user option to change this???
170 unless ( $spec{basename} ) {
171 ($spec{basename} = $args{module_name}) =~ s/.*:://;
174 $spec{srcdir} = File::Spec->canonpath( $spec{srcdir} );
175 $spec{builddir} = File::Spec->canonpath( $spec{builddir} );
177 $spec{output} ||= File::Spec->catfile( $spec{builddir},
178 $spec{basename} . '.'.$cf->{dlext} );
179 $spec{manifest} ||= File::Spec->catfile( $spec{builddir},
180 $spec{basename} . '.'.$cf->{dlext}.'.manifest');
181 $spec{implib} ||= File::Spec->catfile( $spec{builddir},
182 $spec{basename} . $cf->{lib_ext} );
183 $spec{explib} ||= File::Spec->catfile( $spec{builddir},
184 $spec{basename} . '.exp' );
185 if ($cf->{cc} eq 'cl') {
186 $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir},
187 $spec{basename} . '.pdb' );
189 elsif ($cf->{cc} eq 'bcc32') {
190 $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir},
191 $spec{basename} . '.tds' );
193 $spec{def_file} ||= File::Spec->catfile( $spec{srcdir} ,
194 $spec{basename} . '.def' );
195 $spec{base_file} ||= File::Spec->catfile( $spec{srcdir} ,
196 $spec{basename} . '.base' );
198 $self->add_to_cleanup(
200 @{[ @spec{qw(manifest implib explib dbg_file def_file base_file map_file)} ]}
203 foreach my $opt ( qw(output manifest implib explib dbg_file def_file map_file base_file) ) {
204 $self->normalize_filespecs( \$spec{$opt} );
207 foreach my $opt ( qw(libpath startup objects) ) {
208 $self->normalize_filespecs( $spec{$opt} );
211 (my $def_base = $spec{def_file}) =~ tr/'"//d;
212 $def_base =~ s/\.def$//;
213 $self->prelink( dl_name => $args{module_name},
214 dl_file => $def_base,
215 dl_base => $spec{basename} );
217 my @cmds = $self->format_linker_cmd(%spec);
218 while ( my $cmd = shift @cmds ) {
219 $self->do_system( @$cmd );
222 $spec{output} =~ tr/'"//d;
224 ? grep defined, @spec{qw[output manifest implib explib dbg_file def_file map_file base_file]}
228 # canonize & quote paths
229 sub normalize_filespecs {
230 my ($self, @specs) = @_;
231 foreach my $spec ( grep defined, @specs ) {
232 if ( ref $spec eq 'ARRAY') {
233 $self->normalize_filespecs( map {\$_} grep defined, @$spec )
234 } elsif ( ref $spec eq 'SCALAR' ) {
235 $$spec =~ tr/"//d if $$spec;
237 $$spec = '"' . File::Spec->canonpath($$spec) . '"';
238 } elsif ( ref $spec eq '' ) {
239 $spec = '"' . File::Spec->canonpath($spec) . '"';
241 die "Don't know how to normalize " . (ref $spec || $spec) . "\n";
246 # directory of perl's include files
250 my $perl_src = $self->perl_src();
253 File::Spec->catdir($perl_src, "lib", "CORE");
255 File::Spec->catdir($self->{config}{archlibexp},"CORE");
265 ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms
269 This module implements the Windows-specific parts of ExtUtils::CBuilder.
270 Most of the Windows-specific stuff has to do with compiling and
271 linking C code. Currently we support the 3 compilers perl itself
272 supports: MSVC, BCC, and GCC.
274 This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality
275 not implemented here will be implemented there. The interfaces are
276 defined by the L<ExtUtils::CBuilder> documentation.
280 Ken Williams <ken@mathforum.org>
282 Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>.
286 perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3)