|
0 |
# $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $
|
|
1 |
|
|
2 |
package #
|
|
3 |
Devel::CheckLib;
|
|
4 |
|
|
5 |
use 5.00405; #postfix foreach
|
|
6 |
use strict;
|
|
7 |
use vars qw($VERSION @ISA @EXPORT);
|
|
8 |
$VERSION = '1.11';
|
|
9 |
use Config qw(%Config);
|
|
10 |
use Text::ParseWords 'quotewords';
|
|
11 |
|
|
12 |
use File::Spec;
|
|
13 |
use File::Temp;
|
|
14 |
use File::Path;
|
|
15 |
|
|
16 |
require Exporter;
|
|
17 |
@ISA = qw(Exporter);
|
|
18 |
@EXPORT = qw(assert_lib check_lib_or_exit check_lib);
|
|
19 |
|
|
20 |
# localising prevents the warningness leaking out of this module
|
|
21 |
local $^W = 1; # use warnings is a 5.6-ism
|
|
22 |
|
|
23 |
_findcc(); # bomb out early if there's no compiler
|
|
24 |
|
|
25 |
=head1 NAME
|
|
26 |
|
|
27 |
Devel::CheckLib - check that a library is available
|
|
28 |
|
|
29 |
=head1 DESCRIPTION
|
|
30 |
|
|
31 |
Devel::CheckLib is a perl module that checks whether a particular C
|
|
32 |
library and its headers are available.
|
|
33 |
|
|
34 |
=head1 SYNOPSIS
|
|
35 |
|
|
36 |
use Devel::CheckLib;
|
|
37 |
|
|
38 |
check_lib_or_exit( lib => 'jpeg', header => 'jpeglib.h' );
|
|
39 |
check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] );
|
|
40 |
|
|
41 |
# or prompt for path to library and then do this:
|
|
42 |
check_lib_or_exit( lib => 'jpeg', libpath => $additional_path );
|
|
43 |
|
|
44 |
=head1 USING IT IN Makefile.PL or Build.PL
|
|
45 |
|
|
46 |
If you want to use this from Makefile.PL or Build.PL, do
|
|
47 |
not simply copy the module into your distribution as this may cause
|
|
48 |
problems when PAUSE and search.cpan.org index the distro. Instead, use
|
|
49 |
the use-devel-checklib script.
|
|
50 |
|
|
51 |
=head1 HOW IT WORKS
|
|
52 |
|
|
53 |
You pass named parameters to a function, describing to it how to build
|
|
54 |
and link to the libraries.
|
|
55 |
|
|
56 |
It works by trying to compile some code - which defaults to this:
|
|
57 |
|
|
58 |
int main(int argc, char *argv[]) { return 0; }
|
|
59 |
|
|
60 |
and linking it to the specified libraries. If something pops out the end
|
|
61 |
which looks executable, it gets executed, and if main() returns 0 we know
|
|
62 |
that it worked. That tiny program is
|
|
63 |
built once for each library that you specify, and (without linking) once
|
|
64 |
for each header file.
|
|
65 |
|
|
66 |
If you want to check for the presence of particular functions in a
|
|
67 |
library, or even that those functions return particular results, then
|
|
68 |
you can pass your own function body for main() thus:
|
|
69 |
|
|
70 |
check_lib_or_exit(
|
|
71 |
function => 'foo();if(libversion() > 5) return 0; else return 1;'
|
|
72 |
incpath => ...
|
|
73 |
libpath => ...
|
|
74 |
lib => ...
|
|
75 |
header => ...
|
|
76 |
);
|
|
77 |
|
|
78 |
In that case, it will fail to build if either foo() or libversion() don't
|
|
79 |
exist, and main() will return the wrong value if libversion()'s return
|
|
80 |
value isn't what you want.
|
|
81 |
|
|
82 |
=head1 FUNCTIONS
|
|
83 |
|
|
84 |
All of these take the same named parameters and are exported by default.
|
|
85 |
To avoid exporting them, C<use Devel::CheckLib ()>.
|
|
86 |
|
|
87 |
=head2 assert_lib
|
|
88 |
|
|
89 |
This takes several named parameters, all of which are optional, and dies
|
|
90 |
with an error message if any of the libraries listed can
|
|
91 |
not be found. B<Note>: dying in a Makefile.PL or Build.PL may provoke
|
|
92 |
a 'FAIL' report from CPAN Testers' automated smoke testers. Use
|
|
93 |
C<check_lib_or_exit> instead.
|
|
94 |
|
|
95 |
The named parameters are:
|
|
96 |
|
|
97 |
=over
|
|
98 |
|
|
99 |
=item lib
|
|
100 |
|
|
101 |
Must be either a string with the name of a single
|
|
102 |
library or a reference to an array of strings of library names. Depending
|
|
103 |
on the compiler found, library names will be fed to the compiler either as
|
|
104 |
C<-l> arguments or as C<.lib> file names. (E.g. C<-ljpeg> or C<jpeg.lib>)
|
|
105 |
|
|
106 |
=item libpath
|
|
107 |
|
|
108 |
a string or an array of strings
|
|
109 |
representing additional paths to search for libraries.
|
|
110 |
|
|
111 |
=item LIBS
|
|
112 |
|
|
113 |
a C<ExtUtils::MakeMaker>-style space-separated list of
|
|
114 |
libraries (each preceded by '-l') and directories (preceded by '-L').
|
|
115 |
|
|
116 |
This can also be supplied on the command-line.
|
|
117 |
|
|
118 |
=item debug
|
|
119 |
|
|
120 |
If true - emit information during processing that can be used for
|
|
121 |
debugging.
|
|
122 |
|
|
123 |
=back
|
|
124 |
|
|
125 |
And libraries are no use without header files, so ...
|
|
126 |
|
|
127 |
=over
|
|
128 |
|
|
129 |
=item header
|
|
130 |
|
|
131 |
Must be either a string with the name of a single
|
|
132 |
header file or a reference to an array of strings of header file names.
|
|
133 |
|
|
134 |
=item incpath
|
|
135 |
|
|
136 |
a string or an array of strings
|
|
137 |
representing additional paths to search for headers.
|
|
138 |
|
|
139 |
=item INC
|
|
140 |
|
|
141 |
a C<ExtUtils::MakeMaker>-style space-separated list of
|
|
142 |
incpaths, each preceded by '-I'.
|
|
143 |
|
|
144 |
This can also be supplied on the command-line.
|
|
145 |
|
|
146 |
=item ccflags
|
|
147 |
|
|
148 |
Extra flags to pass to the compiler.
|
|
149 |
|
|
150 |
=item ldflags
|
|
151 |
|
|
152 |
Extra flags to pass to the linker.
|
|
153 |
|
|
154 |
=item analyze_binary
|
|
155 |
|
|
156 |
a callback function that will be invoked in order to perform custom
|
|
157 |
analysis of the generated binary. The callback arguments are the
|
|
158 |
library name and the path to the binary just compiled.
|
|
159 |
|
|
160 |
It is possible to use this callback, for instance, to inspect the
|
|
161 |
binary for further dependencies.
|
|
162 |
|
|
163 |
=back
|
|
164 |
|
|
165 |
=head2 check_lib_or_exit
|
|
166 |
|
|
167 |
This behaves exactly the same as C<assert_lib()> except that instead of
|
|
168 |
dieing, it warns (with exactly the same error message) and exits.
|
|
169 |
This is intended for use in Makefile.PL / Build.PL
|
|
170 |
when you might want to prompt the user for various paths and
|
|
171 |
things before checking that what they've told you is sane.
|
|
172 |
|
|
173 |
If any library or header is missing, it exits with an exit value of 0 to avoid
|
|
174 |
causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this
|
|
175 |
result -- which is what you want if an external library dependency is not
|
|
176 |
available.
|
|
177 |
|
|
178 |
=head2 check_lib
|
|
179 |
|
|
180 |
This behaves exactly the same as C<assert_lib()> except that it is silent,
|
|
181 |
returning false instead of dieing, or true otherwise.
|
|
182 |
|
|
183 |
=cut
|
|
184 |
|
|
185 |
sub check_lib_or_exit {
|
|
186 |
eval 'assert_lib(@_)';
|
|
187 |
if($@) {
|
|
188 |
warn $@;
|
|
189 |
exit;
|
|
190 |
}
|
|
191 |
}
|
|
192 |
|
|
193 |
sub check_lib {
|
|
194 |
eval 'assert_lib(@_)';
|
|
195 |
return $@ ? 0 : 1;
|
|
196 |
}
|
|
197 |
|
|
198 |
# borrowed from Text::ParseWords
|
|
199 |
sub _parse_line {
|
|
200 |
my($delimiter, $keep, $line) = @_;
|
|
201 |
my($word, @pieces);
|
|
202 |
|
|
203 |
no warnings 'uninitialized'; # we will be testing undef strings
|
|
204 |
|
|
205 |
while (length($line)) {
|
|
206 |
# This pattern is optimised to be stack conservative on older perls.
|
|
207 |
# Do not refactor without being careful and testing it on very long strings.
|
|
208 |
# See Perl bug #42980 for an example of a stack busting input.
|
|
209 |
$line =~ s/^
|
|
210 |
(?:
|
|
211 |
# double quoted string
|
|
212 |
(") # $quote
|
|
213 |
((?>[^\\"]*(?:\\.[^\\"]*)*))" # $quoted
|
|
214 |
| # --OR--
|
|
215 |
# singe quoted string
|
|
216 |
(') # $quote
|
|
217 |
((?>[^\\']*(?:\\.[^\\']*)*))' # $quoted
|
|
218 |
| # --OR--
|
|
219 |
# unquoted string
|
|
220 |
( # $unquoted
|
|
221 |
(?:\\.|[^\\"'])*?
|
|
222 |
)
|
|
223 |
# followed by
|
|
224 |
( # $delim
|
|
225 |
\Z(?!\n) # EOL
|
|
226 |
| # --OR--
|
|
227 |
(?-x:$delimiter) # delimiter
|
|
228 |
| # --OR--
|
|
229 |
(?!^)(?=["']) # a quote
|
|
230 |
)
|
|
231 |
)//xs or return; # extended layout
|
|
232 |
my ($quote, $quoted, $unquoted, $delim) = (($1 ? ($1,$2) : ($3,$4)), $5, $6);
|
|
233 |
|
|
234 |
return() unless( defined($quote) || length($unquoted) || length($delim));
|
|
235 |
|
|
236 |
if ($keep) {
|
|
237 |
$quoted = "$quote$quoted$quote";
|
|
238 |
}
|
|
239 |
else {
|
|
240 |
$unquoted =~ s/\\(.)/$1/sg;
|
|
241 |
if (defined $quote) {
|
|
242 |
$quoted =~ s/\\(.)/$1/sg if ($quote eq '"');
|
|
243 |
}
|
|
244 |
}
|
|
245 |
$word .= substr($line, 0, 0); # leave results tainted
|
|
246 |
$word .= defined $quote ? $quoted : $unquoted;
|
|
247 |
|
|
248 |
if (length($delim)) {
|
|
249 |
push(@pieces, $word);
|
|
250 |
push(@pieces, $delim) if ($keep eq 'delimiters');
|
|
251 |
undef $word;
|
|
252 |
}
|
|
253 |
if (!length($line)) {
|
|
254 |
push(@pieces, $word);
|
|
255 |
}
|
|
256 |
}
|
|
257 |
return(@pieces);
|
|
258 |
}
|
|
259 |
|
|
260 |
sub assert_lib {
|
|
261 |
my %args = @_;
|
|
262 |
my (@libs, @libpaths, @headers, @incpaths);
|
|
263 |
|
|
264 |
# FIXME: these four just SCREAM "refactor" at me
|
|
265 |
@libs = (ref($args{lib}) ? @{$args{lib}} : $args{lib})
|
|
266 |
if $args{lib};
|
|
267 |
@libpaths = (ref($args{libpath}) ? @{$args{libpath}} : $args{libpath})
|
|
268 |
if $args{libpath};
|
|
269 |
@headers = (ref($args{header}) ? @{$args{header}} : $args{header})
|
|
270 |
if $args{header};
|
|
271 |
@incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath})
|
|
272 |
if $args{incpath};
|
|
273 |
my $analyze_binary = $args{analyze_binary};
|
|
274 |
|
|
275 |
my @argv = @ARGV;
|
|
276 |
push @argv, _parse_line('\s+', 0, $ENV{PERL_MM_OPT}||'');
|
|
277 |
|
|
278 |
# work-a-like for Makefile.PL's LIBS and INC arguments
|
|
279 |
# if given as command-line argument, append to %args
|
|
280 |
for my $arg (@argv) {
|
|
281 |
for my $mm_attr_key (qw(LIBS INC)) {
|
|
282 |
if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) {
|
|
283 |
# it is tempting to put some \s* into the expression, but the
|
|
284 |
# MM command-line parser only accepts LIBS etc. followed by =,
|
|
285 |
# so we should not be any more lenient with whitespace than that
|
|
286 |
$args{$mm_attr_key} .= " $mm_attr_value";
|
|
287 |
}
|
|
288 |
}
|
|
289 |
}
|
|
290 |
|
|
291 |
# using special form of split to trim whitespace
|
|
292 |
if(defined($args{LIBS})) {
|
|
293 |
foreach my $arg (split(' ', $args{LIBS})) {
|
|
294 |
die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-[lLR]/);
|
|
295 |
push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2);
|
|
296 |
}
|
|
297 |
}
|
|
298 |
if(defined($args{INC})) {
|
|
299 |
foreach my $arg (split(' ', $args{INC})) {
|
|
300 |
die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/);
|
|
301 |
push @incpaths, substr($arg, 2);
|
|
302 |
}
|
|
303 |
}
|
|
304 |
|
|
305 |
my ($cc, $ld) = _findcc($args{debug}, $args{ccflags}, $args{ldflags});
|
|
306 |
my @missing;
|
|
307 |
my @wrongresult;
|
|
308 |
my @wronganalysis;
|
|
309 |
my @use_headers;
|
|
310 |
|
|
311 |
# first figure out which headers we can't find ...
|
|
312 |
for my $header (@headers) {
|
|
313 |
push @use_headers, $header;
|
|
314 |
my($ch, $cfile) = File::Temp::tempfile(
|
|
315 |
'assertlibXXXXXXXX', SUFFIX => '.c'
|
|
316 |
);
|
|
317 |
my $ofile = $cfile;
|
|
318 |
$ofile =~ s/\.c$/$Config{_o}/;
|
|
319 |
print $ch qq{#include <$_>\n} for @use_headers;
|
|
320 |
print $ch qq{int main(void) { return 0; }\n};
|
|
321 |
close($ch);
|
|
322 |
my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
|
|
323 |
my @sys_cmd;
|
|
324 |
# FIXME: re-factor - almost identical code later when linking
|
|
325 |
if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
|
|
326 |
require Win32;
|
|
327 |
@sys_cmd = (
|
|
328 |
@$cc,
|
|
329 |
$cfile,
|
|
330 |
"/Fe$exefile",
|
|
331 |
(map { '/I'.Win32::GetShortPathName($_) } @incpaths),
|
|
332 |
"/link",
|
|
333 |
@$ld,
|
|
334 |
split(' ', $Config{libs}),
|
|
335 |
);
|
|
336 |
} elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
|
|
337 |
@sys_cmd = (
|
|
338 |
@$cc,
|
|
339 |
@$ld,
|
|
340 |
(map { "-I$_" } @incpaths),
|
|
341 |
"-o$exefile",
|
|
342 |
$cfile
|
|
343 |
);
|
|
344 |
} else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ...
|
|
345 |
@sys_cmd = (
|
|
346 |
@$cc,
|
|
347 |
@$ld,
|
|
348 |
$cfile,
|
|
349 |
(map { "-I$_" } @incpaths),
|
|
350 |
"-o", "$exefile"
|
|
351 |
);
|
|
352 |
}
|
|
353 |
warn "# @sys_cmd\n" if $args{debug};
|
|
354 |
my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
|
|
355 |
push @missing, $header if $rv != 0 || ! -x $exefile;
|
|
356 |
_cleanup_exe($exefile);
|
|
357 |
unlink $cfile;
|
|
358 |
}
|
|
359 |
|
|
360 |
# now do each library in turn with headers
|
|
361 |
my($ch, $cfile) = File::Temp::tempfile(
|
|
362 |
'assertlibXXXXXXXX', SUFFIX => '.c'
|
|
363 |
);
|
|
364 |
my $ofile = $cfile;
|
|
365 |
$ofile =~ s/\.c$/$Config{_o}/;
|
|
366 |
print $ch qq{#include <$_>\n} foreach (@headers);
|
|
367 |
print $ch "int main(int argc, char *argv[]) { ".($args{function} || 'return 0;')." }\n";
|
|
368 |
close($ch);
|
|
369 |
for my $lib ( @libs ) {
|
|
370 |
my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
|
|
371 |
my @sys_cmd;
|
|
372 |
if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
|
|
373 |
require Win32;
|
|
374 |
my @libpath = map {
|
|
375 |
q{/libpath:} . Win32::GetShortPathName($_)
|
|
376 |
} @libpaths;
|
|
377 |
# this is horribly sensitive to the order of arguments
|
|
378 |
@sys_cmd = (
|
|
379 |
@$cc,
|
|
380 |
$cfile,
|
|
381 |
"${lib}.lib",
|
|
382 |
"/Fe$exefile",
|
|
383 |
(map { '/I'.Win32::GetShortPathName($_) } @incpaths),
|
|
384 |
"/link",
|
|
385 |
@$ld,
|
|
386 |
split(' ', $Config{libs}),
|
|
387 |
(map {'/libpath:'.Win32::GetShortPathName($_)} @libpaths),
|
|
388 |
);
|
|
389 |
} elsif($Config{cc} eq 'CC/DECC') { # VMS
|
|
390 |
} elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
|
|
391 |
@sys_cmd = (
|
|
392 |
@$cc,
|
|
393 |
@$ld,
|
|
394 |
"-o$exefile",
|
|
395 |
(map { "-I$_" } @incpaths),
|
|
396 |
(map { "-L$_" } @libpaths),
|
|
397 |
"-l$lib",
|
|
398 |
$cfile);
|
|
399 |
} else { # Unix-ish
|
|
400 |
# gcc, Sun, AIX (gcc, cc)
|
|
401 |
@sys_cmd = (
|
|
402 |
@$cc,
|
|
403 |
@$ld,
|
|
404 |
$cfile,
|
|
405 |
"-o", "$exefile",
|
|
406 |
(map { "-I$_" } @incpaths),
|
|
407 |
(map { "-L$_" } @libpaths),
|
|
408 |
"-l$lib",
|
|
409 |
);
|
|
410 |
}
|
|
411 |
warn "# @sys_cmd\n" if $args{debug};
|
|
412 |
local $ENV{LD_RUN_PATH} = join(":", grep $_, @libpaths, $ENV{LD_RUN_PATH}) unless $^O eq 'MSWin32';
|
|
413 |
local $ENV{PATH} = join(";", @libpaths).";".$ENV{PATH} if $^O eq 'MSWin32';
|
|
414 |
my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
|
|
415 |
if ($rv != 0 || ! -x $exefile) {
|
|
416 |
push @missing, $lib;
|
|
417 |
}
|
|
418 |
else {
|
|
419 |
my $absexefile = File::Spec->rel2abs($exefile);
|
|
420 |
$absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/;
|
|
421 |
if (system($absexefile) != 0) {
|
|
422 |
push @wrongresult, $lib;
|
|
423 |
}
|
|
424 |
else {
|
|
425 |
if ($analyze_binary) {
|
|
426 |
push @wronganalysis, $lib if !$analyze_binary->($lib, $exefile)
|
|
427 |
}
|
|
428 |
}
|
|
429 |
}
|
|
430 |
_cleanup_exe($exefile);
|
|
431 |
}
|
|
432 |
unlink $cfile;
|
|
433 |
|
|
434 |
my $miss_string = join( q{, }, map { qq{'$_'} } @missing );
|
|
435 |
die("Can't link/include C library $miss_string, aborting.\n") if @missing;
|
|
436 |
my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult);
|
|
437 |
die("wrong result: $wrong_string\n") if @wrongresult;
|
|
438 |
my $analysis_string = join(q{, }, map { qq{'$_'} } @wronganalysis );
|
|
439 |
die("wrong analysis: $analysis_string") if @wronganalysis;
|
|
440 |
}
|
|
441 |
|
|
442 |
sub _cleanup_exe {
|
|
443 |
my ($exefile) = @_;
|
|
444 |
my $ofile = $exefile;
|
|
445 |
$ofile =~ s/$Config{_exe}$/$Config{_o}/;
|
|
446 |
# List of files to remove
|
|
447 |
my @rmfiles;
|
|
448 |
push @rmfiles, $exefile, $ofile, "$exefile\.manifest";
|
|
449 |
if ( $Config{cc} eq 'cl' ) {
|
|
450 |
# MSVC also creates foo.ilk and foo.pdb
|
|
451 |
my $ilkfile = $exefile;
|
|
452 |
$ilkfile =~ s/$Config{_exe}$/.ilk/;
|
|
453 |
my $pdbfile = $exefile;
|
|
454 |
$pdbfile =~ s/$Config{_exe}$/.pdb/;
|
|
455 |
push @rmfiles, $ilkfile, $pdbfile;
|
|
456 |
}
|
|
457 |
if ( $Config{archname} =~ m/^darwin/ ) {
|
|
458 |
my $dsymdir = $exefile;
|
|
459 |
$dsymdir =~ s/$Config{_exe}$/.dSYM/;
|
|
460 |
File::Path::remove_tree($dsymdir) if $dsymdir && -d $dsymdir;
|
|
461 |
}
|
|
462 |
foreach (@rmfiles) {
|
|
463 |
if ( -f $_ ) {
|
|
464 |
unlink $_ or warn "Could not remove $_: $!";
|
|
465 |
}
|
|
466 |
}
|
|
467 |
return
|
|
468 |
}
|
|
469 |
|
|
470 |
# return ($cc, $ld)
|
|
471 |
# where $cc is an array ref of compiler name, compiler flags
|
|
472 |
# where $ld is an array ref of linker flags
|
|
473 |
sub _findcc {
|
|
474 |
my ($debug, $user_ccflags, $user_ldflags) = @_;
|
|
475 |
# Need to use $keep=1 to work with MSWin32 backslashes and quotes
|
|
476 |
my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile
|
|
477 |
my @Config_ldflags = ();
|
|
478 |
for my $config_val ( @Config{qw(ldflags)} ){
|
|
479 |
push @Config_ldflags, $config_val if ( $config_val =~ /\S/ );
|
|
480 |
}
|
|
481 |
my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags||'', $user_ccflags||'');
|
|
482 |
my @ldflags = grep { length && $_ !~ m/^-Wl/ } quotewords('\s+', 1, @Config_ldflags, $user_ldflags||'');
|
|
483 |
my @paths = split(/$Config{path_sep}/, $ENV{PATH});
|
|
484 |
my @cc = split(/\s+/, $Config{cc});
|
|
485 |
if (check_compiler ($cc[0], $debug)) {
|
|
486 |
return ( [ @cc, @ccflags ], \@ldflags );
|
|
487 |
}
|
|
488 |
# Find the extension for executables.
|
|
489 |
my $exe = $Config{_exe};
|
|
490 |
if ($^O eq 'cygwin') {
|
|
491 |
$exe = '';
|
|
492 |
}
|
|
493 |
foreach my $path (@paths) {
|
|
494 |
# Look for "$path/$cc[0].exe"
|
|
495 |
my $compiler = File::Spec->catfile($path, $cc[0]) . $exe;
|
|
496 |
if (check_compiler ($compiler, $debug)) {
|
|
497 |
return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
|
|
498 |
}
|
|
499 |
next if ! $exe;
|
|
500 |
# Look for "$path/$cc[0]" without the .exe, if necessary.
|
|
501 |
$compiler = File::Spec->catfile($path, $cc[0]);
|
|
502 |
if (check_compiler ($compiler, $debug)) {
|
|
503 |
return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
|
|
504 |
}
|
|
505 |
}
|
|
506 |
die("Couldn't find your C compiler.\n");
|
|
507 |
}
|
|
508 |
|
|
509 |
sub check_compiler
|
|
510 |
{
|
|
511 |
my ($compiler, $debug) = @_;
|
|
512 |
if (-f $compiler && -x $compiler) {
|
|
513 |
if ($debug) {
|
|
514 |
warn("# Compiler seems to be $compiler\n");
|
|
515 |
}
|
|
516 |
return 1;
|
|
517 |
}
|
|
518 |
return '';
|
|
519 |
}
|
|
520 |
|
|
521 |
|
|
522 |
# code substantially borrowed from IPC::Run3
|
|
523 |
sub _quiet_system {
|
|
524 |
my (@cmd) = @_;
|
|
525 |
|
|
526 |
# save handles
|
|
527 |
local *STDOUT_SAVE;
|
|
528 |
local *STDERR_SAVE;
|
|
529 |
open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT";
|
|
530 |
open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR";
|
|
531 |
|
|
532 |
# redirect to nowhere
|
|
533 |
local *DEV_NULL;
|
|
534 |
open DEV_NULL, ">" . File::Spec->devnull
|
|
535 |
or die "CheckLib: $! opening handle to null device";
|
|
536 |
open STDOUT, ">&" . fileno DEV_NULL
|
|
537 |
or die "CheckLib: $! redirecting STDOUT to null handle";
|
|
538 |
open STDERR, ">&" . fileno DEV_NULL
|
|
539 |
or die "CheckLib: $! redirecting STDERR to null handle";
|
|
540 |
|
|
541 |
# run system command
|
|
542 |
my $rv = system(@cmd);
|
|
543 |
|
|
544 |
# restore handles
|
|
545 |
open STDOUT, ">&" . fileno STDOUT_SAVE
|
|
546 |
or die "CheckLib: $! restoring STDOUT handle";
|
|
547 |
open STDERR, ">&" . fileno STDERR_SAVE
|
|
548 |
or die "CheckLib: $! restoring STDERR handle";
|
|
549 |
|
|
550 |
return $rv;
|
|
551 |
}
|
|
552 |
|
|
553 |
=head1 PLATFORMS SUPPORTED
|
|
554 |
|
|
555 |
You must have a C compiler installed. We check for C<$Config{cc}>,
|
|
556 |
both literally as it is in Config.pm and also in the $PATH.
|
|
557 |
|
|
558 |
It has been tested with varying degrees of rigorousness on:
|
|
559 |
|
|
560 |
=over
|
|
561 |
|
|
562 |
=item gcc (on Linux, *BSD, Mac OS X, Solaris, Cygwin)
|
|
563 |
|
|
564 |
=item Sun's compiler tools on Solaris
|
|
565 |
|
|
566 |
=item IBM's tools on AIX
|
|
567 |
|
|
568 |
=item SGI's tools on Irix 6.5
|
|
569 |
|
|
570 |
=item Microsoft's tools on Windows
|
|
571 |
|
|
572 |
=item MinGW on Windows (with Strawberry Perl)
|
|
573 |
|
|
574 |
=item Borland's tools on Windows
|
|
575 |
|
|
576 |
=item QNX
|
|
577 |
|
|
578 |
=back
|
|
579 |
|
|
580 |
=head1 WARNINGS, BUGS and FEEDBACK
|
|
581 |
|
|
582 |
This is a very early release intended primarily for feedback from
|
|
583 |
people who have discussed it. The interface may change and it has
|
|
584 |
not been adequately tested.
|
|
585 |
|
|
586 |
Feedback is most welcome, including constructive criticism.
|
|
587 |
Bug reports should be made using L<http://rt.cpan.org/> or by email.
|
|
588 |
|
|
589 |
When submitting a bug report, please include the output from running:
|
|
590 |
|
|
591 |
perl -V
|
|
592 |
perl -MDevel::CheckLib -e0
|
|
593 |
|
|
594 |
=head1 SEE ALSO
|
|
595 |
|
|
596 |
L<Devel::CheckOS>
|
|
597 |
|
|
598 |
L<Probe::Perl>
|
|
599 |
|
|
600 |
=head1 AUTHORS
|
|
601 |
|
|
602 |
David Cantrell E<lt>david@cantrell.org.ukE<gt>
|
|
603 |
|
|
604 |
David Golden E<lt>dagolden@cpan.orgE<gt>
|
|
605 |
|
|
606 |
Yasuhiro Matsumoto E<lt>mattn@cpan.orgE<gt>
|
|
607 |
|
|
608 |
Thanks to the cpan-testers-discuss mailing list for prompting us to write it
|
|
609 |
in the first place;
|
|
610 |
|
|
611 |
to Chris Williams for help with Borland support;
|
|
612 |
|
|
613 |
to Tony Cook for help with Microsoft compiler command-line options
|
|
614 |
|
|
615 |
=head1 COPYRIGHT and LICENCE
|
|
616 |
|
|
617 |
Copyright 2007 David Cantrell. Portions copyright 2007 David Golden.
|
|
618 |
|
|
619 |
This module is free-as-in-speech software, and may be used, distributed,
|
|
620 |
and modified under the same conditions as perl itself.
|
|
621 |
|
|
622 |
=head1 CONSPIRACY
|
|
623 |
|
|
624 |
This module is also free-as-in-mason software.
|
|
625 |
|
|
626 |
=cut
|
|
627 |
|
|
628 |
1;
|