use strict;
use vars qw(%Config $Config_SH_expanded);
-# commonly used names to put first (and hence lookup fastest)
-my %Common = map {($_,$_)}
- qw(archname osname osvers prefix libs libpth
- dynamic_ext static_ext dlsrc so
- cc ccflags cppflags
- privlibexp archlibexp installprivlib installarchlib
- sharpbang startsh shsharp
- );
+my $how_many_common = 22;
+
+# commonly used names to precache (and hence lookup fastest)
+my %Common;
+
+while ($how_many_common--) {
+ $_ = <DATA>;
+ chomp;
+ /^(\S+):\s*(\d+)$/ or die "Malformed line '$_'";
+ $Common{$1} = $1;
+}
# names of things which may need to have slashes changed to double-colons
my %Extensions = map {($_,$_)}
@Config::EXPORT = qw(%%Config);
@Config::EXPORT_OK = qw(myconfig config_sh config_vars config_re);
+# Need to stub all the functions to make code such as print Config::config_sh
+# keep working
+
+sub myconfig;
+sub config_sh;
+sub config_vars;
+sub config_re;
+
my %%Export_Cache = map {($_ => 1)} (@Config::EXPORT, @Config::EXPORT_OK);
our %%Config;
my @non_v = ();
-my @v_fast = ();
-my %v_fast = ();
my @v_others = ();
my $in_v = 0;
my %Data = ();
-# This is somewhat grim, but I want the code for parsing config.sh here and
-# now so that I can expand $Config{ivsize} and $Config{ivtype}
-
-my $fetch_string = <<'EOT';
-
-# Search for it in the big string
-sub fetch_string {
- my($self, $key) = @_;
-
- my $quote_type = "'";
- my $marker = "$key=";
-
- # Check for the common case, ' delimited
- my $start = index($Config_SH_expanded, "\n$marker$quote_type");
- # If that failed, check for " delimited
- if ($start == -1) {
- $quote_type = '"';
- $start = index($Config_SH_expanded, "\n$marker$quote_type");
- }
- # Start can never be -1 now, as we've rigged the long string we're
- # searching with an initial dummy newline.
- return undef if $start == -1;
-
- $start += length($marker) + 2;
-
- my $value = substr($Config_SH_expanded, $start,
- index($Config_SH_expanded, "$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\"";
- }
-
- # So we can say "if $Config{'foo'}".
- $value = undef if $value eq 'undef';
- $self->{$key} = $value; # cache it
-}
-EOT
-
-eval $fetch_string;
-die if $@;
+my %seen_quotes;
{
my ($name, $val);
open(CONFIG_SH, 'config.sh') || die "Can't open config.sh: $!";
$val =~ s/$quote\n?\z//;
my $line = "$name=$quote$val$quote\n";
- if (!$Common{$name}){
- push(@v_others, $line);
- }
- else {
- push(@v_fast, $line);
- $v_fast{$name} = "'$name' => $quote$val$quote";
- }
+ push(@v_others, $line);
+ $seen_quotes{$quote}++;
}
close CONFIG_SH;
}
+# This is somewhat grim, but I want the code for parsing config.sh here and
+# now so that I can expand $Config{ivsize} and $Config{ivtype}
+
+my $fetch_string = <<'EOT';
+
+# Search for it in the big string
+sub fetch_string {
+ my($self, $key) = @_;
+
+EOT
+
+if ($seen_quotes{'"'}) {
+ # We need the full ' and " code
+ $fetch_string .= <<'EOT';
+ my $quote_type = "'";
+ my $marker = "$key=";
+
+ # Check for the common case, ' delimited
+ my $start = index($Config_SH_expanded, "\n$marker$quote_type");
+ # If that failed, check for " delimited
+ if ($start == -1) {
+ $quote_type = '"';
+ $start = index($Config_SH_expanded, "\n$marker$quote_type");
+ }
+EOT
+} else {
+ $fetch_string .= <<'EOT';
+ # We only have ' delimted.
+ my $start = index($Config_SH_expanded, "\n$key=\'");
+EOT
+}
+$fetch_string .= <<'EOT';
+ # Start can never be -1 now, as we've rigged the long string we're
+ # searching with an initial dummy newline.
+ return undef if $start == -1;
+
+ $start += length($key) + 3;
+
+EOT
+if (!$seen_quotes{'"'}) {
+ # Don't need the full ' and " code, or the eval expansion.
+ $fetch_string .= <<'EOT';
+ my $value = substr($Config_SH_expanded, $start,
+ index($Config_SH_expanded, "'\n", $start)
+ - $start);
+EOT
+} else {
+ $fetch_string .= <<'EOT';
+ my $value = substr($Config_SH_expanded, $start,
+ index($Config_SH_expanded, "$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\"";
+ }
+EOT
+}
+$fetch_string .= <<'EOT';
+ # So we can say "if $Config{'foo'}".
+ $value = undef if $value eq 'undef';
+ $self->{$key} = $value; # cache it
+}
+EOT
+
+eval $fetch_string;
+die if $@;
# Calculation for the keys for byteorder
# This is somewhat grim, but I need to run fetch_string here.
-our $Config_SH_expanded = join "\n", '', @v_fast, @v_others;
+our $Config_SH_expanded = join "\n", '', @v_others;
my $t = fetch_string ({}, 'ivtype');
my $s = fetch_string ({}, 'ivsize');
my $list = join ',', reverse(2..$s);
my $format = 'a'x$s;
$byteorder_code = <<"EOT";
+
my \$i = 0;
foreach my \$c ($list) { \$i |= ord(\$c); \$i <<= 8 }
\$i |= ord(1);
} else {
$byteorder_code = "our \$byteorder = '?'x$s;\n";
}
-print CONFIG $byteorder_code;
+
+my @need_relocation;
+
+if (fetch_string({},'userelocatableinc')) {
+ foreach my $what (qw(archlibexp
+ privlibexp
+ sitearchexp
+ sitelibexp
+ sitelib_stem
+ vendorarchexp
+ vendorlibexp
+ vendorlib_stem)) {
+ push @need_relocation, $what if fetch_string({}, $what) =~ m!^\.\.\./!;
+ }
+}
+
+my %need_relocation;
+@need_relocation{@need_relocation} = @need_relocation;
+
+# This can have .../ anywhere:
+if (fetch_string({}, 'otherlibdirs') =~ m!\.\.\./!) {
+ $need_relocation{otherlibdirs} = 'otherlibdirs';
+}
+
+my $relocation_code = <<'EOT';
+
+sub relocate_inc {
+ my $libdir = shift;
+ return $libdir unless $libdir =~ s!^\.\.\./!!;
+ my $prefix = $^X;
+ if ($prefix =~ s!/[^/]*$!!) {
+ while ($libdir =~ m!^\.\./!) {
+ # Loop while $libdir starts "../" and $prefix still has a trailing
+ # directory
+ last unless $prefix =~ s!/([^/]+)$!!;
+ # but bail out if the directory we picked off the end of $prefix is .
+ # or ..
+ if ($1 eq '.' or $1 eq '..') {
+ # Undo! This should be rare, hence code it this way rather than a
+ # check each time before the s!!! above.
+ $prefix = "$prefix/$1";
+ last;
+ }
+ # Remove that leading ../ and loop again
+ substr ($libdir, 0, 3, '');
+ }
+ $libdir = "$prefix/$libdir";
+ }
+ $libdir;
+}
+EOT
+
+if (%need_relocation) {
+ my $relocations_in_common;
+ # otherlibdirs only features in the hash
+ foreach (keys %need_relocation) {
+ $relocations_in_common++ if $Common{$_};
+ }
+ if ($relocations_in_common) {
+ print CONFIG $relocation_code;
+ } else {
+ print CONFIG_HEAVY $relocation_code;
+ }
+}
print CONFIG_HEAVY @non_v, "\n";
$_ = <<'!END!';
EOT
-print CONFIG_HEAVY join("", @v_fast, sort @v_others);
+print CONFIG_HEAVY join('', sort @v_others), "!END!\n";
+
+# Only need the dynamic byteorder code in Config.pm if 'byteorder' is one of
+# the precached keys
+if ($Common{byteorder}) {
+ print CONFIG $byteorder_code;
+} else {
+ print CONFIG_HEAVY $byteorder_code;
+}
+
+if (@need_relocation) {
+print CONFIG_HEAVY 'foreach my $what (qw(', join (' ', @need_relocation),
+ ")) {\n", <<'EOT';
+ s/^($what=)(['"])(.*?)\2/$1 . $2 . relocate_inc($3) . $2/me;
+}
+EOT
+# Currently it only makes sense to do the ... relocation on Unix, so there's
+# no need to emulate the "which separator for this platform" logic in perl.c -
+# ':' will always be applicable
+if ($need_relocation{otherlibdirs}) {
+print CONFIG_HEAVY << 'EOT';
+s{^(otherlibdirs=)(['"])(.*?)\2}
+ {$1 . $2 . join ':', map {relocate_inc($_)} split ':', $3 . $2}me;
+EOT
+}
+}
print CONFIG_HEAVY <<'EOT';
-!END!
s/(byteorder=)(['"]).*?\2/$1$2$Config::byteorder$2/m;
-our $Config_SH : unique = $_;
+
+my $config_sh_len = length $_;
our $Config_SH_expanded : unique = "\n$_" . << 'EOVIRTUAL';
EOT
ENDOFEND
print CONFIG_HEAVY <<'ENDOFEND';
+
my $prevpos = 0;
sub FIRSTKEY {
}
sub NEXTKEY {
+ENDOFEND
+if ($seen_quotes{'"'}) {
+print CONFIG_HEAVY <<'ENDOFEND';
# Find out how the current key's quoted so we can skip to its end.
my $quote = substr($Config_SH_expanded,
index($Config_SH_expanded, "=", $prevpos)+1, 1);
my $pos = index($Config_SH_expanded, qq($quote\n), $prevpos) + 2;
+ENDOFEND
+} else {
+ # Just ' quotes, so it's much easier.
+print CONFIG_HEAVY <<'ENDOFEND';
+ my $pos = index($Config_SH_expanded, qq('\n), $prevpos) + 2;
+ENDOFEND
+}
+print CONFIG_HEAVY <<'ENDOFEND';
my $len = index($Config_SH_expanded, "=", $pos) - $pos;
$prevpos = $pos;
$len > 0 ? substr($Config_SH_expanded, $pos, $len) : undef;
sub EXISTS {
return 1 if exists($_[0]->{$_[1]});
- return(index($Config_SH_expanded, "\n$_[1]='") != -1 or
- index($Config_SH_expanded, "\n$_[1]=\"") != -1
+ return(index($Config_SH_expanded, "\n$_[1]='") != -1
+ENDOFEND
+if ($seen_quotes{'"'}) {
+print CONFIG_HEAVY <<'ENDOFEND';
+ or index($Config_SH_expanded, "\n$_[1]=\"") != -1
+ENDOFEND
+}
+print CONFIG_HEAVY <<'ENDOFEND';
);
}
sub config_sh {
- $Config_SH
+ substr $Config_SH_expanded, 1, $config_sh_len;
}
sub config_re {
ENDOFSET
}
-my $fast_config = join '', map { " $_,\n" }
- sort values (%v_fast), 'byteorder => $byteorder' ;
+foreach my $key (keys %Common) {
+ my $value = fetch_string ({}, $key);
+ # Is it safe on the LHS of => ?
+ my $qkey = $key =~ /^[A-Za-z_][A-Za-z0-9_]*$/ ? $key : "'$key'";
+ if (defined $value) {
+ # Quote things for a '' string
+ $value =~ s!\\!\\\\!g;
+ $value =~ s!'!\\'!g;
+ $value = "'$value'";
+ if ($key eq 'otherlibdirs') {
+ $value = "join (':', map {relocate_inc(\$_)} split (':', $value))";
+ } elsif ($need_relocation{$key}) {
+ $value = "relocate_inc($value)";
+ }
+ } else {
+ $value = "undef";
+ }
+ $Common{$key} = "$qkey => $value";
+}
+
+if ($Common{byteorder}) {
+ $Common{byteorder} = 'byteorder => $byteorder';
+}
+my $fast_config = join '', map { " $_,\n" } sort values %Common;
print CONFIG sprintf <<'ENDOFTIE', $fast_config;
sub DESTROY { }
sub AUTOLOAD {
- require 'config_heavy.pl';
+ require 'Config_heavy.pl';
goto \&launcher;
die "&Config::AUTOLOAD failed on $Config::AUTOLOAD";
}
+# tie returns the object, so the value returned to require will be true.
tie %%Config, 'Config', {
-%s
-};
-
-1;
+%s};
ENDOFTIE
exit 0;
+# Popularity of various entries in %Config, based on a large build and test
+# run of code in the Fotango build system:
+__DATA__
+path_sep: 8490
+d_readlink: 7101
+d_symlink: 7101
+archlibexp: 4318
+sitearchexp: 4305
+sitelibexp: 4305
+privlibexp: 4163
+ldlibpthname: 4041
+libpth: 2134
+archname: 1591
+exe_ext: 1256
+scriptdir: 1155
+version: 1116
+useithreads: 1002
+osvers: 982
+osname: 851
+inc_version_list: 783
+dont_use_nlink: 779
+intsize: 759
+usevendorprefix: 642
+dlsrc: 624
+cc: 541
+lib_ext: 520
+so: 512
+ld: 501
+ccdlflags: 500
+ldflags: 495
+obj_ext: 495
+cccdlflags: 493
+lddlflags: 493
+ar: 492
+dlext: 492
+libc: 492
+ranlib: 492
+full_ar: 491
+vendorarchexp: 491
+vendorlibexp: 491
+installman1dir: 489
+installman3dir: 489
+installsitebin: 489
+installsiteman1dir: 489
+installsiteman3dir: 489
+installvendorman1dir: 489
+installvendorman3dir: 489
+d_flexfnam: 474
+eunicefix: 360
+d_link: 347
+installsitearch: 344
+installscript: 341
+installprivlib: 337
+binexp: 336
+installarchlib: 336
+installprefixexp: 336
+installsitelib: 336
+installstyle: 336
+installvendorarch: 336
+installvendorbin: 336
+installvendorlib: 336
+man1ext: 336
+man3ext: 336
+sh: 336
+siteprefixexp: 336
+installbin: 335
+usedl: 332
+ccflags: 285
+startperl: 232
+optimize: 231
+usemymalloc: 229
+cpprun: 228
+sharpbang: 228
+perllibs: 225
+usesfio: 224
+usethreads: 220
+perlpath: 218
+extensions: 217
+usesocks: 208
+shellflags: 198
+make: 191
+d_pwage: 189
+d_pwchange: 189
+d_pwclass: 189
+d_pwcomment: 189
+d_pwexpire: 189
+d_pwgecos: 189
+d_pwpasswd: 189
+d_pwquota: 189
+gccversion: 189
+libs: 186
+useshrplib: 186
+cppflags: 185
+ptrsize: 185
+shrpenv: 185
+static_ext: 185
+use5005threads: 185
+uselargefiles: 185
+alignbytes: 184
+byteorder: 184
+ccversion: 184
+config_args: 184
+cppminus: 184