This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
one more iteration on PerlIO_teardown prototype
[perl5.git] / configpm
index 061528c..cb6122c 100755 (executable)
--- a/configpm
+++ b/configpm
@@ -1,13 +1,55 @@
 #!./miniperl -w
+#
+# configpm
+#
+# Copyright (C) 1994, 1995, 1996 1997, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Larry Wall and others.
+#
+#
+# Regenerate the files
+#
+#    lib/Config.pm
+#    lib/Config_heavy.pl
+#    lib/Config.pod
+#    lib/Cross.pm (optionally)
+#
+# from the contents of the static files
+#
+#    Porting/Glossary
+#    myconfig.SH
+#
+# and from the contents of the Configure-generated file
+#
+#    config.sh
+#
+# It will only update Config.pm and Config_heavy.pl if the contents of
+# either file would be different. Note that *both* files are updated in
+# this case, since for example an extension makefile that has a dependency
+# on Config.pm should trigger even if only Config_heavy.pl has changed.
+
+sub usage { die <<EOF }
+usage: $0  [ options ] [ Config_file ] [ Glossary_file ]
+    --cross=PLATFORM    cross-compile for a different platform
+    --no-glossary       don't include Porting/Glossary in lib/Config.pod
+    --heavy=FILE        alternative name for lib/Config_heavy.pl
+    Config_file         alternative name for lib/Config.pm
+    Glossary_file       alternative name for Porting/Glossary
+EOF
+
+use strict;
+use vars qw(%Config $Config_SH_expanded);
+
+my $how_many_common = 22;
 
-# 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
-               );
+# 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 {($_,$_)}
@@ -15,9 +57,10 @@ my %Extensions = map {($_,$_)}
 
 # allowed opts as well as specifies default and initial values
 my %Allowed_Opts = (
-    'cross'    => '', # --cross=PALTFORM - crosscompiling for PLATFORM
-    'glossary' => 1,  # --no-glossary  - no glossary file inclusion, 
+    'cross'    => '', # --cross=PLATFORM - crosscompiling for PLATFORM
+    'glossary' => 1,  # --no-glossary  - no glossary file inclusion,
                       #                  for compactness
+    'heavy' => '',   # pathname of the Config_heavy.pl file
 );
 
 sub opts {
@@ -32,7 +75,8 @@ sub opts {
     my %opts = (%Allowed_Opts, %given_opts);
 
     for my $opt (grep {!exists $Allowed_Opts{$_}} keys %given_opts) {
-        die "option '$opt' is not recognized";
+        warn "option '$opt' is not recognized";
+       usage;
     }
     @ARGV = grep {!/^--/} @ARGV;
 
@@ -42,7 +86,7 @@ sub opts {
 
 my %Opts = opts();
 
-my $Config_PM;
+my ($Config_PM, $Config_heavy);
 my $Glossary = $ARGV[1] || 'Porting/Glossary';
 
 if ($Opts{cross}) {
@@ -54,30 +98,62 @@ if ($Opts{cross}) {
 else {
   $Config_PM = $ARGV[0] || 'lib/Config.pm';
 }
+if ($Opts{heavy}) {
+  $Config_heavy = $Opts{heavy};
+}
+else {
+  ($Config_heavy = $Config_PM) =~ s!\.pm$!_heavy.pl!;
+  die "Can't automatically determine name for Config_heavy.pl from '$Config_PM'"
+    if $Config_heavy eq $Config_PM;
+}
+
+my $config_txt;
+my $heavy_txt;
 
+$heavy_txt .= <<'ENDOFBEG';
+# 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.
 
-open CONFIG, ">$Config_PM" or die "Can't open $Config_PM: $!\n";
+package Config;
+use strict;
+# use warnings; Pulls in Carp
+# use vars pulls in Carp
+ENDOFBEG
 
-my $myver = sprintf "v%vd", $^V;
+my $myver = sprintf "%vd", $^V;
 
-printf CONFIG <<'ENDOFBEG', ($myver) x 3;
+$config_txt .= sprintf <<'ENDOFBEG', ($myver) x 3;
 # 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.
 
 package Config;
-@EXPORT = qw(%%Config);
-@EXPORT_OK = qw(myconfig config_sh config_vars config_re);
+use strict;
+# use warnings; Pulls in Carp
+# use vars pulls in Carp
+@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
 
-my %%Export_Cache = map {($_ => 1)} (@EXPORT, @EXPORT_OK);
+sub myconfig;
+sub config_sh;
+sub config_vars;
+sub config_re;
+
+my %%Export_Cache = map {($_ => 1)} (@Config::EXPORT, @Config::EXPORT_OK);
+
+our %%Config;
 
 # Define our own import method to avoid pulling in the full Exporter:
 sub import {
     my $pkg = shift;
-    @_ = @EXPORT unless @_;
+    @_ = @Config::EXPORT unless @_;
 
     my @funcs = grep $_ ne '%%Config', @_;
     my $export_Config = @funcs < @_ ? 1 : 0;
 
+    no strict 'refs';
     my $callpkg = caller(0);
     foreach my $func (@funcs) {
        die sprintf qq{"%%s" is not exported by the %%s module\n},
@@ -100,21 +176,75 @@ ENDOFBEG
 
 
 my @non_v    = ();
-my @v_fast   = ();
-my %v_fast   = ();
 my @v_others = ();
 my $in_v     = 0;
 my %Data     = ();
 
+
+my %seen_quotes;
+{
+  my ($name, $val);
+  open(CONFIG_SH, 'config.sh') || die "Can't open config.sh: $!";
+  while (<CONFIG_SH>) {
+    next if m:^#!/bin/sh:;
+
+    # Catch PERL_CONFIG_SH=true and PERL_VERSION=n line from Configure.
+    s/^(\w+)=(true|\d+)\s*$/$1='$2'\n/ or m/^(\w+)='(.*)'$/;
+    my($k, $v) = ($1, $2);
+
+    # grandfather PATCHLEVEL and SUBVERSION and CONFIG
+    if ($k) {
+       if ($k eq 'PERL_VERSION') {
+           push @v_others, "PATCHLEVEL='$v'\n";
+       }
+       elsif ($k eq 'PERL_SUBVERSION') {
+           push @v_others, "SUBVERSION='$v'\n";
+       }
+       elsif ($k eq 'PERL_CONFIG_SH') {
+           push @v_others, "CONFIG='$v'\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;
+    }
+    my $quote = $2;
+    if ($in_v) { 
+        $val .= $_;
+    }
+    else { 
+        ($name,$val) = ($1,$3); 
+    }
+    $in_v = $val !~ /$quote\n/;
+    next if $in_v;
+
+    s,/,::,g if $Extensions{$name};
+
+    $val =~ s/$quote\n?\z//;
+
+    my $line = "$name=$quote$val$quote\n";
+    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 
+# 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=";
 
@@ -125,13 +255,31 @@ sub fetch_string {
         $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($marker) + 2;
+    $start += length($key) + 3;
 
-    my $value = substr($Config_SH_expanded, $start, 
+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);
 
@@ -144,7 +292,9 @@ sub fetch_string {
        $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
@@ -154,60 +304,9 @@ EOT
 eval $fetch_string;
 die if $@;
 
-open(CONFIG_SH, 'config.sh') || die "Can't open config.sh: $!";
-while (<CONFIG_SH>) {
-    next if m:^#!/bin/sh:;
-
-    # Catch PERL_CONFIG_SH=true and PERL_VERSION=n line from Configure.
-    s/^(\w+)=(true|\d+)\s*$/$1='$2'\n/ or m/^(\w+)='(.*)'$/;
-    my($k, $v) = ($1, $2);
-
-    # grandfather PATCHLEVEL and SUBVERSION and CONFIG
-    if ($k) {
-       if ($k eq 'PERL_VERSION') {
-           push @v_others, "PATCHLEVEL='$v'\n";
-       }
-       elsif ($k eq 'PERL_SUBVERSION') {
-           push @v_others, "SUBVERSION='$v'\n";
-       }
-       elsif ($k eq 'PERL_CONFIG_SH') {
-           push @v_others, "CONFIG='$v'\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;
-
-    s,/,::,g if $Extensions{$name};
-
-    $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";
-    }
-}
-close CONFIG_SH;
-
 # 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');
@@ -224,35 +323,144 @@ if ($s == 4 || $s == 8) {
     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);
-my \$byteorder = join('', unpack('$format', pack('$f', \$i)));
+our \$byteorder = join('', unpack('$format', pack('$f', \$i)));
 EOT
 } else {
-    $byteorder_code = "my \$byteorder = '?'x$s;\n";
+    $byteorder_code = "our \$byteorder = '?'x$s;\n";
+}
+
+my @need_relocation;
+
+if (fetch_string({},'userelocatableinc')) {
+    foreach my $what (qw(prefixexp
+
+                        archlibexp
+                        html1direxp
+                        html3direxp
+                        man1direxp
+                        man3direxp
+                        privlibexp
+                        scriptdirexp
+                        sitearchexp
+                        sitebinexp
+                        sitehtml1direxp
+                        sitehtml3direxp
+                        sitelibexp
+                        siteman1direxp
+                        siteman3direxp
+                        sitescriptexp
+                        vendorarchexp
+                        vendorbinexp
+                        vendorhtml1direxp
+                        vendorhtml3direxp
+                        vendorlibexp
+                        vendorman1direxp
+                        vendorman3direxp
+                        vendorscriptexp
+
+                        siteprefixexp
+                        sitelib_stem
+                        vendorlib_stem
+
+                        installarchlib
+                        installhtml1dir
+                        installhtml3dir
+                        installman1dir
+                        installman3dir
+                        installprefix
+                        installprefixexp
+                        installprivlib
+                        installscript
+                        installsitearch
+                        installsitebin
+                        installsitehtml1dir
+                        installsitehtml3dir
+                        installsitelib
+                        installsiteman1dir
+                        installsiteman3dir
+                        installsitescript
+                        installvendorarch
+                        installvendorbin
+                        installvendorhtml1dir
+                        installvendorhtml3dir
+                        installvendorlib
+                        installvendorman1dir
+                        installvendorman3dir
+                        installvendorscript
+                        )) {
+       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) {
+    $config_txt .= $relocation_code;
+  } else {
+    $heavy_txt .= $relocation_code;
+  }
 }
 
-print CONFIG @non_v, "\n";
+$heavy_txt .= join('', @non_v) . "\n";
 
 # copy config summary format from the myconfig.SH script
-print CONFIG "our \$summary : unique = <<'!END!';\n";
+$heavy_txt .= "our \$summary = <<'!END!';\n";
 open(MYCONFIG,"<myconfig.SH") || die "open myconfig.SH failed: $!";
 1 while defined($_ = <MYCONFIG>) && !/^Summary of/;
-do { print CONFIG $_ } until !defined($_ = <MYCONFIG>) || /^\s*$/;
+do { $heavy_txt .= $_ } until !defined($_ = <MYCONFIG>) || /^\s*$/;
 close(MYCONFIG);
 
-# NB. as $summary is unique, we need to copy it in a lexical variable
-# before expanding it, because may have been made readonly if a perl
-# interpreter has been cloned.
-
-print CONFIG "\n!END!\n", $byteorder_code, <<'EOT';
+$heavy_txt .= "\n!END!\n" . <<'EOT';
 my $summary_expanded;
 
 sub myconfig {
     return $summary_expanded if $summary_expanded;
     ($summary_expanded = $summary) =~ s{\$(\w+)}
-                { my $c = $Config{$1}; defined($c) ? $c : 'undef' }ge;
+                { my $c = $Config::Config{$1}; defined($c) ? $c : 'undef' }ge;
     $summary_expanded;
 }
 
@@ -260,25 +468,54 @@ local *_ = \my $a;
 $_ = <<'!END!';
 EOT
 
-print CONFIG join("", @v_fast, sort @v_others);
+$heavy_txt .= join('', sort @v_others) . "!END!\n";
 
-print CONFIG <<'EOT';
-!END!
-s/(byteorder=)(['"]).*?\2/$1$2$byteorder$2/m;
-our $Config_SH : unique = $_;
+# Only need the dynamic byteorder code in Config.pm if 'byteorder' is one of
+# the precached keys
+if ($Common{byteorder}) {
+    $config_txt .= $byteorder_code;
+} else {
+    $heavy_txt .= $byteorder_code;
+}
 
-our $Config_SH_expanded : unique = "\n$_" . << 'EOVIRTUAL';
+if (@need_relocation) {
+$heavy_txt .= '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}) {
+$heavy_txt .= << 'EOT';
+s{^(otherlibdirs=)(['"])(.*?)\2}
+ {$1 . $2 . join ':', map {relocate_inc($_)} split ':', $3 . $2}me;
+EOT
+}
+}
+
+$heavy_txt .= <<'EOT';
+s/(byteorder=)(['"]).*?\2/$1$2$Config::byteorder$2/m;
+
+my $config_sh_len = length $_;
+
+our $Config_SH_expanded = "\n$_" . << 'EOVIRTUAL';
 EOT
 
 foreach my $prefix (qw(ccflags ldflags)) {
     my $value = fetch_string ({}, $prefix);
     my $withlargefiles = fetch_string ({}, $prefix . "_uselargefiles");
-    $value =~ s/\Q$withlargefiles\E\b//;
-    print CONFIG "${prefix}_nolargefiles='$value'\n";
+    if (defined $withlargefiles) {
+        $value =~ s/\Q$withlargefiles\E\b//;
+        $heavy_txt .= "${prefix}_nolargefiles='$value'\n";
+    }
 }
 
 foreach my $prefix (qw(libs libswanted)) {
     my $value = fetch_string ({}, $prefix);
+    my $withlf = fetch_string ({}, 'libswanted_uselargefiles');
+    next unless defined $withlf;
     my @lflibswanted
        = split(' ', fetch_string ({}, 'libswanted_uselargefiles'));
     if (@lflibswanted) {
@@ -295,16 +532,16 @@ foreach my $prefix (qw(libs libswanted)) {
            $value = join(' ', @libswanted);
        }
     }
-    print CONFIG "${prefix}_nolargefiles='$value'\n";
+    $heavy_txt .= "${prefix}_nolargefiles='$value'\n";
 }
 
-print CONFIG "EOVIRTUAL\n";
+$heavy_txt .= "EOVIRTUAL\n";
 
-print CONFIG $fetch_string;
+$heavy_txt .= $fetch_string;
 
-print CONFIG <<'ENDOFEND';
+$config_txt .= <<'ENDOFEND';
 
-sub FETCH { 
+sub FETCH {
     my($self, $key) = @_;
 
     # check for cached value (which may be undef so we use exists not defined)
@@ -312,32 +549,49 @@ sub FETCH {
 
     return $self->fetch_string($key);
 }
+ENDOFEND
+
+$heavy_txt .= <<'ENDOFEND';
+
 my $prevpos = 0;
 
 sub FIRSTKEY {
     $prevpos = 0;
-    substr($Config_SH_expanded, 0, index($Config_SH_expanded, '=') );
+    substr($Config_SH_expanded, 1, index($Config_SH_expanded, '=') - 1 );
 }
 
 sub NEXTKEY {
+ENDOFEND
+if ($seen_quotes{'"'}) {
+$heavy_txt .= <<'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.
+$heavy_txt .= <<'ENDOFEND';
+    my $pos = index($Config_SH_expanded, qq('\n), $prevpos) + 2;
+ENDOFEND
+}
+$heavy_txt .= <<'ENDOFEND';
     my $len = index($Config_SH_expanded, "=", $pos) - $pos;
     $prevpos = $pos;
     $len > 0 ? substr($Config_SH_expanded, $pos, $len) : undef;
 }
 
-sub EXISTS { 
+sub EXISTS {
     return 1 if exists($_[0]->{$_[1]});
 
-    return(index($Config_SH_expanded, "\n$_[1]='") != -1 or
-           substr($Config_SH_expanded, 0, length($_[1])+2) eq "$_[1]='" or
-           index($Config_SH_expanded, "\n$_[1]=\"") != -1 or
-           substr($Config_SH_expanded, 0, length($_[1])+2) eq "$_[1]=\"" or
-           $_[1] =~ /^(?:(?:cc|ld)flags|libs(?:wanted)?)_nolargefiles$/
+    return(index($Config_SH_expanded, "\n$_[1]='") != -1
+ENDOFEND
+if ($seen_quotes{'"'}) {
+$heavy_txt .= <<'ENDOFEND';
+           or index($Config_SH_expanded, "\n$_[1]=\"") != -1
+ENDOFEND
+}
+$heavy_txt .= <<'ENDOFEND';
           );
 }
 
@@ -347,7 +601,7 @@ sub STORE  { die "\%Config::Config is read-only\n" }
 
 
 sub config_sh {
-    $Config_SH
+    substr $Config_SH_expanded, 1, $config_sh_len;
 }
 
 sub config_re {
@@ -371,17 +625,25 @@ sub config_vars {
            print map "$_$lnend", @matches ? @matches : "$qry: not found"               if !$notag;
            print map { s/\w+=//; "$_$lnend" } @matches ? @matches : "$qry: not found"  if  $notag;
        } else {
-           my $v = (exists $Config{$qry}) ? $Config{$qry} : 'UNKNOWN';
+           my $v = (exists $Config::Config{$qry}) ? $Config::Config{$qry}
+                                                  : 'UNKNOWN';
            $v = 'undef' unless defined $v;
            print "${prfx}'${v}'$lnend";
        }
     }
 }
 
+# Called by the real AUTOLOAD
+sub launcher {
+    undef &AUTOLOAD;
+    goto \&$Config::AUTOLOAD;
+}
+
+1;
 ENDOFEND
 
 if ($^O eq 'os2') {
-    print CONFIG <<'ENDOFSET';
+    $config_txt .= <<'ENDOFSET';
 my %preconfig;
 if ($OS2::is_aout) {
     my ($value, $v) = $Config_SH_expanded =~ m/^used_aout='(.*)'\s*$/m;
@@ -401,30 +663,57 @@ ENDOFSET
            $dll = $1, last if /^PERL_DLL_BASE\s*=\s*(\S*)\s*$/;
        }
     }
-    print CONFIG <<ENDOFSET if $dll;
+    $config_txt .= <<ENDOFSET if $dll;
 \$preconfig{dll_name} = '$dll';
 ENDOFSET
 } else {
-    print CONFIG <<'ENDOFSET';
+    $config_txt .= <<'ENDOFSET';
 sub TIEHASH {
     bless $_[1], $_[0];
 }
 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";
+}
 
-print CONFIG sprintf <<'ENDOFTIE', $fast_config;
+if ($Common{byteorder}) {
+    $Common{byteorder} = 'byteorder => $byteorder';
+}
+my $fast_config = join '', map { "    $_,\n" } sort values %Common;
+
+# Sanity check needed to stop an infite loop if Config_heavy.pl fails to define
+# &launcher for some reason (eg it got truncated)
+$config_txt .= sprintf <<'ENDOFTIE', $fast_config;
 
-# avoid Config..Exporter..UNIVERSAL search for DESTROY then AUTOLOAD
 sub DESTROY { }
 
-tie %%Config, 'Config', {
-%s
-};
+sub AUTOLOAD {
+    require 'Config_heavy.pl';
+    goto \&launcher unless $Config::AUTOLOAD =~ /launcher$/;
+    die "&Config::AUTOLOAD failed on $Config::AUTOLOAD";
+}
 
-1;
+# tie returns the object, so the value returned to require will be true.
+tie %%Config, 'Config', {
+%s};
 ENDOFTIE
 
 
@@ -550,8 +839,8 @@ ENDOFTAIL
 if ($Opts{glossary}) {
   open(GLOS, "<$Glossary") or die "Can't open $Glossary: $!";
 }
-%seen = ();
-$text = 0;
+my %seen = ();
+my $text = 0;
 $/ = '';
 
 sub process {
@@ -626,9 +915,30 @@ outside of it.
 
 ENDOFTAIL
 
-close(CONFIG);
-close(GLOS);
+close(GLOS) if $Opts{glossary};
 close(CONFIG_POD);
+print "written lib/Config.pod\n";
+
+my $orig_config_txt = "";
+my $orig_heavy_txt = "";
+{
+    local $/;
+    my $fh;
+    $orig_config_txt = <$fh> if open $fh, "<", $Config_PM;
+    $orig_heavy_txt  = <$fh> if open $fh, "<", $Config_heavy;
+}
+
+if ($orig_config_txt ne $config_txt or $orig_heavy_txt ne $heavy_txt) {
+    open CONFIG, ">", $Config_PM or die "Can't open $Config_PM: $!\n";
+    open CONFIG_HEAVY, ">", $Config_heavy or die "Can't open $Config_heavy: $!\n";
+    print CONFIG $config_txt;
+    print CONFIG_HEAVY $heavy_txt;
+    close(CONFIG_HEAVY);
+    close(CONFIG);
+    print "updated $Config_PM\n";
+    print "updated $Config_heavy\n";
+}
+
 
 # Now create Cross.pm if needed
 if ($Opts{cross}) {
@@ -655,11 +965,15 @@ EOS
   $cross =~ s/\*\*\*replace-marker\*\*\*/$Opts{cross}/g;
   print CROSS $cross;
   close CROSS;
+  print "written lib/Cross.pm\n";
+  unshift(@INC,"xlib/$Opts{cross}");
 }
 
 # Now do some simple tests on the Config.pm file we have created
 unshift(@INC,'lib');
+unshift(@INC,'xlib/symbian') if $Opts{cross};
 require $Config_PM;
+require $Config_heavy;
 import Config;
 
 die "$0: $Config_PM not valid"
@@ -677,3 +991,106 @@ die "$0: error processing $Config_PM"
 
 
 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