From: Tony Cook Date: Sun, 23 Oct 2011 00:34:55 +0000 (+1100) Subject: improve MSVC support some more X-Git-Tag: v0.85_02~4 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/ae394c13e01e5d0d583ea1dd701e2c913e962b4d improve MSVC support some more --- diff --git a/Changes b/Changes index b93fcf66..1d0f45d1 100644 --- a/Changes +++ b/Changes @@ -66,6 +66,8 @@ Bug fixes: prefixed names on Win32. https://rt.cpan.org/Ticket/Display.html?id=71642 + - fix library detection with MSVC + Imager 0.85_01 - 10 Oct 2011 ============== diff --git a/FT2/inc/Devel/CheckLib.pm b/FT2/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/FT2/inc/Devel/CheckLib.pm +++ b/FT2/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/GIF/inc/Devel/CheckLib.pm b/GIF/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/GIF/inc/Devel/CheckLib.pm +++ b/GIF/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/JPEG/inc/Devel/CheckLib.pm b/JPEG/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/JPEG/inc/Devel/CheckLib.pm +++ b/JPEG/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/PNG/inc/Devel/CheckLib.pm b/PNG/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/PNG/inc/Devel/CheckLib.pm +++ b/PNG/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/T1/inc/Devel/CheckLib.pm b/T1/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/T1/inc/Devel/CheckLib.pm +++ b/T1/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/TIFF/inc/Devel/CheckLib.pm b/TIFF/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/TIFF/inc/Devel/CheckLib.pm +++ b/TIFF/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/W32/inc/Devel/CheckLib.pm b/W32/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/W32/inc/Devel/CheckLib.pm +++ b/W32/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/inc/Devel/CheckLib.pm b/inc/Devel/CheckLib.pm index 531a6239..c396ee4f 100644 --- a/inc/Devel/CheckLib.pm +++ b/inc/Devel/CheckLib.pm @@ -245,13 +245,13 @@ sub assert_lib { } } if(defined($args{INC})) { - foreach my $arg (split(' ', $args{INC})) { + foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } - my @cc = _findcc(); + my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; @@ -271,21 +271,25 @@ sub assert_lib { if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( - @cc, + @$cc, $cfile, "/Fe$exefile", - (map { '/I'.Win32::GetShortPathName($_) } @incpaths) + (map { '/I'.Win32::GetShortPathName($_) } @incpaths), + "/link", + @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, (map { "-I$_" } @incpaths), "-o$exefile", - $cfile + $cfile, + @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" @@ -317,18 +321,20 @@ sub assert_lib { } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( - @cc, + @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", + @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( - @cc, + @$cc, + @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), @@ -337,7 +343,8 @@ sub assert_lib { } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( - @cc, + @$cc, + @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), @@ -368,23 +375,55 @@ sub _cleanup_exe { unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; + if ( $Config{cc} eq 'cl' ) { + # MSVC also creates foo.ilk and foo.pdb + my $ilkfile = $exefile; + $ilkfile =~ s/$Config{_exe}$/.ilk/; + my $pdbfile = $exefile; + $pdbfile =~ s/$Config{_exe}$/.pdb/; + unlink $ilkfile if -f $ilkfile; + unlink $pdbfile if -f $pdbfile; + } return } - + +# return ($cc, $ld) +# where $cc is an array ref of compiler name, compiler flags +# where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes - my @Config_ccflags_ldflags = @Config{qw(ccflags ldflags)}; # use copy so ASPerl will compile - my @flags = grep { length } map { quotewords('\s+', 1, $_ || ()) } @Config_ccflags_ldflags; + my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile + my @Config_ldflags = @Config{qw(ldflags perllibs)}; + my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); + my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); - return (@cc, @flags) if -x $cc[0]; + return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; - return ($compiler, @cc[1 .. $#cc], @flags) if -x $compiler; + return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) + if -x $compiler; } die("Couldn't find your C compiler\n"); } +sub _shellwords { + my $line = shift; + + if ($^O eq "MSWin32") { + my @elements; + $line =~ s/^\s+//; + while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { + push @elements, $1; + $line =~ s/^\s+//; + } + return @elements; + } + else { + return quotewords('\s+', 0, shift); + } +} + # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; diff --git a/lib/Imager/Probe.pm b/lib/Imager/Probe.pm index e8db68e1..611c1823 100644 --- a/lib/Imager/Probe.pm +++ b/lib/Imager/Probe.pm @@ -130,6 +130,38 @@ sub _probe_pkg { return; } +sub _is_msvc { + return $Config{cc} eq "cl"; +} + +sub _lib_basename { + my ($base) = @_; + + if (_is_msvc()) { + return $base; + } + else { + return "lib$base"; + } +} + +sub _lib_option { + my ($base) = @_; + + if (_is_msvc()) { + return $base . $Config{_a}; + } + else { + return "-l$base"; + } +} + +sub _quotearg { + my ($opt) = @_; + + return $opt =~ /\s/ ? qq("$opt") : $opt; +} + sub _probe_check { my ($req) = @_; @@ -139,9 +171,10 @@ sub _probe_check { # synthesize a libcheck my $lext=$Config{'so'}; # Get extensions of libraries my $aext=$Config{'_a'}; + my $basename = _lib_basename($libbase); $libcheck = sub { - -e File::Spec->catfile($_[0], "lib$libbase$aext") - || -e File::Spec->catfile($_[0], "lib$libbase.$lext") + -e File::Spec->catfile($_[0], "$basename$aext") + || -e File::Spec->catfile($_[0], "$basename.$lext") }; } @@ -187,7 +220,7 @@ sub _probe_check { push @libs, $req->{libopts}; } elsif ($libbase) { - push @libs, "-l$libbase"; + push @libs, _lib_option($libbase); } else { die "$req->{altname}: inccheck but no libbase or libopts"; @@ -195,8 +228,8 @@ sub _probe_check { return { - INC => "-I$found_incpath", - LIBS => "@libs", + INC => _quotearg("-I$found_incpath"), + LIBS => join(" ", map _quotearg($_), @libs), DEFINE => "", }; }