1 package Module::Build::Platform::Windows;
10 use Module::Build::Base;
13 @ISA = qw(Module::Build::Base);
16 sub manpage_separator {
20 sub have_multiarg_pipeopen { 0 }
22 sub ACTION_realclean {
25 $self->SUPER::ACTION_realclean();
27 my $basename = basename($0);
28 $basename =~ s/(?:\.bat)?$//i;
30 if ( $basename eq $self->build_script ) {
31 if ( $self->build_bat ) {
32 my $full_progname = $0;
33 $full_progname =~ s/(?:\.bat)?$/.bat/i;
35 # Vodoo required to have a batch file delete itself without error;
36 # Syntax differs between 9x & NT: the later requires a null arg (???)
38 my $null_arg = (Win32::IsWinNT()) ? '""' : '';
39 my $cmd = qq(start $null_arg /min "\%comspec\%" /c del "$full_progname");
41 my $fh = IO::File->new(">> $basename.bat")
42 or die "Can't create $basename.bat: $!";
46 $self->delete_filetree($self->build_script . '.bat');
54 $self->SUPER::make_executable(@_);
56 foreach my $script (@_) {
58 if ( $script eq $self->build_script ) {
59 $opts{ntargs} = q(-x -S %0 --build_bat %*);
60 $opts{otherargs} = q(-x -S "%0" --build_bat %1 %2 %3 %4 %5 %6 %7 %8 %9);
63 my $out = eval {$self->pl2bat(in => $script, update => 1, %opts)};
65 $self->log_warn("WARNING: Unable to convert file '$script' to an executable script:\n$@");
67 $self->SUPER::make_executable($out);
72 # This routine was copied almost verbatim from the 'pl2bat' utility
73 # distributed with perl. It requires too much vodoo with shell quoting
74 # differences and shortcomings between the various flavors of Windows
75 # to reliably shell out
80 # NOTE: %0 is already enclosed in doublequotes by cmd.exe, as appropriate
81 $opts{ntargs} = '-x -S %0 %*' unless exists $opts{ntargs};
82 $opts{otherargs} = '-x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9' unless exists $opts{otherargs};
84 $opts{stripsuffix} = '/\\.plx?/' unless exists $opts{stripsuffix};
85 $opts{stripsuffix} = ($opts{stripsuffix} =~ m{^/([^/]*[^/\$]|)\$?/?$} ? $1 : "\Q$opts{stripsuffix}\E");
87 unless (exists $opts{out}) {
88 $opts{out} = $opts{in};
89 $opts{out} =~ s/$opts{stripsuffix}$//oi;
90 $opts{out} .= '.bat' unless $opts{in} =~ /\.bat$/i or $opts{in} =~ /^-$/;
96 if "%OS%" == "Windows_NT" goto WinNT
101 if NOT "%COMSPEC%" == "%SystemRoot%\\system32\\cmd.exe" goto endofperl
102 if %errorlevel% == 9009 echo You do not have Perl in your PATH.
103 if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul
109 my $headlines = 2 + ($head =~ tr/\n/\n/);
110 my $tail = "\n__END__\n:endofperl\n";
117 my $start = $Config{startperl};
118 $start = "#!perl" unless $start =~ /^#!.*perl/;
120 my $in = IO::File->new("< $opts{in}") or die "Can't open $opts{in}: $!";
124 foreach my $line ( @file ) {
126 if ( $line =~ /^:endofperl\b/ ) {
127 if (!exists $opts{update}) {
128 warn "$opts{in} has already been converted to a batch file!\n";
133 if ( not $linedone and $line =~ /^#!.*perl/ ) {
134 if (exists $opts{update}) {
135 $skiplines = $linenum - 1;
136 $line .= "#line ".(1+$headlines)."\n";
138 $line .= "#line ".($linenum+$headlines)."\n";
142 if ( $line =~ /^#\s*line\b/ and $linenum == 2 + $skiplines ) {
147 my $out = IO::File->new("> $opts{out}") or die "Can't open $opts{out}: $!";
149 print $out $start, ( $opts{usewarnings} ? " -w" : "" ),
150 "\n#line ", ($headlines+1), "\n" unless $linedone;
151 print $out @file[$skiplines..$#file];
152 print $out $tail unless $taildone;
159 sub split_like_shell {
160 # As it turns out, Windows command-parsing is very different from
161 # Unix command-parsing. Double-quotes mean different things,
162 # backslashes don't necessarily mean escapes, and so on. So we
163 # can't use Text::ParseWords::shellwords() to break a command string
164 # into words. The algorithm below was bashed out by Randy and Ken
165 # (mostly Randy), and there are a lot of regression tests, so we
166 # should feel free to adjust if desired.
168 (my $self, local $_) = @_;
170 return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY');
173 return @argv unless defined() && length();
176 my( $i, $quote_mode ) = ( 0, 0 );
178 while ( $i < length() ) {
180 my $ch = substr( $_, $i , 1 );
181 my $next_ch = substr( $_, $i+1, 1 );
183 if ( $ch eq '\\' && $next_ch eq '"' ) {
186 } elsif ( $ch eq '\\' && $next_ch eq '\\' ) {
189 } elsif ( $ch eq '"' && $next_ch eq '"' && $quote_mode ) {
190 $quote_mode = !$quote_mode;
193 } elsif ( $ch eq '"' && $next_ch eq '"' && !$quote_mode &&
194 ( $i + 2 == length() ||
195 substr( $_, $i + 2, 1 ) eq ' ' )
196 ) { # for cases like: a"" => [ 'a' ]
200 } elsif ( $ch eq '"' ) {
201 $quote_mode = !$quote_mode;
202 } elsif ( $ch eq ' ' && !$quote_mode ) {
203 push( @argv, $arg ) if $arg;
205 ++$i while substr( $_, $i + 1, 1 ) eq ' ';
213 push( @argv, $arg ) if defined( $arg ) && length( $arg );
223 Module::Build::Platform::Windows - Builder class for Windows platforms
227 The sole purpose of this module is to inherit from
228 C<Module::Build::Base> and override a few methods. Please see
229 L<Module::Build> for the docs.
233 Ken Williams <ken@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
237 perl(1), Module::Build(3)