This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
new perldelta
[perl5.git] / cpan / Config-Perl-V / V.pm
CommitLineData
4b07058c
RS
1package Config::Perl::V;
2
3use strict;
4use warnings;
5
6use Config;
7use Exporter;
8use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS);
be92c2d2 9$VERSION = "0.36";
275d368b 10@ISA = qw( Exporter );
4b07058c
RS
11@EXPORT_OK = qw( plv2hash summary myconfig signature );
12%EXPORT_TAGS = (
edd16cfc
MB
13 'all' => [ @EXPORT_OK ],
14 'sig' => [ "signature" ],
4b07058c
RS
15 );
16
17# Characteristics of this binary (from libperl):
18# Compile-time options: DEBUGGING PERL_DONT_CREATE_GVSV PERL_MALLOC_WRAP
19# USE_64_BIT_INT USE_LARGE_FILES USE_PERLIO
20
21# The list are as the perl binary has stored it in PL_bincompat_options
22# search for it in
21555490
MB
23# perl.c line 1643 S_Internals_V ()
24# perl -ne'(/^S_Internals_V/../^}/)&&s/^\s+"( .*)"/$1/ and print' perl.c
25# perl.h line 4566 PL_bincompat_options
26# perl -ne'(/^\w.*PL_bincompat/../^\w}/)&&s/^\s+"( .*)"/$1/ and print' perl.h
edd16cfc 27my %BTD = map {( $_ => 0 )} qw(
4b07058c
RS
28
29 DEBUGGING
215cc5d7 30 NO_HASH_SEED
b4ade012 31 NO_MATHOMS
3eb80770
MB
32 NO_PERL_INTERNAL_RAND_SEED
33 NO_PERL_RAND_SEED
215cc5d7 34 NO_TAINT_SUPPORT
21555490 35 PERL_BOOL_AS_CHAR
9a4196f3 36 PERL_COPY_ON_WRITE
4b07058c
RS
37 PERL_DISABLE_PMC
38 PERL_DONT_CREATE_GVSV
215cc5d7 39 PERL_EXTERNAL_GLOB
215cc5d7 40 PERL_HASH_FUNC_DJB2
215cc5d7
MB
41 PERL_HASH_FUNC_MURMUR3
42 PERL_HASH_FUNC_ONE_AT_A_TIME
43 PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
44 PERL_HASH_FUNC_ONE_AT_A_TIME_OLD
b4ade012
MB
45 PERL_HASH_FUNC_SDBM
46 PERL_HASH_FUNC_SIPHASH
47 PERL_HASH_FUNC_SUPERFAST
4b07058c
RS
48 PERL_IS_MINIPERL
49 PERL_MALLOC_WRAP
50 PERL_MEM_LOG
51 PERL_MEM_LOG_ENV
52 PERL_MEM_LOG_ENV_FD
53 PERL_MEM_LOG_NOIMPL
54 PERL_MEM_LOG_STDERR
55 PERL_MEM_LOG_TIMESTAMP
215cc5d7 56 PERL_NEW_COPY_ON_WRITE
834069b8 57 PERL_OP_PARENT
215cc5d7
MB
58 PERL_PERTURB_KEYS_DETERMINISTIC
59 PERL_PERTURB_KEYS_DISABLED
60 PERL_PERTURB_KEYS_RANDOM
4b07058c 61 PERL_PRESERVE_IVUV
be92c2d2 62 PERL_RC_STACK
4b07058c
RS
63 PERL_RELOCATABLE_INCPUSH
64 PERL_USE_DEVEL
65 PERL_USE_SAFE_PUTENV
3eb80770 66 PERL_USE_UNSHARED_KEYS_IN_LARGE_HASHES
6b3eaabc 67 SILENT_NO_TAINT_SUPPORT
4b07058c
RS
68 UNLINK_ALL_VERSIONS
69 USE_ATTRIBUTES_FOR_PERLIO
70 USE_FAST_STDIO
215cc5d7 71 USE_HASH_SEED_EXPLICIT
4b07058c 72 USE_LOCALE
215cc5d7 73 USE_LOCALE_CTYPE
9a4196f3 74 USE_NO_REGISTRY
4b07058c
RS
75 USE_PERL_ATOF
76 USE_SITECUSTOMIZE
72b2b1d9 77 USE_THREAD_SAFE_LOCALE
4b07058c
RS
78
79 DEBUG_LEAKING_SCALARS
80 DEBUG_LEAKING_SCALARS_FORK_DUMP
81 DECCRTL_SOCKETS
82 FAKE_THREADS
83 FCRYPT
84 HAS_TIMES
215cc5d7 85 HAVE_INTERP_INTERN
4b07058c
RS
86 MULTIPLICITY
87 MYMALLOC
3eb80770 88 NO_HASH_SEED
21555490 89 PERL_DEBUG_READONLY_COW
4b07058c
RS
90 PERL_DEBUG_READONLY_OPS
91 PERL_GLOBAL_STRUCT
b4ade012 92 PERL_GLOBAL_STRUCT_PRIVATE
3eb80770
MB
93 PERL_HASH_NO_SBOX32
94 PERL_HASH_USE_SBOX32
4b07058c
RS
95 PERL_IMPLICIT_CONTEXT
96 PERL_IMPLICIT_SYS
b4ade012 97 PERLIO_LAYERS
4b07058c
RS
98 PERL_MAD
99 PERL_MICRO
100 PERL_NEED_APPCTX
101 PERL_NEED_TIMESBASE
102 PERL_OLD_COPY_ON_WRITE
4b07058c
RS
103 PERL_POISON
104 PERL_SAWAMPERSAND
105 PERL_TRACK_MEMPOOL
106 PERL_USES_PL_PIDSTATUS
107 PL_OP_SLAB_ALLOC
108 THREADS_HAVE_PIDS
109 USE_64_BIT_ALL
110 USE_64_BIT_INT
111 USE_IEEE
112 USE_ITHREADS
113 USE_LARGE_FILES
114 USE_LOCALE_COLLATE
115 USE_LOCALE_NUMERIC
b4ade012 116 USE_LOCALE_TIME
4b07058c
RS
117 USE_LONG_DOUBLE
118 USE_PERLIO
6fdf23c2 119 USE_QUADMATH
4b07058c
RS
120 USE_REENTRANT_API
121 USE_SFIO
122 USE_SOCKS
123 VMS_DO_SOCKETS
124 VMS_SHORTEN_LONG_SYMBOLS
125 VMS_SYMBOL_CASE_AS_IS
126 );
127
128# These are all the keys that are
215cc5d7 129# 1. Always present in %Config - lib/Config.pm #87 tie %Config
4b07058c
RS
130# 2. Reported by 'perl -V' (the rest)
131my @config_vars = qw(
132
133 api_subversion
134 api_version
135 api_versionstring
136 archlibexp
137 dont_use_nlink
138 d_readlink
139 d_symlink
140 exe_ext
141 inc_version_list
142 ldlibpthname
143 patchlevel
144 path_sep
145 perl_patchlevel
146 privlibexp
147 scriptdir
148 sitearchexp
149 sitelibexp
150 subversion
151 usevendorprefix
152 version
153
154 git_commit_id
155 git_describe
156 git_branch
157 git_uncommitted_changes
158 git_commit_id_title
159 git_snapshot_date
160
161 package revision version_patchlevel_string
162
163 osname osvers archname
164 myuname
165 config_args
166 hint useposix d_sigaction
167 useithreads usemultiplicity
168 useperlio d_sfio uselargefiles usesocks
169 use64bitint use64bitall uselongdouble
275d368b 170 usemymalloc default_inc_excludes_dot bincompat5005
4b07058c
RS
171
172 cc ccflags
173 optimize
174 cppflags
175 ccversion gccversion gccosandvers
176 intsize longsize ptrsize doublesize byteorder
177 d_longlong longlongsize d_longdbl longdblsize
178 ivtype ivsize nvtype nvsize lseektype lseeksize
179 alignbytes prototype
180
181 ld ldflags
182 libpth
183 libs
184 perllibs
185 libc so useshrplib libperl
186 gnulibc_version
187
188 dlsrc dlext d_dlsymun ccdlflags
189 cccdlflags lddlflags
190 );
191
192my %empty_build = (
edd16cfc
MB
193 'osname' => "",
194 'stamp' => 0,
195 'options' => { %BTD },
196 'patches' => [],
4b07058c
RS
197 );
198
275d368b 199sub _make_derived {
4b07058c
RS
200 my $conf = shift;
201
edd16cfc
MB
202 for ( [ 'lseektype' => "Off_t" ],
203 [ 'myuname' => "uname" ],
204 [ 'perl_patchlevel' => "patch" ],
4b07058c 205 ) {
edd16cfc
MB
206 my ($official, $derived) = @{$_};
207 $conf->{'config'}{$derived} ||= $conf->{'config'}{$official};
208 $conf->{'config'}{$official} ||= $conf->{'config'}{$derived};
209 $conf->{'derived'}{$derived} = delete $conf->{'config'}{$derived};
4b07058c
RS
210 }
211
edd16cfc
MB
212 if (exists $conf->{'config'}{'version_patchlevel_string'} &&
213 !exists $conf->{'config'}{'api_version'}) {
214 my $vps = $conf->{'config'}{'version_patchlevel_string'};
4b07058c 215 $vps =~ s{\b revision \s+ (\S+) }{}x and
edd16cfc 216 $conf->{'config'}{'revision'} ||= $1;
4b07058c
RS
217
218 $vps =~ s{\b version \s+ (\S+) }{}x and
edd16cfc 219 $conf->{'config'}{'api_version'} ||= $1;
4b07058c 220 $vps =~ s{\b subversion \s+ (\S+) }{}x and
edd16cfc 221 $conf->{'config'}{'subversion'} ||= $1;
4b07058c 222 $vps =~ s{\b patch \s+ (\S+) }{}x and
edd16cfc 223 $conf->{'config'}{'perl_patchlevel'} ||= $1;
4b07058c
RS
224 }
225
edd16cfc
MB
226 ($conf->{'config'}{'version_patchlevel_string'} ||= join " ",
227 map { ($_, $conf->{'config'}{$_} ) }
228 grep { $conf->{'config'}{$_} }
4b07058c
RS
229 qw( api_version subversion perl_patchlevel )) =~ s/\bperl_//;
230
edd16cfc 231 $conf->{'config'}{'perl_patchlevel'} ||= ""; # 0 is not a valid patchlevel
4b07058c 232
edd16cfc
MB
233 if ($conf->{'config'}{'perl_patchlevel'} =~ m{^git\w*-([^-]+)}i) {
234 $conf->{'config'}{'git_branch'} ||= $1;
235 $conf->{'config'}{'git_describe'} ||= $conf->{'config'}{'perl_patchlevel'};
4b07058c
RS
236 }
237
edd16cfc 238 $conf->{'config'}{$_} ||= "undef" for grep m{^(?:use|def)} => @config_vars;
275d368b 239
4b07058c
RS
240 $conf;
241 } # _make_derived
242
275d368b 243sub plv2hash {
4b07058c 244 my %config;
4b07058c 245
b4ade012
MB
246 my $pv = join "\n" => @_;
247
edd16cfc
MB
248 if ($pv =~ m{^Summary of my\s+(\S+)\s+\(\s*(.*?)\s*\)}m) {
249 $config{'package'} = $1;
b4ade012 250 my $rev = $2;
edd16cfc
MB
251 $rev =~ s/^ revision \s+ (\S+) \s*//x and $config{'revision'} = $1;
252 $rev and $config{'version_patchlevel_string'} = $rev;
253 my ($rel) = $config{'package'} =~ m{perl(\d)};
b4ade012
MB
254 my ($vers, $subvers) = $rev =~ m{version\s+(\d+)\s+subversion\s+(\d+)};
255 defined $vers && defined $subvers && defined $rel and
edd16cfc 256 $config{'version'} = "$rel.$vers.$subvers";
b4ade012
MB
257 }
258
edd16cfc
MB
259 if ($pv =~ m{^\s+(Snapshot of:)\s+(\S+)}) {
260 $config{'git_commit_id_title'} = $1;
261 $config{'git_commit_id'} = $2;
b4ade012 262 }
4b07058c 263
6b3eaabc
MB
264 # these are always last on line and can have multiple quotation styles
265 for my $k (qw( ccflags ldflags lddlflags )) {
266 $pv =~ s{, \s* $k \s*=\s* (.*) \s*$}{}mx or next;
267 my $v = $1;
268 $v =~ s/\s*,\s*$//;
269 $v =~ s/^(['"])(.*)\1$/$2/;
270 $config{$k} = $v;
271 }
272
be92c2d2
YO
273 my %kv;
274 if ($pv =~ m{\S,? (?:osvers|archname)=}) { # attr is not the first on the line
275 # up to and including 5.24, a line could have multiple kv pairs
276 %kv = ($pv =~ m{\b
60df6830
MB
277 (\w+) # key
278 \s*= # assign
279 ( '\s*[^']*?\s*' # quoted value
280 | \S+[^=]*?\s*\n # unquoted running till end of line
281 | \S+ # unquoted value
282 | \s*\n # empty
283 )
be92c2d2
YO
284 (?:,?\s+|\s*\n)? # optional separator (5.8.x reports did
285 }gx); # not have a ',' between every kv pair)
286 }
287 else {
288 # as of 5.25, each kv pair is listed on its own line
289 %kv = ($pv =~ m{^
290 \s+
291 (\w+) # key
292 \s*=\s* # assign
293 (.*?) # value
294 \s*,?\s*$
295 }gmx);
296 }
297
298 while (my ($k, $v) = each %kv) {
299 $k =~ s{\s+$} {};
300 $v =~ s{\s*\n\z} {};
301 $v =~ s{,$} {};
302 $v =~ m{^'(.*)'$} and $v = $1;
303 $v =~ s{\s+$} {};
304 $config{$k} = $v;
4b07058c 305 }
b4ade012 306
4b07058c 307 my $build = { %empty_build };
b4ade012
MB
308
309 $pv =~ m{^\s+Compiled at\s+(.*)}m
edd16cfc 310 and $build->{'stamp'} = $1;
60df6830 311 $pv =~ m{^\s+Locally applied patches:(?:\s+|\n)(.*?)(?:[\s\n]+Buil[td] under)}ms
edd16cfc 312 and $build->{'patches'} = [ split m{\n+\s*}, $1 ];
60df6830 313 $pv =~ m{^\s+Compile-time options:(?:\s+|\n)(.*?)(?:[\s\n]+(?:Locally applied|Buil[td] under))}ms
edd16cfc 314 and map { $build->{'options'}{$_} = 1 } split m{\s+|\n} => $1;
b4ade012 315
edd16cfc 316 $build->{'osname'} = $config{'osname'};
b4ade012 317 $pv =~ m{^\s+Built under\s+(.*)}m
edd16cfc
MB
318 and $build->{'osname'} = $1;
319 $config{'osname'} ||= $build->{'osname'};
b4ade012 320
4b07058c 321 return _make_derived ({
edd16cfc
MB
322 'build' => $build,
323 'environment' => {},
324 'config' => \%config,
325 'derived' => {},
326 'inc' => [],
4b07058c
RS
327 });
328 } # plv2hash
329
275d368b 330sub summary {
4b07058c 331 my $conf = shift || myconfig ();
eeb5a5dc 332 ref $conf eq "HASH"
edd16cfc
MB
333 && exists $conf->{'config'}
334 && exists $conf->{'build'}
335 && ref $conf->{'config'} eq "HASH"
336 && ref $conf->{'build'} eq "HASH" or return;
4b07058c
RS
337
338 my %info = map {
edd16cfc 339 exists $conf->{'config'}{$_} ? ( $_ => $conf->{'config'}{$_} ) : () }
4b07058c
RS
340 qw( archname osname osvers revision patchlevel subversion version
341 cc ccversion gccversion config_args inc_version_list
342 d_longdbl d_longlong use64bitall use64bitint useithreads
343 uselongdouble usemultiplicity usemymalloc useperlio useshrplib
344 doublesize intsize ivsize nvsize longdblsize longlongsize lseeksize
275d368b 345 default_inc_excludes_dot
4b07058c 346 );
edd16cfc 347 $info{$_}++ for grep { $conf->{'build'}{'options'}{$_} } keys %{$conf->{'build'}{'options'}};
4b07058c
RS
348
349 return \%info;
350 } # summary
351
275d368b 352sub signature {
eeb5a5dc
CBW
353 my $no_md5 = "0" x 32;
354 my $conf = summary (shift) or return $no_md5;
355
4b07058c 356 eval { require Digest::MD5 };
eeb5a5dc
CBW
357 $@ and return $no_md5;
358
edd16cfc
MB
359 $conf->{'cc'} =~ s{.*\bccache\s+}{};
360 $conf->{'cc'} =~ s{.*[/\\]}{};
4b07058c 361
edd16cfc 362 delete $conf->{'config_args'};
4b07058c
RS
363 return Digest::MD5::md5_hex (join "\xFF" => map {
364 "$_=".(defined $conf->{$_} ? $conf->{$_} : "\xFE");
edd16cfc 365 } sort keys %{$conf});
4b07058c
RS
366 } # signature
367
275d368b 368sub myconfig {
4b07058c 369 my $args = shift;
edd16cfc
MB
370 my %args = ref $args eq "HASH" ? %{$args} :
371 ref $args eq "ARRAY" ? @{$args} : ();
4b07058c
RS
372
373 my $build = { %empty_build };
374
375 # 5.14.0 and later provide all the information without shelling out
376 my $stamp = eval { Config::compile_date () };
377 if (defined $stamp) {
378 $stamp =~ s/^Compiled at //;
edd16cfc
MB
379 $build->{'osname'} = $^O;
380 $build->{'stamp'} = $stamp;
381 $build->{'patches'} = [ Config::local_patches () ];
382 $build->{'options'}{$_} = 1 for Config::bincompat_options (),
383 Config::non_bincompat_options ();
4b07058c
RS
384 }
385 else {
386 #y $pv = qx[$^X -e"sub Config::myconfig{};" -V];
b4ade012
MB
387 my $cnf = plv2hash (qx[$^X -V]);
388
edd16cfc 389 $build->{$_} = $cnf->{'build'}{$_} for qw( osname stamp patches options );
4b07058c
RS
390 }
391
392 my @KEYS = keys %ENV;
393 my %env =
edd16cfc
MB
394 map {( $_ => $ENV{$_} )} grep m{^PERL} => @KEYS;
395 if ($args{'env'}) {
396 $env{$_} = $ENV{$_} for grep m{$args{'env'}} => @KEYS;
397 }
4b07058c
RS
398
399 my %config = map { $_ => $Config{$_} } @config_vars;
400
401 return _make_derived ({
edd16cfc
MB
402 'build' => $build,
403 'environment' => \%env,
404 'config' => \%config,
405 'derived' => {},
406 'inc' => \@INC,
4b07058c
RS
407 });
408 } # myconfig
409
4101;
411
412__END__
413
414=head1 NAME
415
416Config::Perl::V - Structured data retrieval of perl -V output
417
418=head1 SYNOPSIS
419
420 use Config::Perl::V;
421
422 my $local_config = Config::Perl::V::myconfig ();
423 print $local_config->{config}{osname};
424
425=head1 DESCRIPTION
426
427=head2 $conf = myconfig ()
428
72b2b1d9 429This function will collect the data described in L</"The hash structure"> below,
4b07058c 430and return that as a hash reference. It optionally accepts an option to
72b2b1d9 431include more entries from %ENV. See L</environment> below.
4b07058c
RS
432
433Note that this will not work on uninstalled perls when called with
434C<-I/path/to/uninstalled/perl/lib>, but it works when that path is in
435C<$PERL5LIB> or in C<$PERL5OPT>, as paths passed using C<-I> are not
436known when the C<-V> information is collected.
437
438=head2 $conf = plv2hash ($text [, ...])
439
440Convert a sole 'perl -V' text block, or list of lines, to a complete
441myconfig hash. All unknown entries are defaulted.
442
443=head2 $info = summary ([$conf])
444
445Return an arbitrary selection of the information. If no C<$conf> is
446given, C<myconfig ()> is used instead.
447
448=head2 $md5 = signature ([$conf])
449
450Return the MD5 of the info returned by C<summary ()> without the
451C<config_args> entry.
452
453If C<Digest::MD5> is not available, it return a string with only C<0>'s.
454
455=head2 The hash structure
456
457The returned hash consists of 4 parts:
458
459=over 4
460
461=item build
462
463This information is extracted from the second block that is emitted by
464C<perl -V>, and usually looks something like
465
466 Characteristics of this binary (from libperl):
467 Compile-time options: DEBUGGING USE_64_BIT_INT USE_LARGE_FILES
468 Locally applied patches:
469 defined-or
470 MAINT24637
471 Built under linux
472 Compiled at Jun 13 2005 10:44:20
473 @INC:
474 /usr/lib/perl5/5.8.7/i686-linux-64int
475 /usr/lib/perl5/5.8.7
476 /usr/lib/perl5/site_perl/5.8.7/i686-linux-64int
477 /usr/lib/perl5/site_perl/5.8.7
478 /usr/lib/perl5/site_perl
479 .
480
481or
482
483 Characteristics of this binary (from libperl):
484 Compile-time options: DEBUGGING MULTIPLICITY
485 PERL_DONT_CREATE_GVSV PERL_IMPLICIT_CONTEXT
486 PERL_MALLOC_WRAP PERL_TRACK_MEMPOOL
487 PERL_USE_SAFE_PUTENV USE_ITHREADS
488 USE_LARGE_FILES USE_PERLIO
489 USE_REENTRANT_API
490 Built under linux
491 Compiled at Jan 28 2009 15:26:59
492
493This information is not available anywhere else, including C<%Config>,
494but it is the information that is only known to the perl binary.
495
496The extracted information is stored in 5 entries in the C<build> hash:
497
498=over 4
499
500=item osname
501
502This is most likely the same as C<$Config{osname}>, and was the name
503known when perl was built. It might be different if perl was cross-compiled.
504
505The default for this field, if it cannot be extracted, is to copy
506C<$Config{osname}>. The two may be differing in casing (OpenBSD vs openbsd).
507
508=item stamp
509
510This is the time string for which the perl binary was compiled. The default
511value is 0.
512
513=item options
514
515This is a hash with all the known defines as keys. The value is either 0,
516which means unknown or unset, or 1, which means defined.
517
518=item derived
519
520As some variables are reported by a different name in the output of C<perl -V>
521than their actual name in C<%Config>, I decided to leave the C<config> entry
522as close to reality as possible, and put in the entries that might have been
523guessed by the printed output in a separate block.
524
525=item patches
526
527This is a list of optionally locally applied patches. Default is an empty list.
528
529=back
530
531=item environment
532
533By default this hash is only filled with the environment variables
534out of %ENV that start with C<PERL>, but you can pass the C<env> option
535to myconfig to get more
536
537 my $conf = Config::Perl::V::myconfig ({ env => qr/^ORACLE/ });
538 my $conf = Config::Perl::V::myconfig ([ env => qr/^ORACLE/ ]);
539
540=item config
541
542This hash is filled with the variables that C<perl -V> fills its report
543with, and it has the same variables that C<Config::myconfig> returns
544from C<%Config>.
545
546=item inc
547
548This is the list of default @INC.
549
550=back
551
552=head1 REASONING
553
554This module was written to be able to return the configuration for the
555currently used perl as deeply as needed for the CPANTESTERS framework.
556Up until now they used the output of myconfig as a single text blob,
557and so it was missing the vital binary characteristics of the running
558perl and the optional applied patches.
559
560=head1 BUGS
561
562Please feedback what is wrong
563
564=head1 TODO
565
566 * Implement retrieval functions/methods
567 * Documentation
568 * Error checking
569 * Tests
570
571=head1 AUTHOR
572
573H.Merijn Brand <h.m.brand@xs4all.nl>
574
575=head1 COPYRIGHT AND LICENSE
576
22cc837a 577Copyright (C) 2009-2023 H.Merijn Brand
4b07058c
RS
578
579This library is free software; you can redistribute it and/or modify
580it under the same terms as Perl itself.
581
582=cut