File Coverage

blib/lib/Config/Perl/V.pm
Criterion Covered Total %
statement 110 115 95.6
branch 44 54 81.4
condition 34 58 58.6
subroutine 9 9 100.0
pod 4 4 100.0
total 201 240 83.7


line stmt bran cond sub pod time code
1             package Config::Perl::V;
2              
3 34     34   4533564 use strict;
  34         79  
  34         1521  
4 34     34   365 use warnings;
  34         69  
  34         1949  
5              
6 34     34   210 use Config;
  34         58  
  34         1412  
7 34     34   248 use Exporter;
  34         144  
  34         139835  
8             our $VERSION = "0.39";
9             our @ISA = qw( Exporter );
10             our @EXPORT_OK = qw( plv2hash summary myconfig signature );
11             our %EXPORT_TAGS = (
12             'all' => [ @EXPORT_OK ],
13             'sig' => [ "signature" ],
14             );
15              
16             # Characteristics of this binary (from libperl):
17             # Compile-time options: DEBUGGING PERL_DONT_CREATE_GVSV PERL_MALLOC_WRAP
18             # USE_64_BIT_INT USE_LARGE_FILES USE_PERLIO
19              
20             # The list are as the perl binary has stored it in PL_bincompat_options
21             # search for it in
22             # perl.c line 1643 S_Internals_V ()
23             # perl -ne'(/^S_Internals_V/../^}/)&&s/^\s+"( .*)"/$1/ and print' perl.c
24             # perl.h line 4566 PL_bincompat_options
25             # perl -ne'(/^\w.*PL_bincompat/../^\w}/)&&s/^\s+"( .*)"/$1/ and print' perl.h
26             my %BTD = map {( $_ => 0 )} qw(
27              
28             DEBUGGING
29             HAS_LONG_DOUBLE
30             HAS_STRTOLD
31             NO_HASH_SEED
32             NO_MATHOMS
33             NO_PERL_INTERNAL_RAND_SEED
34             NO_PERL_RAND_SEED
35             NO_TAINT_SUPPORT
36             PERL_BOOL_AS_CHAR
37             PERL_COPY_ON_WRITE
38             PERL_DISABLE_PMC
39             PERL_DONT_CREATE_GVSV
40             PERL_EXTERNAL_GLOB
41             PERL_HASH_FUNC_DJB2
42             PERL_HASH_FUNC_MURMUR3
43             PERL_HASH_FUNC_ONE_AT_A_TIME
44             PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
45             PERL_HASH_FUNC_ONE_AT_A_TIME_OLD
46             PERL_HASH_FUNC_SDBM
47             PERL_HASH_FUNC_SIPHASH
48             PERL_HASH_FUNC_SUPERFAST
49             PERL_IS_MINIPERL
50             PERL_MALLOC_WRAP
51             PERL_MEM_LOG
52             PERL_MEM_LOG_ENV
53             PERL_MEM_LOG_ENV_FD
54             PERL_MEM_LOG_NOIMPL
55             PERL_MEM_LOG_STDERR
56             PERL_MEM_LOG_TIMESTAMP
57             PERL_NEW_COPY_ON_WRITE
58             PERL_OP_PARENT
59             PERL_PERTURB_KEYS_DETERMINISTIC
60             PERL_PERTURB_KEYS_DISABLED
61             PERL_PERTURB_KEYS_RANDOM
62             PERL_PRESERVE_IVUV
63             PERL_RC_STACK
64             PERL_RELOCATABLE_INCPUSH
65             PERL_USE_DEVEL
66             PERL_USE_SAFE_PUTENV
67             PERL_USE_UNSHARED_KEYS_IN_LARGE_HASHES
68             SILENT_NO_TAINT_SUPPORT
69             UNLINK_ALL_VERSIONS
70             USE_ATTRIBUTES_FOR_PERLIO
71             USE_FAST_STDIO
72             USE_HASH_SEED_EXPLICIT
73             USE_LOCALE
74             USE_LOCALE_CTYPE
75             USE_NO_REGISTRY
76             USE_PERL_ATOF
77             USE_SITECUSTOMIZE
78             USE_THREAD_SAFE_LOCALE
79              
80             DEBUG_LEAKING_SCALARS
81             DEBUG_LEAKING_SCALARS_FORK_DUMP
82             DECCRTL_SOCKETS
83             FAKE_THREADS
84             FCRYPT
85             HAS_TIMES
86             HAVE_INTERP_INTERN
87             MULTIPLICITY
88             MYMALLOC
89             NO_HASH_SEED
90             PERL_DEBUG_READONLY_COW
91             PERL_DEBUG_READONLY_OPS
92             PERL_GLOBAL_STRUCT
93             PERL_GLOBAL_STRUCT_PRIVATE
94             PERL_HASH_NO_SBOX32
95             PERL_HASH_USE_SBOX32
96             PERL_IMPLICIT_CONTEXT
97             PERL_IMPLICIT_SYS
98             PERLIO_LAYERS
99             PERL_MAD
100             PERL_MICRO
101             PERL_NEED_APPCTX
102             PERL_NEED_TIMESBASE
103             PERL_OLD_COPY_ON_WRITE
104             PERL_POISON
105             PERL_SAWAMPERSAND
106             PERL_TRACK_MEMPOOL
107             PERL_USES_PL_PIDSTATUS
108             PL_OP_SLAB_ALLOC
109             THREADS_HAVE_PIDS
110             USE_64_BIT_ALL
111             USE_64_BIT_INT
112             USE_IEEE
113             USE_ITHREADS
114             USE_LARGE_FILES
115             USE_LOCALE_COLLATE
116             USE_LOCALE_NUMERIC
117             USE_LOCALE_TIME
118             USE_LONG_DOUBLE
119             USE_PERLIO
120             USE_QUADMATH
121             USE_REENTRANT_API
122             USE_SFIO
123             USE_SOCKS
124             VMS_DO_SOCKETS
125             VMS_SHORTEN_LONG_SYMBOLS
126             VMS_SYMBOL_CASE_AS_IS
127             );
128              
129             # These are all the keys that are
130             # 1. Always present in %Config - lib/Config.pm #87 tie %Config
131             # 2. Reported by 'perl -V' (the rest)
132             my @config_vars = qw(
133              
134             api_subversion
135             api_version
136             api_versionstring
137             archlibexp
138             dont_use_nlink
139             d_readlink
140             d_symlink
141             exe_ext
142             inc_version_list
143             ldlibpthname
144             patchlevel
145             path_sep
146             perl_patchlevel
147             privlibexp
148             scriptdir
149             sitearchexp
150             sitelibexp
151             subversion
152             usevendorprefix
153             version
154              
155             git_commit_id
156             git_describe
157             git_branch
158             git_uncommitted_changes
159             git_commit_id_title
160             git_snapshot_date
161              
162             package revision version_patchlevel_string
163              
164             osname osvers archname
165             myuname
166             config_args
167             hint useposix d_sigaction
168             useithreads usemultiplicity
169             useperlio d_sfio uselargefiles usesocks
170             use64bitint use64bitall uselongdouble
171             usemymalloc default_inc_excludes_dot bincompat5005
172              
173             cc ccflags
174             optimize
175             cppflags
176             ccversion gccversion gccosandvers
177             intsize longsize ptrsize doublesize byteorder
178             d_longlong longlongsize d_longdbl longdblsize
179             ivtype ivsize nvtype nvsize lseektype lseeksize
180             alignbytes prototype
181              
182             ld ldflags
183             libpth
184             libs
185             perllibs
186             libc so useshrplib libperl
187             gnulibc_version
188              
189             dlsrc dlext d_dlsymun ccdlflags
190             cccdlflags lddlflags
191             );
192              
193             my %empty_build = (
194             'osname' => "",
195             'stamp' => 0,
196             'options' => { %BTD },
197             'patches' => [],
198             );
199              
200             sub _make_derived {
201 79     79   184 my $conf = shift;
202              
203 79         435 for ( [ 'lseektype' => "Off_t" ],
204             [ 'myuname' => "uname" ],
205             [ 'perl_patchlevel' => "patch" ],
206             ) {
207 237         360 my ($official, $derived) = @{$_};
  237         559  
208 237   100     1187 $conf->{'config'}{$derived} ||= $conf->{'config'}{$official};
209 237   100     1309 $conf->{'config'}{$official} ||= $conf->{'config'}{$derived};
210 237         747 $conf->{'derived'}{$derived} = delete $conf->{'config'}{$derived};
211             }
212              
213 79 100 100     645 if (exists $conf->{'config'}{'version_patchlevel_string'} &&
214             !exists $conf->{'config'}{'api_version'}) {
215 38         159 my $vps = $conf->{'config'}{'version_patchlevel_string'};
216             $vps =~ s{\b revision \s+ (\S+) }{}x and
217 38 50 0     305 $conf->{'config'}{'revision'} ||= $1;
218              
219             $vps =~ s{\b version \s+ (\S+) }{}x and
220 38 50 33     881 $conf->{'config'}{'api_version'} ||= $1;
221             $vps =~ s{\b subversion \s+ (\S+) }{}x and
222 38 50 66     601 $conf->{'config'}{'subversion'} ||= $1;
223             $vps =~ s{\b patch \s+ (\S+) }{}x and
224 38 50 0     139 $conf->{'config'}{'perl_patchlevel'} ||= $1;
225             }
226              
227             ($conf->{'config'}{'version_patchlevel_string'} ||= join " ",
228 0         0 map { ($_, $conf->{'config'}{$_} ) }
229 79   66     494 grep { $conf->{'config'}{$_} }
  99         324  
230             qw( api_version subversion perl_patchlevel )) =~ s/\bperl_//;
231              
232 79   50     481 $conf->{'config'}{'perl_patchlevel'} ||= ""; # 0 is not a valid patchlevel
233              
234 79 50       270 if ($conf->{'config'}{'perl_patchlevel'} =~ m{^git\w*-([^-]+)}i) {
235 0   0     0 $conf->{'config'}{'git_branch'} ||= $1;
236 0   0     0 $conf->{'config'}{'git_describe'} ||= $conf->{'config'}{'perl_patchlevel'};
237             }
238              
239 79   100     4950 $conf->{'config'}{$_} ||= "undef" for grep m{^(?:use|def)} => @config_vars;
240              
241 79         1372 $conf;
242             } # _make_derived
243              
244             sub plv2hash {
245 71     71 1 6927416 my %config;
246              
247 71         1292 my $pv = join "\n" => @_;
248              
249 71 100       1032 if ($pv =~ m{^Summary of my\s+(\S+)\s+\(\s*(.*?)\s*\)}m) {
250 38         330 $config{'package'} = $1;
251 38         205 my $rev = $2;
252 38 50       459 $rev =~ s/^ revision \s+ (\S+) \s*//x and $config{'revision'} = $1;
253 38 50       210 $rev and $config{'version_patchlevel_string'} = $rev;
254 38         269 my ($rel) = $config{'package'} =~ m{perl(\d)};
255 38         287 my ($vers, $subvers) = $rev =~ m{version\s+(\d+)\s+subversion\s+(\d+)};
256             defined $vers && defined $subvers && defined $rel and
257 38 50 33     551 $config{'version'} = "$rel.$vers.$subvers";
      33        
258             }
259              
260 71 50       368 if ($pv =~ m{^\s+(Snapshot of:)\s+(\S+)}) {
261 0         0 $config{'git_commit_id_title'} = $1;
262 0         0 $config{'git_commit_id'} = $2;
263             }
264              
265             # these are always last on line and can have multiple quotation styles
266 71         236 for my $k (qw( ccflags ldflags lddlflags )) {
267 213 100       16918 $pv =~ s{, \s* $k \s*=\s* (.*) \s*$}{}mx or next;
268 45         179 my $v = $1;
269 45         214 $v =~ s/\s*,\s*$//;
270 45         205 $v =~ s/^(['"])(.*)\1$/$2/;
271 45         153 $config{$k} = $v;
272             }
273              
274 71         188 my %kv;
275 71 100       3374 if ($pv =~ m{\S,? (?:osvers|archname)=}) { # attr is not the first on the line
276             # up to and including 5.24, a line could have multiple kv pairs
277 15         7789 %kv = ($pv =~ m{\b
278             (\w+) # key
279             \s*= # assign
280             ( '\s*[^']*?\s*' # quoted value
281             | \S+[^=]*?\s*\n # unquoted running till end of line
282             | \S+ # unquoted value
283             | \s*\n # empty
284             )
285             (?:,?\s+|\s*\n)? # optional separator (5.8.x reports did
286             }gx); # not have a ',' between every kv pair)
287             }
288             else {
289             # as of 5.25, each kv pair is listed on its own line
290 56         19318 %kv = ($pv =~ m{^
291             \s+
292             (\w+) # key
293             \s*=\s* # assign
294             (.*?) # value
295             \s*,?\s*$
296             }gmx);
297             }
298              
299 71         752 while (my ($k, $v) = each %kv) {
300 2195         3617 $k =~ s{\s+$} {};
301 2195         3785 $v =~ s{\s*\n\z} {};
302 2195         3395 $v =~ s{,$} {};
303 2195 100       5389 $v =~ m{^'(.*)'$} and $v = $1;
304 2195         4267 $v =~ s{\s+$} {};
305 2195         7610 $config{$k} = $v;
306             }
307              
308 71         732 my $build = { %empty_build };
309              
310             $pv =~ m{^\s+Compiled at\s+(.*)}m
311 71 100       5442 and $build->{'stamp'} = $1;
312             $pv =~ m{^\s+Locally applied patches:(?:\s+|\n)(.*?)(?:[\s\n]+Buil[td] under)}ms
313 71 100       1351 and $build->{'patches'} = [ split m{\n+\s*}, $1 ];
314             $pv =~ m{^\s+Compile-time options:(?:\s+|\n)(.*?)(?:[\s\n]+(?:Locally applied|Buil[td] under))}ms
315 71 100       7811 and map { $build->{'options'}{$_} = 1 } split m{\s+|\n} => $1;
  793         1952  
316              
317 71         382 $build->{'osname'} = $config{'osname'};
318             $pv =~ m{^\s+Built under\s+(.*)}m
319 71 100       5145 and $build->{'osname'} = $1;
320 71   66     434 $config{'osname'} ||= $build->{'osname'};
321              
322 71         750 return _make_derived ({
323             'build' => $build,
324             'environment' => {},
325             'config' => \%config,
326             'derived' => {},
327             'inc' => [],
328             });
329             } # plv2hash
330              
331             sub summary {
332 60   66 60 1 470441 my $conf = shift || myconfig ();
333             ref $conf eq "HASH"
334             && exists $conf->{'config'}
335             && exists $conf->{'build'}
336             && ref $conf->{'config'} eq "HASH"
337 60 100 66     1336 && ref $conf->{'build'} eq "HASH" or return;
      100        
      100        
      100        
338              
339             my %info = map {
340 56 100       250 exists $conf->{'config'}{$_} ? ( $_ => $conf->{'config'}{$_} ) : () }
  1680         6619  
341             qw( archname osname osvers revision patchlevel subversion version
342             cc ccversion gccversion config_args inc_version_list
343             d_longdbl d_longlong use64bitall use64bitint useithreads
344             uselongdouble usemultiplicity usemymalloc useperlio useshrplib
345             doublesize intsize ivsize nvsize longdblsize longlongsize lseeksize
346             default_inc_excludes_dot
347             );
348 56         245 $info{$_}++ for grep { $conf->{'build'}{'options'}{$_} } keys %{$conf->{'build'}{'options'}};
  4286         7514  
  56         1311  
349              
350 56         797 return \%info;
351             } # summary
352              
353             sub signature {
354 39     39 1 3180372 my $no_md5 = "0" x 32;
355 39 100       238 my $conf = summary (shift) or return $no_md5;
356              
357 35         102 eval { require Digest::MD5 };
  35         487  
358 35 100       298 $@ and return $no_md5;
359              
360 34         194 $conf->{'cc'} =~ s{.*\bccache\s+}{};
361 34         270 $conf->{'cc'} =~ s{.*[/\\]}{};
362              
363 34         106 delete $conf->{'config_args'};
364             return Digest::MD5::md5_hex (join "\xFF" => map {
365 942 50       3718 "$_=".(defined $conf->{$_} ? $conf->{$_} : "\xFE");
366 34         88 } sort keys %{$conf});
  34         531  
367             } # signature
368              
369             sub myconfig {
370 8     8 1 238754 my $args = shift;
371 1         5 my %args = ref $args eq "HASH" ? %{$args} :
372 8 100       62 ref $args eq "ARRAY" ? @{$args} : ();
  1 100       9  
373              
374 8         46 my $build = { %empty_build };
375              
376             # 5.14.0 and later provide all the information without shelling out
377 8         18 my $stamp = eval { Config::compile_date () };
  8         199  
378 8 100       50 if (defined $stamp) {
379 3         15 $stamp =~ s/^Compiled at //;
380 3         13 $build->{'osname'} = $^O;
381 3         7 $build->{'stamp'} = $stamp;
382 3         22 $build->{'patches'} = [ Config::local_patches () ];
383 3         89 $build->{'options'}{$_} = 1 for Config::bincompat_options (),
384             Config::non_bincompat_options ();
385             }
386             else {
387             #y $pv = qx[$^X -e"sub Config::myconfig{};" -V];
388 5         2300547 my $cnf = plv2hash (qx[$^X -V]);
389              
390 5         154 $build->{$_} = $cnf->{'build'}{$_} for qw( osname stamp patches options );
391             }
392              
393 8         142 my @KEYS = keys %ENV;
394             my %env =
395 8         116 map {( $_ => $ENV{$_} )} grep m{^PERL} => @KEYS;
  32         137  
396 8 100       40 if ($args{'env'}) {
397 2         76 $env{$_} = $ENV{$_} for grep m{$args{'env'}} => @KEYS;
398             }
399              
400 8         22 my %config = map { $_ => $Config{$_} } @config_vars;
  712         15682  
401              
402 8         103 return _make_derived ({
403             'build' => $build,
404             'environment' => \%env,
405             'config' => \%config,
406             'derived' => {},
407             'inc' => \@INC,
408             });
409             } # myconfig
410              
411             1;
412              
413             __END__