File Coverage

blib/lib/ExtUtils/CppGuess.pm
Criterion Covered Total %
statement 74 96 77.0
branch 19 50 38.0
condition 9 27 33.3
subroutine 20 26 76.9
pod 7 8 87.5
total 129 207 62.3


line stmt bran cond sub pod time code
1             package ExtUtils::CppGuess;
2              
3 1     1   653 use strict;
  1         2  
  1         22  
4 1     1   5 use warnings;
  1         1  
  1         54  
5              
6             =head1 NAME
7              
8             ExtUtils::CppGuess - guess C++ compiler and flags
9              
10             =head1 SYNOPSIS
11              
12             With L:
13              
14             use ExtUtils::CppGuess;
15              
16             my $guess = ExtUtils::CppGuess->new;
17              
18             WriteMakefile
19             ( # MakeMaker args,
20             $guess->makemaker_options,
21             );
22              
23             With L:
24              
25             my $guess = ExtUtils::CppGuess->new;
26              
27             my $build = Module::Build->new
28             ( # Module::Build arguments
29             $guess->module_build_options,
30             );
31             $build->create_build_script;
32              
33             =head1 DESCRIPTION
34              
35             C attempts to guess the system's C++ compiler
36             that is compatible with the C compiler that your perl was built with.
37              
38             It can generate the necessary options to the L
39             constructor or to L's C
40             function.
41              
42             =head1 METHODS
43              
44             =head2 new
45              
46             Creates a new C object.
47             Takes the path to the C compiler as the C argument,
48             but falls back to the value of C<$Config{cc}>, which should
49             be what you want anyway.
50              
51             You can specify C and C
52             (as strings) which will be merged in with the auto-detected ones.
53              
54             =head2 module_build_options
55              
56             Returns the correct options to the constructor of C.
57             These are:
58              
59             extra_compiler_flags
60             extra_linker_flags
61              
62             =head2 makemaker_options
63              
64             Returns the correct options to the C function of
65             C.
66             These are:
67              
68             CCFLAGS
69             dynamic_lib => { OTHERLDFLAGS => ... }
70              
71             If you specify the extra compiler or linker flags in the
72             constructor, they'll be merged into C or
73             C respectively.
74              
75             =head2 is_gcc
76              
77             Returns true if the detected compiler is in the gcc family.
78              
79             =head2 is_msvc
80              
81             Returns true if the detected compiler is in the MS VC family.
82              
83             =head2 add_extra_compiler_flags
84              
85             Takes a string as argument that is added to the string of extra compiler
86             flags.
87              
88             =head2 add_extra_linker_flags
89              
90             Takes a string as argument that is added to the string of extra linker
91             flags.
92              
93             =head1 AUTHOR
94              
95             Mattia Barbon
96              
97             Steffen Mueller
98              
99             Tobias Leich
100              
101             =head1 COPYRIGHT AND LICENSE
102              
103             Copyright 2010, 2011 by Mattia Barbon.
104              
105             This program is free software; you can redistribute it and/or
106             modify it under the same terms as Perl itself.
107              
108             =cut
109              
110 1     1   19 use Config ();
  1         2  
  1         18  
111 1     1   4 use File::Basename qw();
  1         2  
  1         16  
112 1     1   136842 use Capture::Tiny 'capture_merged';
  1         268814  
  1         2496  
113              
114             our $VERSION = '0.11';
115              
116             sub new {
117 1     1 1 714 my( $class, %args ) = @_;
118 1         6 my $self = bless { %args }, $class;
119              
120             # Allow override of default %Config::Config; useful in testing.
121 1 50 33     15 if( ! exists $self->{config} || ! defined $self->{config} ) {
122 1         5 $self->{config} = \%Config::Config;
123             }
124              
125             # Allow a 'cc' %args. If not supplied, pull from {config}, or $Config{cc}.
126 1 50 33     12 if( ! exists $self->{cc} || ! defined $self->{cc} ) {
127             $self->{cc}
128             = exists $self->{config}{cc} && defined $self->{config}{cc}
129             ? $self->{config}{cc}
130 1 50 33     48 : $Config::Config{cc};
131             }
132              
133             # Set up osname.
134 1 50 33     12 if( ! exists $self->{os} || ! defined $self->{os} ) {
135             $self->{os}
136             = exists $self->{config}{osname} && defined $self->{config}{osname}
137             ? $self->{config}{osname}
138 1 50 33     39 : $^O;
139             }
140              
141 1         12 return $self;
142             }
143              
144             # Thus saith the law: All references to %Config::Config shall come through
145             # $self->_config. Accessors shall provide access to key components thereof.
146             # Testing shall thus grow stronger, verifying performance for platforms diverse
147             # to which access we have not.
148              
149 2     2   170 sub _config { shift->{config} }
150 1     1   4 sub _cc { shift->{cc} }
151 2     2   27 sub _os { shift->{os} }
152              
153              
154             sub guess_compiler {
155 4     4 0 8 my $self = shift;
156              
157 4 100       28 return $self->{guess} if $self->{guess};
158              
159 1 50       5 if( $self->_os =~ /^mswin/i ) {
160 0 0       0 $self->_guess_win32() or return;
161             } else {
162 1 50       5 $self->_guess_unix() or return;
163             }
164 1         12 return $self->{guess};
165             }
166              
167              
168             sub _get_cflags {
169 2     2   6 my $self = shift;
170              
171 2 50       9 $self->guess_compiler or die;
172              
173 2         14 my $cflags = ' ' . $self->_config->{ccflags};
174 2         15 $cflags .= ' ' . $self->{guess}{extra_cflags};
175             $cflags .= ' ' . $self->{extra_compiler_flags}
176 2 50       23 if defined $self->{extra_compiler_flags};
177              
178 2         65 return $cflags;
179             }
180              
181              
182             sub _get_lflags {
183 2     2   5 my $self = shift;
184              
185 2 50       10 $self->guess_compiler || die;
186              
187 2         11 my $lflags = $self->{guess}{extra_lflags};
188             $lflags .= ' ' . $self->{extra_linker_flags}
189 2 50       10 if defined $self->{extra_linker_flags};
190              
191 2         13 return $lflags;
192             }
193              
194              
195             sub makemaker_options {
196 1     1 1 536 my $self = shift;
197              
198 1         5 my $lflags = $self->_get_lflags;
199 1         11 my $cflags = $self->_get_cflags;
200              
201             return (
202 1         36 CCFLAGS => $cflags,
203             dynamic_lib => { OTHERLDFLAGS => $lflags },
204             );
205             }
206              
207              
208             sub module_build_options {
209 1     1 1 866 my $self = shift;
210              
211 1         10 my $lflags = $self->_get_lflags;
212 1         11 my $cflags = $self->_get_cflags;
213              
214             return (
215 1         20 extra_compiler_flags => $cflags,
216             extra_linker_flags => $lflags,
217             );
218             }
219              
220              
221             sub _guess_win32 {
222 0     0   0 my $self = shift;
223 0         0 my $c_compiler = $self->_cc;
224             # $c_compiler = $Config::Config{cc} if not defined $c_compiler;
225              
226 0 0       0 if( $self->_cc_is_gcc( $c_compiler ) ) {
    0          
227             $self->{guess} = {
228 0         0 extra_cflags => ' -xc++ ',
229             extra_lflags => ' -lstdc++ ',
230             };
231             } elsif( $self->_cc_is_msvc( $c_compiler ) ) {
232             $self->{guess} = {
233 0         0 extra_cflags => ' -TP -EHsc ',
234             extra_lflags => ' msvcprt.lib ',
235             };
236             } else {
237 0         0 die "Unable to determine a C++ compiler for '$c_compiler'";
238             }
239              
240 0         0 return 1;
241             }
242              
243              
244             sub _guess_unix {
245 1     1   2 my $self = shift;
246 1         5 my $c_compiler = $self->_cc;
247             # $c_compiler = $Config::Config{cc} if not defined $c_compiler;
248              
249 1 50       4 if( !$self->_cc_is_gcc( $c_compiler ) ) {
250 0         0 die "Unable to determine a C++ compiler for '$c_compiler'";
251             }
252              
253             $self->{guess} = {
254 1         24 extra_cflags => ' -xc++ ',
255             extra_lflags => ' -lstdc++ ',
256             };
257             $self->{guess}{extra_lflags} .= ' -lgcc_s'
258 1 50 33     15 if $self->_os eq 'netbsd' && $self->{guess}{extra_lflags} !~ /-lgcc_s/;
259              
260 1         11 return 1;
261             }
262              
263             # originally from Alien::wxWidgets::Utility
264             # Why was this hanging around outside of all functions, and without any other
265             # use of $quotes?
266             # my $quotes = $self->_os =~ /MSWin32/ ? '"' : "'";
267              
268             sub _capture {
269 2     2   9 my @cmd = @_;
270              
271 2     2   161 my $out = capture_merged { system(@cmd) };
  2         20100  
272 2 50       3762 $out = '' if not defined $out;
273              
274 2         72 return $out;
275             }
276              
277             # capture the output of a command that is run with piping
278             # to stdin of the command. We immediately close the pipe.
279             sub _capture_empty_stdin {
280 1     1   11 my $cmd = shift;
281             my $out = capture_merged {
282 1 50   1   7252 if ( open my $fh, '|-', $cmd ) {
283 1         16009 close $fh;
284             }
285 1         117 };
286 1 50       1709 $out = '' if not defined $out;
287              
288 1         32 return $out;
289             }
290              
291              
292             sub _cc_is_msvc {
293 0     0   0 my( $self, $cc ) = @_;
294             $self->{is_msvc}
295 0   0     0 = ($self->_os =~ /MSWin32/ and File::Basename::basename($cc) =~ /^cl/i);
296 0         0 return $self->{is_msvc};
297             }
298              
299              
300             sub _cc_is_gcc {
301 1     1   4 my( $self, $cc ) = @_;
302              
303 1         3 $self->{is_gcc} = 0;
304 1         8 my $cc_version = _capture( "$cc --version" );
305 1 50 50     58 if (
      50        
      50        
306             $cc_version =~ m/\bg(?:cc|\+\+)/i # 3.x, some 4.x
307             || scalar( _capture( "$cc" ) =~ m/\bgcc\b/i ) # 2.95
308             || scalar(_capture_empty_stdin("$cc -dM -E -") =~ /__GNUC__/) # more or less universal?
309             || scalar($cc_version =~ m/\bcc\b.*Free Software Foundation/si) # some 4.x?
310             ) {
311 1         10 $self->{is_gcc} = 1;
312             }
313              
314 1         16 return $self->{is_gcc};
315             }
316              
317              
318             sub is_gcc {
319 0     0 1   my $self = shift;
320 0 0         $self->guess_compiler || die;
321 0           return $self->{is_gcc};
322             }
323              
324             sub is_msvc {
325 0     0 1   my $self = shift;
326              
327 0 0         $self->guess_compiler || die;
328              
329 0           return $self->{is_msvc};
330             }
331              
332             sub add_extra_compiler_flags {
333 0     0 1   my( $self, $string ) = @_;
334              
335             $self->{extra_compiler_flags}
336             = defined($self->{extra_compiler_flags})
337 0 0         ? $self->{extra_compiler_flags} . ' ' . $string
338             : $string;
339             }
340              
341              
342             sub add_extra_linker_flags {
343 0     0 1   my( $self, $string ) = @_;
344             $self->{extra_linker_flags}
345             = defined($self->{extra_linker_flags})
346 0 0         ? $self->{extra_linker_flags} . ' ' . $string
347             : $string;
348             }
349              
350              
351             1;