http://www.perlmonks.org?node_id=669488

In the Seeker of Perl Wisdom thread Changing Perl compile-time configuration settings I (indirectly) asked for the recommended method of changing Perl's compile time settings, i.e. those values given by the Config module that are allegedly set by the Configure and Makefile scripts immediatly prior to compling Perl. Apart from the monsterous man page for Config there is very little documentation on theses settings, and virtually none whatsoever on changing them. Enevitibly the recommendation is "configure, make, make install", all well and good when you have a trustworthy C++ compling environment, but alas I'm on Windows, and Windows dislikes GNU-style libraries. It's quite likely my Perl distribution was cross complied to Win32 from *nix anyway.

No. I'm not going to switch to Linux. It's not what I need Perl for. I need Perl everywhere, but that's for another Meditation, probably about running Win32 Perl off a flash drive.

Deciding the worst I could do was break my Perl installation... well a copy of my Strawberry Perl installation on my U3 flash drive. I wrote a program that's executed when I open up Command Prompt Portable U3 off my U3 drive. It goes through the three config files (CPAN's Config.pm, Perl's Config.pm and Config_heavy.pl) that seem to contain the relevant settings I wanted to change, and modifies them with basic regexes. Various sources warned me that the settings were also complied into the binary executable and that my efforts were futile. This was also reflected in ActiveState's implementation of reloc_perl.bat and ActiveState::RelocateTree to move your Perl installation to a new PREFIX path1, it's basically rather heavy handed search and replace over all the files in the Perl installation, and it also included diddling with the binary files which means you were out of luck if the new path was longer than the old path. Fortunatly it would appear that Perl on Win32 utilises environment variables and other techniques to resolve some of these options, hence my program is unlikely to break Perl or cause unusual behaviours2.

The resulting script works! I now get a completely different set of errors compling modules :) but I can see that it's more of a matter of setting up my C++ libraries better and possibly utilising PPM3 to get around particularly awkward modules. Basically it seems that the include and lib strings are either not magically passed to the compiler4, or these paths are incomplete and each sub-directory needs to be explicitly included in the various lib and include settings. *nix file systems probably get around this with symlinks or some other advanced file system magic. How did I figure that out? With my Perl-onna-stick I used cpan to install Glib which borked, the earliest error claimed that a certain header file was not found. This header file was clearly available in a subdirectory in my X:\GTK\include, adding an explicit path to this directory (X:\GTK\include\glib-2.0 I think) into my script, and install Glib gives a brand new set of errors... starting with another missing header file. This problem was partially solved by changing my program to retrieve the list of include paths from $ENV{'INCLUDE'} instead of manually crufting them into the program, this also means I now only need to maintain my %INCLUDE% environment variable. Remember this program does not stand alone, it requires the environment variables, especially $ENV{'INCLUDE'}, to be set correctly when the command prompt opens up.

Here's the program, it's been tidied up a lot since I started this meditation. It's a tad long so it's behind this

# No Shebang. Windows only script. use strict; use warnings; use File::Copy; # This config script is used to reconfigure a number of perl config fi +les, particularly CPAN's Config.pm, so that they point to the directo +ry structures on my U3 Flash drive. # Requires U3 commmand prompt which configures a bunch of really usefu +l U3 environment variables. # Version 0.01: Reconfigures CPAN's Config.pm to the 'local' path. # Version 0.02: Reconfigures Perl's Config.pm to the local path. # Version 0.03: Code cleanup. Move a few things to subs. reduced doubl +e looping. # Version 0.04: Reconfigures Config_heavy.pl # Version 0.05: Now obatains include paths from the INCLUDE environmen +t varaible, oh and some of the real idiot debugging code's gone. # Version 0.10: Final revised version. Less idiot debugging. more Perl +y style code. Freezing code until I fix includes etc. for compiling C +++ with minGW my $debug = undef; # Find, check and nofify U3_DEVICE_PATH my $u3drive = $ENV{'U3_DEVICE_PATH'} or die "HALT: U3_DEVICE_PATH is e +mpty or undefined!\n"; print "Starting U3 Strawberry Perl configuration on $u3drive\n"; # Set directories my $strawberry_dir = $u3drive."\\strawberry"; my $perl_dir = $strawberry_dir."\\perl"; my $cpanDir = $strawberry_dir."\\cpan"; my $cpanLibDir = $perl_dir."\\lib\\cpan"; my $cpanBuildDir = $cpanDir."\\build"; my $cpanSourceDir = $cpanDir."\\sources"; my $sysRoot = $ENV{"SYSTEMROOT"}; # include paths my $strawberry_include = $strawberry_dir."\\c\\include"; my @include = split ";", $ENV{'INCLUDE'}; # lib paths my $strawberry_lib = $strawberry_dir."\\c\\lib"; my $GTK_lib = $u3drive."\\GTK\\lib"; my $usr_lib = $u3drive."\\usr\\lib"; #Checking those directories are there for(($strawberry_dir, $perl_dir, $cpanDir, $cpanLibDir, $cpanBuildDir, + $cpanSourceDir, $sysRoot, $strawberry_include, $strawberry_lib, $GTK +_lib, $usr_lib, @include)){ -d or die "Error checking the directory $_ ($!)"; } my $perlConfig = $perl_dir."\\lib\\Config.pm"; print "Reconfiguring Perl, $perlConfig\n"; { # Closure used to limit scope... and my editor collapses them... my @content = load_array($perlConfig); backup ($perlConfig); open PERLCONFIG, ">", $perlConfig or die "HALT! Could not open $pe +rlConfig ($!)\n"; $strawberry_dir =~ s/\\/\\\\/g; # need to write \\ instead of \ for(@content){ s/.:\\\\strawberry/$strawberry_dir/g; print PERLCONFIG; } $strawberry_dir =~ s/\\\\/\\/g; # change it back close PERLCONFIG; } print "Done configuring Perl's Config.pm\n"; my $perl_heavy = $perl_dir."\\lib\\Config_heavy.pl"; # Config_heavy.pl is... large ~1200 lines of code and comments, print "Recongfiguring $perl_heavy\n"; { # Closure used to limit scope... and my editor collapses them... my @content = load_array($perl_heavy); backup($perl_heavy); open CONFIGHEAVY, ">", $perl_heavy or die "HALT! Could not open $p +erl_heavy ($!)\n"; my $heavy_include = join " ", @include; for (@content){ if (/^(glibpth|locincpth|xlibpth)=/){ s/'.*'/'$heavy_include'/; } if(/^strings=/){ my $strings_dir = $strawberry_include."\\string.h"; s/'.*'/'$strings_dir'/; } if(/^timeincl=/){ my $time_dir = $strawberry_include."\\time.h"; s/'.*'/'$time_dir'/; } if(/^sysman=/){ my $sysman_dir = $u3drive."\\usr\\man\\man1"; s/'.*'/'$sysman_dir'/; } if(/^loclibpth=/){ s/'.*'/'$strawberry_lib $GTK_lib $usr_lib'/; } s!.:(/|\\)strawberry!$strawberry_dir!g; print CONFIGHEAVY; } close CONFIGHEAVY; } print "Done configuring Config_heavy.pl\n"; my $cpanConfig = $cpanLibDir."\\Config.pm"; print "Reconfiguring CPAN, $cpanConfig\n"; { # Closure used to limit scope... and my editor collapses them... my @contents = load_array($cpanConfig); backup ($cpanConfig); # double those \\ to \\\\ for CPAN's Config.pm map s/\\/\\\\/g,($strawberry_dir, $perl_dir, $cpanDir, $cpanLibDir +, $cpanBuildDir, $cpanSourceDir, $sysRoot, $strawberry_include, $stra +wberry_lib, $GTK_lib, $usr_lib, @include); open CPANCONFIG, ">", $cpanConfig or die "HALT! Could not open $cp +anConfig ($!)\n"; for(@contents){ if (/build_dir\s/) { s/\[.*\]/\[$cpanBuildDir\]/; } if (/cpan_home\s/){ s/\[.*\]/\[$cpanDir\]/; } if (/\sftp\s/){ s/\[.*\]/\[$sysRoot\\\\system32\\\\ftp.exe\]/; } if (/histfile\s/){ s/\[.*\]/\[$cpanDir\\\\histfile\]/; } if (/keep_source_where\s/){ s/\[.*\]/\[$cpanSourceDir\]/; } if (/\smake\s/){ s/\[.*\]/\[$strawberry_dir\\c\\bin\\dmake.exe\]/; } if (/make_install_arg\s/){ s/\[.*\]/\[PREFIX=$perl_dir]/; } if (/makepl_arg\s/){ #Note: This one might need to be modified + further my $cpan_include = "-I".join " -I", @include; s/\[.*\]/\[PREFIX=$perl_dir LIBS=$strawberry_lib INC="$cpa +n_include"\]/; } if (/pager\s/){ s/\[.*\]/\[$sysRoot\\\\system32\\\\more.com]/; } if (/prefs_dir\s/){ s/\[.*\]/\[$cpanDir\\\\prefs]/; } if (/shell\s/){ # This one probably needs to be changed to use + the U3 command prompt s/\[.*\]/\[$sysRoot\\\\system32\\\\cmd.exe]/; } print CPANCONFIG; } close CPANCONFIG; # Undo the doubleup map s/\\\\/\\/g,($strawberry_dir, $perl_dir, $cpanDir, $cpanLibDir +, $cpanBuildDir, $cpanSourceDir, $sysRoot, $strawberry_include, $stra +wberry_lib, $GTK_lib, $usr_lib, @include); } print "Done configuring CPAN\n"; print "Done configuring U3 Strawberry Perl\n"; # Subroutines only after this # Returns a files contents in an array. No chomping we need those newl +ines. sub load_array{ my $file_name = shift; open THEFILE, "<", $file_name or die "HALT! Could not open $file_n +ame ($!)\n"; my @content = (); push @content, $_ while (<THEFILE>); close THEFILE; @content; } # Back it up! If there is no file appended .orig back it up to there, +otherwise back it up to .last sub backup { for my $original (@_){ my $backup = $original.".orig"; if (-e $backup){ $backup = $original.".last"; print "$backup of original exists, using \"$backup\" inste +ad.\n" if $debug; } else { print "$backup doesn't exist, assuming $original is the or +iginal.\n" if $debug; } unlink $backup; # yes, we don't care if this fails. copy $original, $backup or die "HALT! Could not copy to $backu +p ($!)\n"; } } }

These are the questions from this project:

Adamk is trying a different method, making self configuring scripts, which I think has potential too. I'd like to read a meditation on that sometime.


Updated: This is a semi-final version which will remain unchanged until I explore flattening my include library and using the PPM module... unless I need to reconfigure PPM's config file too.

1 Props to CountZero for pointing out reloc_perl.bat and ActiveState::RelocateTree first.

2 Thanks again to Corion for pointing this out.

3Thanks to syphilis this time

4Thanks again to syphilis for this one too.