418 lines
11 KiB
Plaintext
418 lines
11 KiB
Plaintext
|
#!./miniperl -w
|
||
|
|
||
|
my $config_pm = $ARGV[0] || 'lib/Config.pm';
|
||
|
my $glossary = $ARGV[1] || 'Porting/Glossary';
|
||
|
@ARGV = "./config.sh";
|
||
|
|
||
|
# list names to put first (and hence lookup fastest)
|
||
|
@fast = qw(archname osname osvers prefix libs libpth
|
||
|
dynamic_ext static_ext extensions dlsrc so
|
||
|
sig_name sig_num cc ccflags cppflags
|
||
|
privlibexp archlibexp installprivlib installarchlib
|
||
|
sharpbang startsh shsharp
|
||
|
);
|
||
|
|
||
|
# names of things which may need to have slashes changed to double-colons
|
||
|
@extensions = qw(dynamic_ext static_ext extensions known_extensions);
|
||
|
|
||
|
|
||
|
open CONFIG, ">$config_pm" or die "Can't open $config_pm: $!\n";
|
||
|
$myver = $];
|
||
|
|
||
|
print CONFIG <<"ENDOFBEG";
|
||
|
package Config;
|
||
|
use Exporter ();
|
||
|
\@ISA = (Exporter);
|
||
|
\@EXPORT = qw(%Config);
|
||
|
\@EXPORT_OK = qw(myconfig config_sh config_vars);
|
||
|
|
||
|
\$] == $myver
|
||
|
or die "Perl lib version ($myver) doesn't match executable version (\$])";
|
||
|
|
||
|
# This file was created by configpm when Perl was built. Any changes
|
||
|
# made to this file will be lost the next time perl is built.
|
||
|
|
||
|
ENDOFBEG
|
||
|
|
||
|
|
||
|
@fast{@fast} = @fast;
|
||
|
@extensions{@extensions} = @extensions;
|
||
|
@non_v=();
|
||
|
@v_fast=();
|
||
|
@v_others=();
|
||
|
$in_v = 0;
|
||
|
|
||
|
while (<>) {
|
||
|
next if m:^#!/bin/sh:;
|
||
|
# Catch CONFIG=true and PATCHLEVEL=n line from Configure.
|
||
|
s/^(\w+)=(true|\d+)\s*$/$1='$2'\n/;
|
||
|
# We can delimit things in config.sh with either ' or ".
|
||
|
unless ($in_v or m/^(\w+)=(['"])(.*\n)/){
|
||
|
push(@non_v, "#$_"); # not a name='value' line
|
||
|
next;
|
||
|
}
|
||
|
$quote = $2;
|
||
|
if ($in_v) { $val .= $_; }
|
||
|
else { ($name,$val) = ($1,$3); }
|
||
|
$in_v = $val !~ /$quote\n/;
|
||
|
next if $in_v;
|
||
|
if ($extensions{$name}) { s,/,::,g }
|
||
|
if (!$fast{$name}){ push(@v_others, "$name=$quote$val"); next; }
|
||
|
push(@v_fast,"$name=$quote$val");
|
||
|
}
|
||
|
|
||
|
foreach(@non_v){ print CONFIG $_ }
|
||
|
|
||
|
print CONFIG "\n",
|
||
|
"my \$config_sh = <<'!END!';\n",
|
||
|
join("", @v_fast, sort @v_others),
|
||
|
"!END!\n\n";
|
||
|
|
||
|
# copy config summary format from the myconfig script
|
||
|
|
||
|
print CONFIG "my \$summary = <<'!END!';\n";
|
||
|
|
||
|
open(MYCONFIG,"<myconfig") || die "open myconfig failed: $!";
|
||
|
1 while defined($_ = <MYCONFIG>) && !/^Summary of/;
|
||
|
do { print CONFIG $_ } until !defined($_ = <MYCONFIG>) || /^\s*$/;
|
||
|
close(MYCONFIG);
|
||
|
|
||
|
print CONFIG "\n!END!\n", <<'EOT';
|
||
|
my $summary_expanded = 0;
|
||
|
|
||
|
sub myconfig {
|
||
|
return $summary if $summary_expanded;
|
||
|
$summary =~ s{\$(\w+)}
|
||
|
{ my $c = $Config{$1}; defined($c) ? $c : 'undef' }ge;
|
||
|
$summary_expanded = 1;
|
||
|
$summary;
|
||
|
}
|
||
|
EOT
|
||
|
|
||
|
# ----
|
||
|
|
||
|
print CONFIG <<'ENDOFEND';
|
||
|
|
||
|
sub FETCH {
|
||
|
# check for cached value (which may be undef so we use exists not defined)
|
||
|
return $_[0]->{$_[1]} if (exists $_[0]->{$_[1]});
|
||
|
|
||
|
# Search for it in the big string
|
||
|
my($value, $start, $marker, $quote_type);
|
||
|
$marker = "$_[1]=";
|
||
|
$quote_type = "'";
|
||
|
# return undef unless (($value) = $config_sh =~ m/^$_[1]='(.*)'\s*$/m);
|
||
|
# Check for the common case, ' delimeted
|
||
|
$start = index($config_sh, "\n$marker$quote_type");
|
||
|
# If that failed, check for " delimited
|
||
|
if ($start == -1) {
|
||
|
$quote_type = '"';
|
||
|
$start = index($config_sh, "\n$marker$quote_type");
|
||
|
}
|
||
|
return undef if ( ($start == -1) && # in case it's first
|
||
|
(substr($config_sh, 0, length($marker)) ne $marker) );
|
||
|
if ($start == -1) {
|
||
|
# It's the very first thing we found. Skip $start forward
|
||
|
# and figure out the quote mark after the =.
|
||
|
$start = length($marker) + 1;
|
||
|
$quote_type = substr($config_sh, $start - 1, 1);
|
||
|
}
|
||
|
else {
|
||
|
$start += length($marker) + 2;
|
||
|
}
|
||
|
$value = substr($config_sh, $start,
|
||
|
index($config_sh, "$quote_type\n", $start) - $start);
|
||
|
|
||
|
# If we had a double-quote, we'd better eval it so escape
|
||
|
# sequences and such can be interpolated. Since the incoming
|
||
|
# value is supposed to follow shell rules and not perl rules,
|
||
|
# we escape any perl variable markers
|
||
|
if ($quote_type eq '"') {
|
||
|
$value =~ s/\$/\\\$/g;
|
||
|
$value =~ s/\@/\\\@/g;
|
||
|
eval "\$value = \"$value\"";
|
||
|
}
|
||
|
#$value = sprintf($value) if $quote_type eq '"';
|
||
|
$value = undef if $value eq 'undef'; # So we can say "if $Config{'foo'}".
|
||
|
$_[0]->{$_[1]} = $value; # cache it
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
my $prevpos = 0;
|
||
|
|
||
|
sub FIRSTKEY {
|
||
|
$prevpos = 0;
|
||
|
# my($key) = $config_sh =~ m/^(.*?)=/;
|
||
|
substr($config_sh, 0, index($config_sh, '=') );
|
||
|
# $key;
|
||
|
}
|
||
|
|
||
|
sub NEXTKEY {
|
||
|
# Find out how the current key's quoted so we can skip to its end.
|
||
|
my $quote = substr($config_sh, index($config_sh, "=", $prevpos)+1, 1);
|
||
|
my $pos = index($config_sh, qq($quote\n), $prevpos) + 2;
|
||
|
my $len = index($config_sh, "=", $pos) - $pos;
|
||
|
$prevpos = $pos;
|
||
|
$len > 0 ? substr($config_sh, $pos, $len) : undef;
|
||
|
}
|
||
|
|
||
|
sub EXISTS {
|
||
|
# exists($_[0]->{$_[1]}) or $config_sh =~ m/^$_[1]=/m;
|
||
|
exists($_[0]->{$_[1]}) or
|
||
|
index($config_sh, "\n$_[1]='") != -1 or
|
||
|
substr($config_sh, 0, length($_[1])+2) eq "$_[1]='" or
|
||
|
index($config_sh, "\n$_[1]=\"") != -1 or
|
||
|
substr($config_sh, 0, length($_[1])+2) eq "$_[1]=\"";
|
||
|
}
|
||
|
|
||
|
sub STORE { die "\%Config::Config is read-only\n" }
|
||
|
sub DELETE { &STORE }
|
||
|
sub CLEAR { &STORE }
|
||
|
|
||
|
|
||
|
sub config_sh {
|
||
|
$config_sh
|
||
|
}
|
||
|
|
||
|
sub config_re {
|
||
|
my $re = shift;
|
||
|
my @matches = ($config_sh =~ /^$re=.*\n/mg);
|
||
|
@matches ? (print @matches) : print "$re: not found\n";
|
||
|
}
|
||
|
|
||
|
sub config_vars {
|
||
|
foreach(@_){
|
||
|
config_re($_), next if /\W/;
|
||
|
my $v=(exists $Config{$_}) ? $Config{$_} : 'UNKNOWN';
|
||
|
$v='undef' unless defined $v;
|
||
|
print "$_='$v';\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ENDOFEND
|
||
|
|
||
|
if ($^O eq 'os2') {
|
||
|
print CONFIG <<'ENDOFSET';
|
||
|
my %preconfig;
|
||
|
if ($OS2::is_aout) {
|
||
|
my ($value, $v) = $config_sh =~ m/^used_aout='(.*)'\s*$/m;
|
||
|
for (split ' ', $value) {
|
||
|
($v) = $config_sh =~ m/^aout_$_='(.*)'\s*$/m;
|
||
|
$preconfig{$_} = $v eq 'undef' ? undef : $v;
|
||
|
}
|
||
|
}
|
||
|
sub TIEHASH { bless {%preconfig} }
|
||
|
ENDOFSET
|
||
|
} else {
|
||
|
print CONFIG <<'ENDOFSET';
|
||
|
sub TIEHASH { bless {} }
|
||
|
ENDOFSET
|
||
|
}
|
||
|
|
||
|
print CONFIG <<'ENDOFTAIL';
|
||
|
|
||
|
# avoid Config..Exporter..UNIVERSAL search for DESTROY then AUTOLOAD
|
||
|
sub DESTROY { }
|
||
|
|
||
|
tie %Config, 'Config';
|
||
|
|
||
|
1;
|
||
|
__END__
|
||
|
|
||
|
=head1 NAME
|
||
|
|
||
|
Config - access Perl configuration information
|
||
|
|
||
|
=head1 SYNOPSIS
|
||
|
|
||
|
use Config;
|
||
|
if ($Config{'cc'} =~ /gcc/) {
|
||
|
print "built by gcc\n";
|
||
|
}
|
||
|
|
||
|
use Config qw(myconfig config_sh config_vars);
|
||
|
|
||
|
print myconfig();
|
||
|
|
||
|
print config_sh();
|
||
|
|
||
|
config_vars(qw(osname archname));
|
||
|
|
||
|
|
||
|
=head1 DESCRIPTION
|
||
|
|
||
|
The Config module contains all the information that was available to
|
||
|
the C<Configure> program at Perl build time (over 900 values).
|
||
|
|
||
|
Shell variables from the F<config.sh> file (written by Configure) are
|
||
|
stored in the readonly-variable C<%Config>, indexed by their names.
|
||
|
|
||
|
Values stored in config.sh as 'undef' are returned as undefined
|
||
|
values. The perl C<exists> function can be used to check if a
|
||
|
named variable exists.
|
||
|
|
||
|
=over 4
|
||
|
|
||
|
=item myconfig()
|
||
|
|
||
|
Returns a textual summary of the major perl configuration values.
|
||
|
See also C<-V> in L<perlrun/Switches>.
|
||
|
|
||
|
=item config_sh()
|
||
|
|
||
|
Returns the entire perl configuration information in the form of the
|
||
|
original config.sh shell variable assignment script.
|
||
|
|
||
|
=item config_vars(@names)
|
||
|
|
||
|
Prints to STDOUT the values of the named configuration variable. Each is
|
||
|
printed on a separate line in the form:
|
||
|
|
||
|
name='value';
|
||
|
|
||
|
Names which are unknown are output as C<name='UNKNOWN';>.
|
||
|
See also C<-V:name> in L<perlrun/Switches>.
|
||
|
|
||
|
=back
|
||
|
|
||
|
=head1 EXAMPLE
|
||
|
|
||
|
Here's a more sophisticated example of using %Config:
|
||
|
|
||
|
use Config;
|
||
|
use strict;
|
||
|
|
||
|
my %sig_num;
|
||
|
my @sig_name;
|
||
|
unless($Config{sig_name} && $Config{sig_num}) {
|
||
|
die "No sigs?";
|
||
|
} else {
|
||
|
my @names = split ' ', $Config{sig_name};
|
||
|
@sig_num{@names} = split ' ', $Config{sig_num};
|
||
|
foreach (@names) {
|
||
|
$sig_name[$sig_num{$_}] ||= $_;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print "signal #17 = $sig_name[17]\n";
|
||
|
if ($sig_num{ALRM}) {
|
||
|
print "SIGALRM is $sig_num{ALRM}\n";
|
||
|
}
|
||
|
|
||
|
=head1 WARNING
|
||
|
|
||
|
Because this information is not stored within the perl executable
|
||
|
itself it is possible (but unlikely) that the information does not
|
||
|
relate to the actual perl binary which is being used to access it.
|
||
|
|
||
|
The Config module is installed into the architecture and version
|
||
|
specific library directory ($Config{installarchlib}) and it checks the
|
||
|
perl version number when loaded.
|
||
|
|
||
|
The values stored in config.sh may be either single-quoted or
|
||
|
double-quoted. Double-quoted strings are handy for those cases where you
|
||
|
need to include escape sequences in the strings. To avoid runtime variable
|
||
|
interpolation, any C<$> and C<@> characters are replaced by C<\$> and
|
||
|
C<\@>, respectively. This isn't foolproof, of course, so don't embed C<\$>
|
||
|
or C<\@> in double-quoted strings unless you're willing to deal with the
|
||
|
consequences. (The slashes will end up escaped and the C<$> or C<@> will
|
||
|
trigger variable interpolation)
|
||
|
|
||
|
=head1 GLOSSARY
|
||
|
|
||
|
Most C<Config> variables are determined by the C<Configure> script
|
||
|
on platforms supported by it (which is most UNIX platforms). Some
|
||
|
platforms have custom-made C<Config> variables, and may thus not have
|
||
|
some of the variables described below, or may have extraneous variables
|
||
|
specific to that particular port. See the port specific documentation
|
||
|
in such cases.
|
||
|
|
||
|
ENDOFTAIL
|
||
|
|
||
|
open(GLOS, "<$glossary") or die "Can't open $glossary: $!";
|
||
|
%seen = ();
|
||
|
$text = 0;
|
||
|
$/ = '';
|
||
|
|
||
|
sub process {
|
||
|
s/\A(\w*)\s+\(([\w.]+)\):\s*\n(\t?)/=item C<$1>\n\nFrom F<$2>:\n\n/m;
|
||
|
my $c = substr $1, 0, 1;
|
||
|
unless ($seen{$c}++) {
|
||
|
print CONFIG <<EOF if $text;
|
||
|
=back
|
||
|
|
||
|
EOF
|
||
|
print CONFIG <<EOF;
|
||
|
=head2 $c
|
||
|
|
||
|
=over
|
||
|
|
||
|
EOF
|
||
|
$text = 1;
|
||
|
}
|
||
|
s/n't/n\00t/g; # leave can't, won't etc untouched
|
||
|
s/^\t\s+(.*)/\n\t$1\n/gm; # Indented lines ===> paragraphs
|
||
|
s/^(?<!\n\n)\t(.*)/$1/gm; # Not indented lines ===> text
|
||
|
s{([\'\"])(?=[^\'\"\s]*[./][^\'\"\s]*\1)([^\'\"\s]+)\1}(F<$2>)g; # '.o'
|
||
|
s{([\'\"])([^\'\"\s]+)\1}(C<$2>)g; # "date" command
|
||
|
s{\'([A-Za-z_\- *=/]+)\'}(C<$1>)g; # 'ln -s'
|
||
|
s{
|
||
|
(?<! [\w./<\'\"] ) # Only standalone file names
|
||
|
(?! e \. g \. ) # Not e.g.
|
||
|
(?! \. \. \. ) # Not ...
|
||
|
(?! \d ) # Not 5.004
|
||
|
( [\w./]* [./] [\w./]* ) # Require . or / inside
|
||
|
(?<! \. (?= \s ) ) # Do not include trailing dot
|
||
|
(?! [\w/] ) # Include all of it
|
||
|
}
|
||
|
(F<$1>)xg; # /usr/local
|
||
|
s/((?<=\s)~\w*)/F<$1>/g; # ~name
|
||
|
s/(?<![.<\'\"])\b([A-Z_]{2,})\b(?![\'\"])/C<$1>/g; # UNISTD
|
||
|
s/(?<![.<\'\"])\b(?!the\b)(\w+)\s+macro\b/C<$1> macro/g; # FILE_cnt macro
|
||
|
s/n[\0]t/n't/g; # undo can't, won't damage
|
||
|
}
|
||
|
|
||
|
<GLOS>; # Skip the preamble
|
||
|
while (<GLOS>) {
|
||
|
process;
|
||
|
print CONFIG;
|
||
|
}
|
||
|
|
||
|
print CONFIG <<'ENDOFTAIL';
|
||
|
|
||
|
=back
|
||
|
|
||
|
=head1 NOTE
|
||
|
|
||
|
This module contains a good example of how to use tie to implement a
|
||
|
cache and an example of how to make a tied variable readonly to those
|
||
|
outside of it.
|
||
|
|
||
|
=cut
|
||
|
|
||
|
ENDOFTAIL
|
||
|
|
||
|
close(CONFIG);
|
||
|
close(GLOS);
|
||
|
|
||
|
# Now do some simple tests on the Config.pm file we have created
|
||
|
unshift(@INC,'lib');
|
||
|
require $config_pm;
|
||
|
import Config;
|
||
|
|
||
|
die "$0: $config_pm not valid"
|
||
|
unless $Config{'CONFIG'} eq 'true';
|
||
|
|
||
|
die "$0: error processing $config_pm"
|
||
|
if defined($Config{'an impossible name'})
|
||
|
or $Config{'CONFIG'} ne 'true' # test cache
|
||
|
;
|
||
|
|
||
|
die "$0: error processing $config_pm"
|
||
|
if eval '$Config{"cc"} = 1'
|
||
|
or eval 'delete $Config{"cc"}'
|
||
|
;
|
||
|
|
||
|
|
||
|
exit 0;
|