Perlbrew

Fork me on github!!

Install a sitecustomize.pl file with perlbrew

by @xdg

When perl is compiled with -Dusesitecustomize it will look for a file in the $Config{sitelib} directory called sitecustomize.pl and execute it extremely early in the life of the interpreter. (See perldoc perlrun and the -f switch for an explanation.)

Perlbrew 0.37 adds the --sitecustomize installation option to specify a Perl file to be installed as sitecustomize.pl. (Perlbrew will also set -Dusesitecustomize automatically.)

$ perlbrew install perl-5.14.2 --sitecustomize /path/to/customize.pl

This is extremely useful for doing dynamic manipulation of the environment or perl globals. In particular, it can be used to modify @INC in a more customized way than can be achieved with PERL5LIB.

Consider this usage example: A user wants to be able to install a command line perl application like App::Ack and have it be available regardless of which perl is active with Perlbrew. Further, the user would like to keep its dependencies isolated so that the Perlbrew-installed perl stays 'pure'.

A good way to install an isolated application is to use local::lib with Perlbrew:

$ perlbrew lib create ack
$ perlbrew use perl-5.14.2@ack
$ cpanm App::Ack

This installs the 'ack' program to the bin directory of the configured local library directory. If the user switches to another Perl or another local library directory, ack won't be available. The user can't run ack directly out of the local library bin directory because PERL5LIB won't be set correctly to find its dependencies.

There are many ways to solve this problem. One approach is to use a sitecustomize.pl file. The following sitecustomize.pl file checks to see if the executing script appears to be installed in a local library that follows the INSTALL_BASE convention. If so, it automatically adds the proper library path to @INC:

use strict;
use Config;
use Cwd ();
my %seen;
my @bindirs =
  grep { defined && !$seen{$_}++ } 
  map { $Config{"install". $_} }
  map { ("${_}bin", "${_}script") } "", "site", "vendor";

my $script = Cwd::realpath($0);

if ( ! grep { /\Q$script\E/ } @bindirs ) {
  my @path = split "/", $script;
  if ( @path > 2 ) { # at least /bin/foo
    pop @path; # get rid of script filename
    my $installbase = join("/", @path[0 .. $#path-1], 'lib', 'perl5');
    if ( $path[-1] eq 'bin' && -d $installbase ) {
      require lib;
      lib->import($installbase);
    }
  }
}

That lets the user switch Perlbrew perls but still run the original ack program via an alias.

$ alias ack=`which ack`
$ perlbrew use perl-5.10.2
$ ack PATTERN

The ack that is run via the alias has a shebang line (#!...) that invoke the original perl, which will run sitecustomize.pl, which will fix up @INC and then ack will run successfully, finding its dependencies in @INC.