File Coverage

blib/lib/ExtUtils/CFeatureTest.pm
Criterion Covered Total %
statement 148 338 43.7
branch 59 208 28.3
condition 7 29 24.1
subroutine 25 54 46.3
pod 27 27 100.0
total 266 656 40.5


line stmt bran cond sub pod time code
1             package ExtUtils::CFeatureTest;
2             our $VERSION= '0.002'; # VERSION
3 1     1   133161 use strict;
  1         2  
  1         41  
4 1     1   7 use warnings;
  1         2  
  1         59  
5 1     1   735 use IO::Handle;
  1         8847  
  1         67  
6 1     1   674 use ExtUtils::CBuilder;
  1         86480  
  1         4438  
7              
8             =head1 NAME
9              
10             ExtUtils::CFeatureTest - Test a host for available C language features and libraries
11              
12             =head1 SYNOPSIS
13              
14             use "./inc";
15             use ExtUtils::CFeatureTest;
16             my $ftest= ExtUtils::CFeatureTest->new;
17            
18             # Test if a header exists. If found, set macro HAVE_STDBOOL_H, and all
19             # compilation attempts below this will automatically include the header.
20             $ftest->header('stdbool.h');
21            
22             # Compile and run the snippet of code, and set HAVE_BOOL if it succeeds.
23             $ftest->feature(HAVE_BOOL => 'bool x= true; return x? 0 : 1;');
24            
25             # Compile and run the snippet of code, and try various permutations of
26             # headers and libs until it works. This one is required, so warn and
27             # exit if it isn't available.
28             $ftest->require_feature(HAVE_LIBSSL =>
29             'unsigned char buf[1]; return RAND_bytes(buf, 1) == 1? 0 : 1;',
30             { h => 'openssl/rand.h', pkg_config => ['libressl'] },
31             { h => 'openssl/rand.h', pkg_config => ['openssl'] },
32             { h => 'openssl/rand.h', -l => [ 'ssl', 'crypto' ] });
33            
34             # Export all the things we learned into a header to be included by all
35             # source units in the project.
36             $ftest->write_config_header('MyModule_config.h');
37            
38             # Export the compiler flags into ExtUtils::Depends to be used and/or
39             # installed for other modules to use.
40             my $dep= ExtUtils::Depends->new('MyModule');
41             $ftest->export_deps($dep);
42              
43             =head1 DESCRIPTION
44              
45             This is a module for testing aspects the C compiler and available libraries prior to building an
46             XS distribution. It borrows many ideas from L and L.
47             The main difference is that instead of simply building a list of compiler flags, it
48             builds an entire header file for you that helps remove boilerplate from your other C files.
49              
50             For example, a traditional approach is to test for a C header like C, and if found
51             define a preprocessor macro like C, and then in your source code you write
52              
53             #ifdef HAVE_STDINT_H
54             #include
55             #endif
56              
57             This results in a bulky list of C<< -DHAVE_SOME_FEATURE >> options to your compiler, and also
58             a lot of boilerplate within each C file.
59              
60             This module eliminates the middleman by generating a header of its own with everything it
61             learned from feature detection I the workarounds your Makefile.PL have added based on that
62             knowledge. For the above example, if it finds C it adds the include statement
63             directly to the generated header, saving you the C<#ifdef> boilerplate and avoiding any
64             commandline arguments for the compiler.
65              
66             =head1 INTEGRATION
67              
68             I strongly recommend copying C into your distribution as
69             C<< inc/ExtUtils/CFeatureTest.pm >> rather than installing a system-wide copy. This ensures
70             that future changes to CFeatureTest don't break existing distributions. While I don't change
71             APIs frivolously, I'm not committing to full back-compat until it reaches version 1.0.
72              
73             To this end, C is a single file with no non-core dependencies (since C
74             which added L) so literally all you need to do is copy one file into your
75             distribution as C<< inc/ExtUtils/CFeatureTest.pm >> and add C<< use lib "./inc" >> to the top
76             of your C.
77              
78             See the C of L for a complete example.
79              
80             =head1 CONSTRUCTOR
81              
82             =head2 new
83              
84             $test= ExtUtils::CFeatureTest->new(%attributes);
85              
86             =cut
87              
88             sub new {
89 1     1 1 254419 my $self= bless {}, shift;
90 1   50     15 $self->{verbose}= $ENV{EXTUTILS_CFEATURETEST_VERBOSE} || 0;
91 1         12 $self->{emit_tty}= -t \*STDOUT;
92             $self->{emit_unicode}= $self->{emit_tty}
93             && grep(defined($_) && /UTF-?8/i, @ENV{qw( LANG LC_ALL LC_CTYPE )})
94 1   33     7 && ($^O ne 'MSWin32' || $ENV{WT_SESSION} || $ENV{TERM});
95 1         4 $self->{config_includes}= '';
96 1         4 $self->{config_include_set}= {};
97 1         4 $self->{config_pkg_set}= {};
98 1         6 $self->{config_macros}= {};
99 1         4 $self->{config_local}= '';
100 1         3 $self->{last_err}= '';
101 1         3 $self->{last_compile_output}= '';
102 1         4 $self->{last_exec_output}= '';
103 1         3 $self->{include_dirs}= [];
104 1         4 $self->{extra_compiler_flags}= [];
105 1         3 $self->{extra_linker_flags}= [];
106 1 50       5 @_ & 1 and die "Expected even-length list of attribute => value";
107 1         5 for (my $i= 0; $i < @_; $i+= 2) {
108 0         0 my ($attr, $val)= @_[$i,$i+1];
109 0         0 my $setter= "_set_$attr";
110 0         0 $self->$setter($val);
111             }
112 1         4 $self;
113             }
114              
115             =head1 ATTRIBUTES
116              
117             =head2 verbose
118              
119             If true, emit diagnostics, including output from the compiler. The default comes from
120             C<$ENV{EXTUTILS_CFEATURETEST_VERBOSE}>. A future version might make this into an integer of
121             "log levels".
122              
123             =head2 emit_tty
124              
125             If true, enable fancy colorized output. The default is based on whether STDOUT is a terminal.
126             This also triggers for MSWin32 consoles, but the latest versions of the Windows console do
127             support TTY color codes.
128              
129             =head2 emit_unicode
130              
131             If true, enable fancy unicode indicators in the output. The default is true if any locale
132             environment variables contain 'utf-8'.
133              
134             =cut
135              
136 1 50   1 1 32 sub verbose { @_ > 1? shift->_set_verbose(@_) : $_[0]{verbose} }
137 0     0   0 sub _set_verbose { $_[0]{verbose}= !!$_[1]; $_[0] }
  0         0  
138              
139 0 0   0 1 0 sub emit_tty { @_ > 1? shift->_set_emit_tty(@_) : $_[0]{emit_tty} }
140 0     0   0 sub _set_emit_tty { $_[0]{emit_tty}= !!$_[1]; $_[0] }
  0         0  
141              
142 4 50   4 1 120 sub emit_unicode { @_ > 1? shift->_set_emit_unicode(@_) : $_[0]{emit_unicode} }
143 0     0   0 sub _set_emit_unicode { $_[0]{emit_unicode}= !!$_[1]; $_[0] }
  0         0  
144              
145             my ($green, $red, $reset, $uchar_check, $uchar_x)
146             = ("\e[32m","\e[31m","\e[0m","\x{2713}","\x{2715}");
147              
148             sub _emit {
149 7     7   35 my ($self, $handle, $msg)= @_;
150             # This method is not efficient, but not a hot code path so not worth optimizing.
151             $msg =~ s/\e\[.*?m//g
152 7 50       118 unless $self->{emit_tty};
153 7 50 33     51 if ($self->{emit_unicode} && utf8::is_utf8($msg)) {
154 0         0 require PerlIO;
155 0 0       0 utf8::encode($msg)
156             unless grep /utf-?8/i, PerlIO::get_layers($handle);
157             }
158 7         111 $handle->print($msg."\n");
159             }
160              
161             =head2 config_header_text
162              
163             The C source code generated so far by the detection methods, including the L
164             and L. The config source code is structured as
165              
166             /* attribute config_includes */
167             #include
168             #include
169             ...
170             /* attribute config_macros */
171             #define HAS_HEADER1
172             #define HAS_HEADER2
173             ...
174             /* attribute config_local */
175             ...
176              
177             This structure ensures that system headers are included before the pollution from your local
178             macros and other symbols.
179              
180             =head2 config_includes
181              
182             The C code of C<#include> statements generated so far by the detection methods.
183             Also any code you added with L.
184              
185             =head2 config_include_set
186              
187             A hashref where each key is a header name which has been added to C.
188             (The hashref is used as a cache, not a declaration that drives code generation)
189              
190             =head2 config_pkg_set
191              
192             A hashref of the C library names which have been added. Read-only.
193             (The hashref is used as a cache, not a declaration that drives code generation)
194              
195             =head2 config_macros
196              
197             A hashref where each key is a C macro name and the value is the definition of the macro.
198             You may modify this hashref to define or remove macros.
199             These will always come after the text of C so as not to pollute global
200             namespace before system headers get included. If you wish to define a macro I the
201             inclusion of system headers (such as C<_GNU_SOURCE> or C) use
202             L.
203              
204             =head2 config_local
205              
206             A string of custom C code to append following C and C.
207             This is intended for code you want defined for your entire project but don't want defined until
208             after all system headers are included. See L.
209              
210             =cut
211              
212             sub config_header_text {
213 1     1 1 4 my $self= shift;
214 1         7 return $self->config_includes
215             . $self->_config_macros_text
216             . $self->config_local;
217             }
218              
219 7 50   7 1 198 sub config_includes { @_ > 1? shift->_set_config_includes(@_) : $_[0]{config_includes} }
220             sub _set_config_includes {
221 0 0   0   0 ref $_[1] and die "config_includes must be a string of C code";
222 0         0 $_[0]{config_includes}= $_[1];
223 0         0 $_[0]
224             }
225              
226 3     3 1 31 sub config_include_set { $_[0]{config_include_set} }
227 0     0 1 0 sub config_pkg_set { $_[0]{config_pkg_set} }
228              
229 6 50   6 1 50 sub config_macros { @_ > 1? shift->_set_config_macros(@_) : $_[0]{config_macros} }
230             sub _set_config_macros {
231 0 0   0   0 ref $_[1] eq 'HASH' or die "config_macros must be a hashref";
232 0         0 $_[0]{config_macros}= $_[1];
233 0         0 $_[0]
234             }
235             sub _config_macros_text {
236 5     5   17 my $self= shift;
237 5         26 my $code= '';
238 5         31 my $macros= $self->config_macros;
239 5         38 for (sort keys %$macros) {
240 6 50       21 if (defined(my $val= $macros->{$_})) {
241 6         24 $val =~ s/\n\z//; # automatically add the backslashes on multiline macros
242 6         45 $val =~ s/\n/\\\n/g;
243 6         28 $code .= "#define $_ $val\n";
244             } else {
245 0         0 $code .= "#define $_\n";
246             }
247             }
248 5         28 return $code;
249             }
250              
251 5 50   5 1 94 sub config_local { @_ > 1? shift->_set_config_local(@_) : $_[0]{config_local} }
252             sub _set_config_local {
253 0 0   0   0 ref $_[1] and die "config_local must be a string of C code";
254 0         0 $_[0]{config_local}= $_[1];
255 0         0 $_[0]
256             }
257              
258             =head2 cbuilder
259              
260             An instance of L (a core module in modern perls), lazy-built.
261              
262             =head2 last_err
263              
264             The exception generated by the last call to L, if any.
265              
266             =head2 last_compile_output
267              
268             The stdout/stderr generated by the last invocation of compiler and/or linker.
269              
270             =head2 last_exec_output
271              
272             The stdout/stderr generated by the last execution of a built executable.
273              
274             =cut
275              
276             sub cbuilder {
277             @_ > 1? shift->_set_cbuilder(@_)
278 13 50 66 13 1 396 : ($_[0]{cbuilder} ||= ExtUtils::CBuilder->new)
279             }
280 0     0   0 sub _set_cbuilder { $_[0]{cbuilder}= $_[1]; $_[0] }
  0         0  
281              
282 0 0   0 1 0 sub last_err { @_ > 1? shift->_set_last_err(@_) : $_[0]{last_err} }
283 0     0   0 sub _set_last_err { $_[0]{last_err}= $_[1]; $_[0] }
  0         0  
284              
285 0 0   0 1 0 sub last_compile_output { @_ > 1? shift->_set_last_compile_output(@_) : $_[0]{last_compile_output} }
286 0     0   0 sub _set_last_compile_output { $_[0]{last_compile_output}= $_[1]; $_[0] }
  0         0  
287              
288 0 0   0 1 0 sub last_exec_output { @_ > 1? shift->_set_last_exec_output(@_) : $_[0]{last_exec_output} }
289 0     0   0 sub _set_last_exec_output { $_[0]{last_exec_output}= $_[1]; $_[0] }
  0         0  
290              
291             =head2 include_dirs
292              
293             An arrayref of directories to be passed to the compiler as C<< -Ipath >>.
294              
295             =head2 extra_compiler_flags
296              
297             An arrayref of command line arguments to pass to the C compiler.
298              
299             =head2 extra_linker_flags
300              
301             An arrayref of command line arguments to pass to the C linker.
302              
303             =cut
304              
305 8 50   8 1 40 sub include_dirs { @_ > 1? shift->_set_include_dirs(@_) : $_[0]{include_dirs} }
306 0 0   0   0 sub _set_include_dirs { my $self= shift; $self->{include_dirs}= [ ref $_[0] eq 'ARRAY'? @{$_[0]} : @_ ]; $self }
  0         0  
  0         0  
  0         0  
307              
308 8 50   8 1 57 sub extra_compiler_flags { @_ > 1? shift->_set_extra_compiler_flags(@_) : $_[0]{extra_compiler_flags} }
309 0 0   0   0 sub _set_extra_compiler_flags { my $self= shift; $self->{extra_compiler_flags}= [ ref $_[0] eq 'ARRAY'? @{$_[0]} : @_ ]; $self }
  0         0  
  0         0  
  0         0  
310              
311 8 50   8 1 63 sub extra_linker_flags { @_ > 1? shift->_set_extra_linker_flags(@_) : $_[0]{extra_linker_flags} }
312 0 0   0   0 sub _set_extra_linker_flags { my $self= shift; $self->{extra_linker_flags}= [ ref $_[0] eq 'ARRAY'? @{$_[0]} : @_ ]; $self }
  0         0  
  0         0  
  0         0  
313              
314             sub _spew {
315 8     8   23 my $fname= shift;
316 8 50       1510 open my $fh, '>', $fname or die "open($fname): $!";
317 8 50       126 $fh->print(@_) or die "write($fname): $!";
318 8 50       363 $fh->close or die "close($fname): $!";
319             }
320              
321             sub _maybe_list {
322 0 0 0 0   0 ref $_[0] eq 'ARRAY'? (grep length, @{ $_[0] })
  0 0       0  
323             : defined $_[0] && length $_[0]? ( $_[0] )
324             : ()
325             }
326              
327             sub _capture_output {
328 12     12   46 my ($self, $code)= @_;
329 12         207 my $outfile= "ftest-$$-" . ++$self->{seq} . "-out.txt";
330 12 50       2120 open my $out_fh, '+>', $outfile or die "open($outfile): $!";
331 12 50       327 open my $stdout_save, ">&STDOUT" or die "dup(STDOUT): $!";
332 12 50       283 open my $stderr_save, ">&STDERR" or die "dup(STDERR): $!";
333 12 50       377 open STDOUT, ">&" . fileno $out_fh or die "Can't redirect STDOUT: $!";
334 12 50       432 open STDERR, ">&" . fileno $out_fh or die "Can't redirect STDERR: $!";
335 12         53 my ($ex, $out_txt);
336 12 50       28 eval { $code->(); 1 }
  12         43  
  12         80  
337             or $ex= $@;
338             # restore handles
339 12 50       676 open STDERR, ">&" . fileno $stderr_save or die "Can't restore STDERR: $!";
340 12 50       355 open STDOUT, ">&" . fileno $stdout_save or die "Can't restore STDOUT: $!";
341             # Slurp contents of compiler output
342 12         125 seek($out_fh, 0, 0);
343 12         36 { local $/; $out_txt= <$out_fh> }
  12         191  
  12         766  
344 12         174 close $out_fh;
345 12         1378 unlink $outfile;
346 12 50       179 $out_txt .= "\n".$ex if defined $ex;
347 12         947 return $out_txt;
348             }
349              
350             sub _capture_cmd {
351 0     0   0 my ($self, @cmd)= @_;
352 0         0 my $wstat;
353 0     0   0 my $out= $self->_capture_output(sub { system { $cmd[0] } @cmd; $wstat= $?; });
  0         0  
  0         0  
  0         0  
354 0         0 return ($wstat, $out);
355             }
356              
357             =head1 METHODS
358              
359             =head2 compile_and_run
360              
361             $bool= $ftest->compile_and_run($code, %options);
362             # %options:
363             # include_dirs => [ ... ],
364             # extra_compiler_flags => [ ... ],
365             # extra_linker_flags => [ ... ],
366              
367             Attempt to compile and execute the specified C program text. The compiler will be given all
368             include paths, compiler flags, and linker flags that have been detected so far, in addition to
369             the ones that you pass to this method. C<$code> must be the complete program; the accumulated
370             configuration code in L is not automatically applied.
371              
372             Returns boolean of whether it succeeded (meaning compile, link, and executable all exited with
373             code 0).
374             The compiler output is stored in attribute L, perl exceptions are stored
375             in attribute L, and output of the text executable is stored in L.
376             Nothing is printed to stdout/stderr.
377              
378             =cut
379              
380             sub compile_and_run {
381 8     8 1 100 my ($self, $code, %opts)= @_;
382 8         42 $self->{last_err}= '';
383 8         23 $self->{last_exec_output}= '';
384 8         37 $self->{last_compile_output}= '';
385 8         41 for (qw( include_dirs extra_compiler_flags extra_linker_flags )) {
386 24 50       59 $opts{$_}= [ @{ $self->$_ }, @{ $opts{$_} || [] } ];
  24         160  
  24         193  
387             }
388              
389 8         156 my $srcfile= "ftest-$$-" . ++$self->{seq} . ".c";
390 8         71 _spew($srcfile, $code);
391 8         618 my ($objfile, $exefile, $err, $success);
392              
393             # Compiler is rather noisy. Redirect output to temp file.
394             $self->{last_compile_output}= $self->_capture_output(sub {
395 8     8   18 $success= eval {
396 8         18 $err= "compile failed";
397 8         65 $objfile= $self->cbuilder->compile(%opts, source => $srcfile);
398 5         398434 $err= "link failed";
399 5         116 $exefile= $self->cbuilder->link_executable(%opts, objects => $objfile);
400             };
401 8 50       414210 chomp($self->{last_err}= $@? "$err: $@" : $err) unless $success;
    100          
402 8         205 });
403 8 100       344 if ($success) {
404             $self->{last_exec_output}= $self->_capture_output(sub {
405 4     4   25 $success= eval {
406 4         42 $err= "execute";
407 4         23917 system("./$exefile");
408 4 50       174 if ($?) { $err= "execute failed: ".($? & 0xFF? "signal $?" : "exit code ".($? >> 8)) }
  1 100       84  
409 4         90 $? == 0
410             };
411 4 50       95 chomp($self->{last_err}= $@? "$err: $@" : $err) unless $success;
    100          
412 4         97 });
413             }
414 8         2123 unlink grep defined, $srcfile, $objfile, $exefile;
415 8         514 return $success;
416             }
417              
418             =head2 header
419              
420             $ftest->header('some_header.h', @test_inc_paths);
421              
422             Attempt to compile a simple C program that includes the named header. The first compilation
423             attempt will use the existing include path, and if not found, it will try compilation again
424             for each element of C<@test_inc_paths> added to the include path until one succeeds.
425              
426             If any attempt succeeds, append the C<#include> directive to the L attribute
427             and define macro C in attribute L.
428              
429             This means all future tests will automatically have this header loaded, if it exists.
430              
431             Returns a boolean of whether it added the header.
432              
433             =head2 require_header
434              
435             Like L, but warn+exit if it fails. i.e. the header is mandatory for the build.
436              
437             =cut
438              
439             sub header {
440 2     2 1 18 my ($self, $header, @paths)= @_;
441 2 50       23 return 1 if $self->{config_include_set}{$header};
442 2         35 (my $macro= 'HAVE_'.uc($header)) =~ s/\W/_/g;
443 2         9 my $code= <
444 2         25 @{[ $self->config_includes ]}
445             #include <$header>
446 2         18 @{[ $self->_config_macros_text ]}
447 2         17 @{[ $self->config_local ]}
448             int main(int argc, char **argv) { return 0; }
449             END_C
450 2         18 for my $path (undef, @paths) {
451 2 50       22 if ($self->compile_and_run($code, (defined $path? (include_dirs => [$path]) : ()))) {
    100          
452             # It worked. Add the header to our list, and add a macro for having detected it.
453 1         18 $self->{config_includes} .= "#include <$header>\n";
454 1         23 $self->{config_include_set}{$header}= 1;
455 1 50       11 push @{$self->{include_dirs}}, $path if defined $path;
  0         0  
456 1         12 $self->{config_macros}{$macro}= 1;
457 1 50       32 $self->_emit(\*STDOUT, "Found $header".(defined $path? " at $path" : " in existing include dirs"));
458 1 50       48 $self->_emit(\*STDOUT, ($self->emit_unicode? "$uchar_check " : '+') . "$green$macro$reset");
459 1         41 return 1;
460             }
461             }
462 1 50       38 $self->_emit(\*STDOUT, ($self->emit_unicode? "$uchar_x " : '-') . "$red$macro$reset");
463 1         75 return 0;
464             }
465              
466             sub require_header {
467 0     0 1 0 my ($self, $header, @args)= @_;
468 0         0 my $success= $self->header($header, @args);
469 0 0       0 if (!$success) {
470 0         0 STDOUT->flush;
471 0         0 warn $self->last_err;
472 0         0 warn $self->last_compile_output;
473 0         0 $self->_emit(\*STDERR, "${red}Can't proceed without $header$reset");
474 0         0 exit 1;
475             }
476 0         0 1;
477             }
478              
479             =head2 feature
480              
481             $bool= $ftest->feature(MACRO_NAME => $c_code_snippet,
482             { # one possible set of options known to work
483             h => \@header_names,
484             include_dirs => \@paths,
485             extra_compiler_flags => \@commandline_options,
486             extra_linker_flags => \@commandline_options,
487             pkg_config => \@module_names,
488             },
489             { # another possible set of options known to work
490             # using convenient aliases for the attributes above
491             h => $header, -I => $path, -D => $macro, -L => $path, -l => $lib
492             },
493             ... # as many attempts as you want
494             );
495              
496             This attempts to compile and execute C<$c_code_snippet>. It attempts compilation once without
497             any configuration changes, and then attempts again using each of a supplied list of
498             configurations until one succeeds. You can specify the configurations using full attribute
499             names, or with shorthand aliases that resemble the gcc command line flags.
500              
501             Again, note that any compiler/linker flags are I to any others that were previously
502             detected (the attributes L, L, and L)
503             and the generated source code automatically includes the L that
504             CFeatureTest is in the process of building.
505              
506             Also note that the C option attempts to load I of the C<@module_names> and
507             proceeds to attempt compilation if I of them were found.
508              
509             =head2 require_feature
510              
511             Like L, but warn+exit if it fails. i.e. the feature is mandatory for the build.
512              
513             =cut
514              
515             sub feature {
516 2     2 1 21 my ($self, $macro, $code, @permutations)= @_;
517             # Single function name? just take the address of it
518 2 50       31 if ($code =~ /^\w+\z/) {
519             # Compilers might optimize a simple "fn != NULL" to a constant expression and then not
520             # even link it. Compare to another pointer like argv hoping they can't optimize that.
521 2         9 $code= "void *fn= (void *) $code; return fn != argv? 0 : 1;";
522             }
523             # Bare snippet without 'main' function wrapping it?
524 2 50       11 unless ($code =~ /int main\(/) {
525             # Is it a snippet belonging inside main?
526 2 50       23 if ($code =~ /return [^{}]+;/) {
527 2         7 $code= "int main(int argc, char **argv) { $code }\n";
528             } else {
529 0         0 $code= "$code\nint main(int argc, char **argv) { return 0; }\n";
530             }
531             }
532 2         18 $self->_emit(\*STDOUT, "Test for feature $macro");
533 2         41 for my $p (undef, @permutations) {
534 2         7 my $prefix= $self->config_includes;
535 2         5 my (@headers, @pkg_found);
536 2 50       7 if ($p) {
537             # clone $p before making changes
538 0         0 $p= { %$p };
539             $p->{$_}= [ _maybe_list($p->{$_}) ]
540 0         0 for qw( include_dirs extra_compiler_flags extra_linker_flags );
541             # optional header attempts
542 0         0 @headers= grep !$self->{config_include_set}{$_}, _maybe_list(delete $p->{h});
543 0         0 $prefix .= "#include <$_>\n" for @headers;
544             # expand convenient aliases
545 0         0 push @{ $p->{include_dirs} }, _maybe_list(delete $p->{-I})
546 0 0       0 if defined $p->{-I};
547 0         0 push @{ $p->{extra_compiler_flags} }, map "-D$_", _maybe_list(delete $p->{-D})
548 0 0       0 if defined $p->{-D};
549 0         0 push @{ $p->{extra_linker_flags} }, map "-L$_", _maybe_list(delete $p->{-L})
550 0 0       0 if defined $p->{-L};
551 0         0 push @{ $p->{extra_linker_flags} }, map "-l$_", _maybe_list(delete $p->{-l})
552 0 0       0 if defined $p->{-l};
553             # If any pkg_config modules were requested, add those to the options.
554             # If none are available, skip the compilation attempt.
555 0 0       0 if (my @mod= _maybe_list(delete $p->{pkg_config})) {
556 0         0 my $msg= " pkg-config";
557 0         0 for (@mod) {
558 0 0       0 if ($self->get_pkg_config($_, $p)) {
559 0         0 push @pkg_found, $_;
560 0         0 $msg .= " $green$_$reset (found)";
561             } else {
562 0         0 $msg .= " $red$_$reset (not found)";
563             }
564             }
565 0         0 $self->_emit(\*STDOUT, $msg);
566 0 0       0 next unless @pkg_found;
567             }
568             }
569 2         11 $prefix .= $self->_config_macros_text . $self->config_local;
570 2 50       15 if ($p) {
571 0         0 my @show_options;
572 0         0 for (sort keys %$p) {
573 0         0 my $val= $p->{$_};
574 0 0       0 next unless defined $val;
575 0 0       0 if (ref $val eq 'ARRAY') {
576 0 0       0 next unless @$val;
577 0         0 $val= join ' ', @$val;
578             }
579 0 0       0 next unless length $val;
580 0         0 push @show_options, "$_=$val";
581             }
582 0 0       0 if (@show_options) {
583 0         0 print " test with $_\n" for shift @show_options;
584 0         0 print " $_\n" for @show_options;
585             }
586             }
587 2 50       28 if ($self->compile_and_run($prefix.$code, $p? (%$p) : ())) {
    100          
    50          
588 1 50       17 if ($p) {
589 0         0 for (qw( include_dirs extra_compiler_flags extra_linker_flags )) {
590 0 0       0 push @{$self->{$_}}, @{$p->{$_}} if $p->{$_};
  0         0  
  0         0  
591             }
592 0         0 for (@headers) {
593 0         0 $self->{config_includes} .= "#include <$_>\n";
594 0         0 $self->{config_include_set}{$_}= 1;
595             }
596             }
597 1 50 33     24 if (defined $macro && length $macro) {
598 1         10 $self->{config_macros}{$macro}= 1;
599 1 50       26 $self->_emit(\*STDOUT, ($self->emit_unicode? "$uchar_check " : '+') . "$green$macro$reset");
600             }
601 1         66 return 1;
602             } elsif ($self->verbose) {
603 0         0 my $msg= $self->last_err."\n".$self->last_compile_output."\n";
604 0         0 $msg =~ s/^/ /mg;
605 0         0 print $msg;
606             }
607             }
608 1 50 33     69 $self->_emit(\*STDOUT, ($self->emit_unicode? "$uchar_x " : '-') . "$red$macro$reset")
    50          
609             if defined $macro && length $macro;
610 1         70 return 0;
611             }
612              
613             sub require_feature {
614 0     0 1   my ($self, $macro, @args)= @_;
615 0           my $success= $self->feature($macro, @args);
616 0 0         if (!$success) {
617 0           STDOUT->flush;
618 0           warn $self->last_err;
619 0           warn $self->last_compile_output;
620 0           warn "Can't proceed without $macro";
621 0           exit 1;
622             }
623 0           1;
624             }
625              
626             =head2 get_pkg_config
627              
628             $bool= $ftest->get_pkg_config($package_name, \%options_out);
629             $bool= $ftest->get_pkg_config(\@package_names, \%options_out);
630              
631             For a named package, retrieve the C<--cflags> and C<--libs> and store the values into
632             C<%options_out>.
633             If the package is not installed or C executable is missing, this returns false.
634             You can customize the C executable with C<$ENV{PKG_CONFIG}>.
635              
636             If you specify an array of names to check, B will be attempted, and success will be
637             determined by whether B of them existed. This is intended for cases where you have one
638             specific package in mind, but it may be available as an alternate name or divided into
639             sub-modules depending on the OS distribution.
640              
641             =cut
642              
643             my $have_pkg_config;
644             sub get_pkg_config {
645 0     0 1   my ($self, $modules, $options_out)= @_;
646 0           my $pc = 'pkg-config';
647 0 0         if (defined $ENV{PKG_CONFIG}) {
648             # Disallow shell metacharacters in executable name, just in case.
649 0 0         ($pc= $ENV{PKG_CONFIG}) !~ /[\0-\x1F"'\$\%{}\x7F]/
650             or die "Unsafe value of PKG_CONFIG environment variable";
651             }
652             #print " called get_pkg_config($modules)\n";
653 0 0         unless (defined $have_pkg_config) {
654             # only warn about it once
655 0           my ($wstat, $out)= $self->_capture_cmd($pc, '--version');
656 0 0         chomp($have_pkg_config= $wstat == 0? $out : '');
657 0 0         print "$pc not found (override with PKG_CONFIG=path)\n"
658             unless $have_pkg_config;
659             }
660 0           my $success;
661 0 0         if ($have_pkg_config) {
662 0           for my $m (_maybe_list($modules)) {
663 0 0         if (!exists $self->{config_pkg_set}{$m}) {
664             # Existence check first
665 0 0         if ((system { $pc } $pc, '--exists', $m) == 0) {
  0            
666 0           my ($cf_wstat, $cflags) = $self->_capture_cmd($pc, '--cflags', $m);
667 0           my ($l_wstat, $libs) = $self->_capture_cmd($pc, '--libs', $m);
668 0           chomp($cflags, $libs);
669 0 0 0       if ($self->verbose || $cf_wstat || $l_wstat) {
      0        
670 0 0         print " pkg-config module $m cflags: ".($cf_wstat? 'FAILED: ':'')."$cflags\n";
671 0 0         print " pkg-config module $m libs : ".($l_wstat? 'FAILED: ':'')."$libs\n";
672             }
673 0 0         $self->{config_pkg_set}{$m}{cflags}= $cf_wstat? '' : $cflags;
674 0 0         $self->{config_pkg_set}{$m}{libs}= $l_wstat? '' : $libs;
675             }
676             else {
677             # warn once if module not on this host
678 0 0         print " pkg-config module $m not found\n" if $self->verbose;
679 0           $self->{config_pkg_set}{$m}= undef;
680             }
681             }
682 0 0         if (my $cfg= $self->{config_pkg_set}{$m}) {
683 0           for (_shellwords($cfg->{cflags})) {
684 0 0         if (/^-I(.+)$/) { push @{$options_out->{include_dirs}}, $1; }
  0            
  0            
685 0           else { push @{$options_out->{extra_compiler_flags}}, $_; }
  0            
686             }
687 0           push @{$options_out->{extra_linker_flags}}, _shellwords($cfg->{libs})
688 0 0         if length $cfg->{libs};
689 0           $success= 1;
690             }
691             }
692             }
693 0           return $success;
694             }
695              
696             # Extract a list of program arguments from a commandline string.
697             # This doesn't fully respect shell rules, just enough for what pkg-config is likely
698             # to emit for the --cflags or --libs. Win32 would throw a wrench into proper shell
699             # word parsing, anyway.
700             sub _shellwords {
701 0     0     my ($s)= @_;
702 0           my @out;
703 0   0       while (defined $s && length $s) {
704 0           $s =~ s/^\s+//;
705 0 0         last unless length $s;
706 0 0         if ($s =~ s/^"((?:\\.|[^"])*)"//) {
    0          
707 0           (my $w=$1)=~s/\\"/"/g; $w=~s/\\\\/\\/g;
  0            
708 0           push @out, $w;
709             }
710             elsif ($s =~ s/^'((?:\\.|[^'])*)'//) {
711 0           (my $w=$1)=~s/\\'/'/g; $w=~s/\\\\/\\/g;
  0            
712 0           push @out, $w;
713             }
714             else {
715 0 0         $s =~ s/^([^\s]+)// or last;
716 0           push @out, $1;
717             }
718             }
719 0           return @out;
720             }
721              
722             =head2 append_config_includes
723              
724             $ftest->append_config_includes(@c_code);
725              
726             Append custom lines of C code to the L attribute.
727             Each element of C<@c_code> will be given a trailing newline if it lacks one.
728              
729             =head2 append_config_local
730              
731             $ftest->append_config_local(@c_code);
732              
733             Append custom lines of C code to the L attribute.
734             Each element of C<@c_code> will be given a trailing newline if it lacks one.
735              
736             =cut
737              
738             sub append_config_includes {
739 0     0 1   my ($self, @c_code)= @_;
740 0           s/\n?\z/\n/ for @c_code;
741 0           $self->{config_includes} .= join '', @c_code;
742 0           $self;
743             }
744              
745             sub append_config_local {
746 0     0 1   my ($self, @c_code)= @_;
747 0           s/\n?\z/\n/ for @c_code;
748 0           $self->{config_local} .= join '', @c_code;
749 0           $self;
750             }
751              
752             =head2 write_config_header
753              
754             $ftest->write_config_header($filename);
755              
756             Write the contents of L to a file, also with a standard include-guard of
757              
758             #ifndef FILENAME_H
759             #define FILENAME_H
760             ...
761             #endif
762              
763             You should choose a filename distinct to your project.
764              
765             =cut
766              
767             sub write_config_header {
768 0     0 1   my ($self, $fname)= @_;
769 0           (my $guard_macro= uc($fname)) =~ s/\W/_/g;
770 0           _spew($fname,
771             "#ifndef $guard_macro\n"
772             ."#define $guard_macro\n\n"
773             .$self->config_header_text
774             ."\n#endif\n");
775 0           print "Wrote config to $fname\n";
776 0           return $self;
777             }
778              
779             =head2 export_deps
780              
781             $ftest->export_deps($extutils_depends_obj);
782              
783             Export the include paths, compiler flags, and linker flags required for using this into the
784             L object.
785              
786             =cut
787              
788             sub export_deps {
789 0     0 1   my ($self, $extutils_depends)= @_;
790             my @inc= (
791 0           map("-I$_", grep length, @{ $self->{include_dirs} }),
792 0           @{ $self->{extra_compiler_flags} },
  0            
793             );
794 0 0         $extutils_depends->set_inc(join ' ', @inc) if @inc;
795 0           $extutils_depends->set_libs(join ' ', @{$self->{extra_linker_flags}})
796 0 0         if @{$self->{extra_linker_flags}};
  0            
797 0           return $self;
798             }
799              
800             1;
801              
802             __END__