Debian lenny version packages
[pkg-perl] / deb-src / libextutils-cbuilder-perl / libextutils-cbuilder-perl-0.23 / 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 use IO::File;
11
12 use vars qw($VERSION @ISA);
13 $VERSION = '0.23';
14 @ISA = qw(ExtUtils::CBuilder::Base);
15
16 sub new {
17   my $class = shift;
18   my $self = $class->SUPER::new(@_);
19   my $cf = $self->{config};
20
21   # Inherit from an appropriate compiler driver class
22   unshift @ISA, "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type;
23
24   return $self;
25 }
26
27 sub _compiler_type {
28   my $self = shift;
29   my $cc = $self->{config}{cc};
30
31   return (  $cc =~ /cl(\.exe)?$/ ? 'MSVC'
32           : $cc =~ /bcc32(\.exe)?$/ ? 'BCC'
33           : 'GCC');
34 }
35
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 $_) = @_;
41   
42   return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY');
43   return unless defined() && length();
44   return ($_);
45 }
46
47 sub do_system {
48   # See above
49   my $self = shift;
50   my $cmd = join(" ",
51                  grep length,
52                  map {$a=$_;$a=~s/\t/ /g;$a=~s/^\s+|\s+$//;$a}
53                  grep defined, @_);
54   return $self->SUPER::do_system($cmd);
55 }
56
57 sub arg_defines {
58   my ($self, %args) = @_;
59   s/"/\\"/g foreach values %args;
60   return map qq{"-D$_=$args{$_}"}, keys %args;
61 }
62
63 sub compile {
64   my ($self, %args) = @_;
65   my $cf = $self->{config};
66
67   die "Missing 'source' argument to compile()" unless defined $args{source};
68
69   my ($basename, $srcdir) =
70     ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1];
71
72   $srcdir ||= File::Spec->curdir();
73
74   my @defines = $self->arg_defines( %{ $args{defines} || {} } );
75
76   my %spec = (
77     srcdir      => $srcdir,
78     builddir    => $srcdir,
79     basename    => $basename,
80     source      => $args{source},
81     output      => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext},
82     cc          => $cf->{cc},
83     cflags      => [
84                      $self->split_like_shell($cf->{ccflags}),
85                      $self->split_like_shell($cf->{cccdlflags}),
86                      $self->split_like_shell($args{extra_compiler_flags}),
87                    ],
88     optimize    => [ $self->split_like_shell($cf->{optimize})    ],
89     defines     => \@defines,
90     includes    => [ @{$args{include_dirs} || []} ],
91     perlinc     => [
92                      $self->perl_inc(),
93                      $self->split_like_shell($cf->{incpath}),
94                    ],
95     use_scripts => 1, # XXX provide user option to change this???
96   );
97
98   $self->normalize_filespecs(
99     \$spec{source},
100     \$spec{output},
101      $spec{includes},
102      $spec{perlinc},
103   );
104
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}'";
109   }
110
111   (my $out = $spec{output}) =~ tr/'"//d;
112   return $out;
113 }
114
115 sub need_prelink { 1 }
116
117 sub link {
118   my ($self, %args) = @_;
119   my $cf = $self->{config};
120
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();
124
125   (my $file_base = $args{module_name}) =~ s/.*:://;
126   my $output = $args{lib_file} ||
127     File::Spec->catfile($to, "$file_base.$cf->{dlext}");
128
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;
133
134   my %spec = (
135     srcdir        => $to,
136     builddir      => $to,
137     startup       => [ ],
138     objects       => \@objects,
139     libs          => [ ],
140     output        => $output,
141     ld            => $cf->{ld},
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???
148   );
149
150   unless ( $spec{basename} ) {
151     ($spec{basename} = $args{module_name}) =~ s/.*:://;
152   }
153
154   $spec{srcdir}   = File::Spec->canonpath( $spec{srcdir}   );
155   $spec{builddir} = File::Spec->canonpath( $spec{builddir} );
156
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'  );
168   }
169   elsif ($cf->{cc} eq 'bcc32') {
170     $spec{dbg_file}  ||= File::Spec->catfile( $spec{builddir},
171                                             $spec{basename}  . '.tds'  );
172   }
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' );
177
178   $self->add_to_cleanup(
179     grep defined,
180     @{[ @spec{qw(manifest implib explib dbg_file def_file base_file map_file)} ]}
181   );
182
183   foreach my $opt ( qw(output manifest implib explib dbg_file def_file map_file base_file) ) {
184     $self->normalize_filespecs( \$spec{$opt} );
185   }
186
187   foreach my $opt ( qw(libpath startup objects) ) {
188     $self->normalize_filespecs( $spec{$opt} );
189   }
190
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} );
196
197   my @cmds = $self->format_linker_cmd(%spec);
198   while ( my $cmd = shift @cmds ) {
199     $self->do_system( @$cmd );
200   }
201
202   $spec{output} =~ tr/'"//d;
203   return wantarray
204     ? grep defined, @spec{qw[output manifest implib explib dbg_file def_file map_file base_file]}
205     : $spec{output};
206 }
207
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;
216       next unless $$spec;
217       $$spec = '"' . File::Spec->canonpath($$spec) . '"';
218     } elsif ( ref $spec eq '' ) {
219       $spec = '"' . File::Spec->canonpath($spec) . '"';
220     } else {
221       die "Don't know how to normalize " . (ref $spec || $spec) . "\n";
222     }
223   }
224 }
225
226 # directory of perl's include files
227 sub perl_inc {
228   my $self = shift;
229
230   my $perl_src = $self->perl_src();
231
232   if ($perl_src) {
233     File::Spec->catdir($perl_src, "lib", "CORE");
234   } else {
235     File::Spec->catdir($self->{config}{archlibexp},"CORE");
236   }
237 }
238
239 1;
240
241 ########################################################################
242
243 =begin comment
244
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.
256
257 =end comment
258
259 =cut
260
261 ########################################################################
262 package ExtUtils::CBuilder::Platform::Windows::MSVC;
263
264 sub format_compiler_cmd {
265   my ($self, %spec) = @_;
266
267   foreach my $path ( @{ $spec{includes} || [] },
268                      @{ $spec{perlinc}  || [] } ) {
269     $path = '-I' . $path;
270   }
271
272   %spec = $self->write_compiler_script(%spec)
273     if $spec{use_scripts};
274
275   return [ grep {defined && length} (
276     $spec{cc},'-nologo','-c',
277     @{$spec{includes}}      ,
278     @{$spec{cflags}}        ,
279     @{$spec{optimize}}      ,
280     @{$spec{defines}}       ,
281     @{$spec{perlinc}}       ,
282     "-Fo$spec{output}"      ,
283     $spec{source}           ,
284   ) ];
285 }
286
287 sub write_compiler_script {
288   my ($self, %spec) = @_;
289
290   my $script = File::Spec->catfile( $spec{srcdir},
291                                     $spec{basename} . '.ccs' );
292
293   $self->add_to_cleanup($script);
294   print "Generating script '$script'\n" if !$self->{quiet};
295
296   my $SCRIPT = IO::File->new( ">$script" )
297     or die( "Could not create script '$script': $!" );
298
299   print $SCRIPT join( "\n",
300     map { ref $_ ? @{$_} : $_ }
301     grep defined,
302     delete(
303       @spec{ qw(includes cflags optimize defines perlinc) } )
304   );
305
306   push @{$spec{includes}}, '@"' . $script . '"';
307
308   return %spec;
309 }
310
311 sub format_linker_cmd {
312   my ($self, %spec) = @_;
313   my $cf = $self->{config};
314
315   foreach my $path ( @{$spec{libpath}} ) {
316     $path = "-libpath:$path";
317   }
318
319   my $output = $spec{output};
320
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};
326
327   %spec = $self->write_linker_script(%spec)
328     if $spec{use_scripts};
329
330   my @cmds; # Stores the series of commands needed to build the module.
331
332   push @cmds, [ grep {defined && length} (
333     $spec{ld}               ,
334     @{$spec{lddlflags}}     ,
335     @{$spec{libpath}}       ,
336     @{$spec{other_ldflags}} ,
337     @{$spec{startup}}       ,
338     @{$spec{objects}}       ,
339     $spec{map_file}         ,
340     $spec{libperl}          ,
341     @{$spec{perllibs}}      ,
342     $spec{def_file}         ,
343     $spec{implib}           ,
344     $spec{output}           ,
345   ) ];
346
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) {
349     push @cmds, [
350       'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2"
351     ];
352   }
353
354   return @cmds;
355 }
356
357 sub write_linker_script {
358   my ($self, %spec) = @_;
359
360   my $script = File::Spec->catfile( $spec{srcdir},
361                                     $spec{basename} . '.lds' );
362
363   $self->add_to_cleanup($script);
364
365   print "Generating script '$script'\n" if !$self->{quiet};
366
367   my $SCRIPT = IO::File->new( ">$script" )
368     or die( "Could not create script '$script': $!" );
369
370   print $SCRIPT join( "\n",
371     map { ref $_ ? @{$_} : $_ }
372     grep defined,
373     delete(
374       @spec{ qw(lddlflags libpath other_ldflags
375                 startup objects libperl perllibs
376                 def_file implib map_file)            } )
377   );
378
379   push @{$spec{lddlflags}}, '@"' . $script . '"';
380
381   return %spec;
382 }
383
384 1;
385
386 ########################################################################
387 package ExtUtils::CBuilder::Platform::Windows::BCC;
388
389 sub format_compiler_cmd {
390   my ($self, %spec) = @_;
391
392   foreach my $path ( @{ $spec{includes} || [] },
393                      @{ $spec{perlinc}  || [] } ) {
394     $path = '-I' . $path;
395   }
396
397   %spec = $self->write_compiler_script(%spec)
398     if $spec{use_scripts};
399
400   return [ grep {defined && length} (
401     $spec{cc}, '-c'         ,
402     @{$spec{includes}}      ,
403     @{$spec{cflags}}        ,
404     @{$spec{optimize}}      ,
405     @{$spec{defines}}       ,
406     @{$spec{perlinc}}       ,
407     "-o$spec{output}"       ,
408     $spec{source}           ,
409   ) ];
410 }
411
412 sub write_compiler_script {
413   my ($self, %spec) = @_;
414
415   my $script = File::Spec->catfile( $spec{srcdir},
416                                     $spec{basename} . '.ccs' );
417
418   $self->add_to_cleanup($script);
419
420   print "Generating script '$script'\n" if !$self->{quiet};
421
422   my $SCRIPT = IO::File->new( ">$script" )
423     or die( "Could not create script '$script': $!" );
424
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 $_ ? @{$_} : $_ }
432     grep defined,
433     delete(
434       @spec{ qw(includes cflags optimize perlinc) } )
435   );
436
437   push @{$spec{includes}}, '@"' . $script . '"';
438
439   return %spec;
440 }
441
442 sub format_linker_cmd {
443   my ($self, %spec) = @_;
444
445   foreach my $path ( @{$spec{libpath}} ) {
446     $path = "-L$path";
447   }
448
449   push( @{$spec{startup}}, 'c0d32.obj' )
450     unless ( $spec{starup} && @{$spec{startup}} );
451
452   %spec = $self->write_linker_script(%spec)
453     if $spec{use_scripts};
454
455   return [ grep {defined && length} (
456     $spec{ld}               ,
457     @{$spec{lddlflags}}     ,
458     @{$spec{libpath}}       ,
459     @{$spec{other_ldflags}} ,
460     @{$spec{startup}}       ,
461     @{$spec{objects}}       , ',',
462     $spec{output}           , ',',
463     $spec{map_file}         , ',',
464     $spec{libperl}          ,
465     @{$spec{perllibs}}      , ',',
466     $spec{def_file}
467   ) ];
468 }
469
470 sub write_linker_script {
471   my ($self, %spec) = @_;
472
473   # To work around Borlands "unique" commandline syntax,
474   # two scripts are used:
475
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' );
480
481   $self->add_to_cleanup($ld_script, $ld_libs);
482
483   print "Generating scripts '$ld_script' and '$ld_libs'.\n" if !$self->{quiet};
484
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': $!" );
488
489   print $LD_SCRIPT join( " +\n",
490     map { @{$_} }
491     grep defined,
492     delete(
493       @spec{ qw(lddlflags libpath other_ldflags startup objects) } )
494   );
495
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': $!" );
499
500   print $LD_LIBS join( " +\n",
501      (delete $spec{libperl}  || ''),
502     @{delete $spec{perllibs} || []},
503   );
504
505   push @{$spec{lddlflags}}, '@"' . $ld_script  . '"';
506   push @{$spec{perllibs}},  '@"' . $ld_libs    . '"';
507
508   return %spec;
509 }
510
511 1;
512
513 ########################################################################
514 package ExtUtils::CBuilder::Platform::Windows::GCC;
515
516 sub format_compiler_cmd {
517   my ($self, %spec) = @_;
518
519   foreach my $path ( @{ $spec{includes} || [] },
520                      @{ $spec{perlinc}  || [] } ) {
521     $path = '-I' . $path;
522   }
523
524   # split off any -arguments included in cc
525   my @cc = split / (?=-)/, $spec{cc};
526
527   return [ grep {defined && length} (
528     @cc, '-c'               ,
529     @{$spec{includes}}      ,
530     @{$spec{cflags}}        ,
531     @{$spec{optimize}}      ,
532     @{$spec{defines}}       ,
533     @{$spec{perlinc}}       ,
534     '-o', $spec{output}     ,
535     $spec{source}           ,
536   ) ];
537 }
538
539 sub format_linker_cmd {
540   my ($self, %spec) = @_;
541
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/;
546
547   unshift( @{$spec{other_ldflags}}, '-nostartfiles' )
548     if ( $spec{startup} && @{$spec{startup}} );
549
550   # From ExtUtils::MM_Win32:
551   #
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) );
558
559   %spec = $self->write_linker_script(%spec)
560     if $spec{use_scripts};
561
562   foreach my $path ( @{$spec{libpath}} ) {
563     $path = "-L$path";
564   }
565
566   my @cmds; # Stores the series of commands needed to build the module.
567
568   push @cmds, [
569     'dlltool', '--def'        , $spec{def_file},
570                '--output-exp' , $spec{explib}
571   ];
572
573   # split off any -arguments included in ld
574   my @ld = split / (?=-)/, $spec{ld};
575
576   push @cmds, [ grep {defined && length} (
577     @ld                       ,
578     '-o', $spec{output}       ,
579     "-Wl,--base-file,$spec{base_file}"   ,
580     "-Wl,--image-base,$spec{image_base}" ,
581     @{$spec{lddlflags}}       ,
582     @{$spec{libpath}}         ,
583     @{$spec{startup}}         ,
584     @{$spec{objects}}         ,
585     @{$spec{other_ldflags}}   ,
586     $spec{libperl}            ,
587     @{$spec{perllibs}}        ,
588     $spec{explib}             ,
589     $spec{map_file} ? ('-Map', $spec{map_file}) : ''
590   ) ];
591
592   push @cmds, [
593     'dlltool', '--def'        , $spec{def_file},
594                '--output-exp' , $spec{explib},
595                '--base-file'  , $spec{base_file}
596   ];
597
598   push @cmds, [ grep {defined && length} (
599     @ld                       ,
600     '-o', $spec{output}       ,
601     "-Wl,--image-base,$spec{image_base}" ,
602     @{$spec{lddlflags}}       ,
603     @{$spec{libpath}}         ,
604     @{$spec{startup}}         ,
605     @{$spec{objects}}         ,
606     @{$spec{other_ldflags}}   ,
607     $spec{libperl}            ,
608     @{$spec{perllibs}}        ,
609     $spec{explib}             ,
610     $spec{map_file} ? ('-Map', $spec{map_file}) : ''
611   ) ];
612
613   return @cmds;
614 }
615
616 sub write_linker_script {
617   my ($self, %spec) = @_;
618
619   my $script = File::Spec->catfile( $spec{srcdir},
620                                     $spec{basename} . '.lds' );
621
622   $self->add_to_cleanup($script);
623
624   print "Generating script '$script'\n" if !$self->{quiet};
625
626   my $SCRIPT = IO::File->new( ">$script" )
627     or die( "Could not create script '$script': $!" );
628
629   print $SCRIPT ( 'SEARCH_DIR(' . $_ . ")\n" )
630     for @{delete $spec{libpath} || []};
631
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} || []};
639   }
640
641   print $SCRIPT 'INPUT(' . join( ',',
642     @{delete $spec{objects}  || []}
643   ) . ")\n";
644
645   print $SCRIPT 'INPUT(' . join( ' ',
646      (delete $spec{libperl}  || ''),
647     @{delete $spec{perllibs} || []},
648   ) . ")\n";
649
650   push @{$spec{other_ldflags}}, '"' . $script . '"';
651
652   return %spec;
653 }
654
655 1;
656
657 __END__
658
659 =head1 NAME
660
661 ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms
662
663 =head1 DESCRIPTION
664
665 This module implements the Windows-specific parts of ExtUtils::CBuilder.
666 Most of the Windows-specific stuff has to do with compiling and
667 linking C code.  Currently we support the 3 compilers perl itself
668 supports: MSVC, BCC, and GCC.
669
670 This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality
671 not implemented here will be implemented there.  The interfaces are
672 defined by the L<ExtUtils::CBuilder> documentation.
673
674 =head1 AUTHOR
675
676 Ken Williams <ken@mathforum.org>
677
678 Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>.
679
680 =head1 SEE ALSO
681
682 perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3)
683
684 =cut