Clarifying local::lib and cpan in Chapter 2

local::lib is highlighted in Intermediate Perl when I go through the CPAN tools in Chapter 2. Each of the tools has a slightly different set of features and I try to steal the good one. I added a local::lib to cpan so you can add the local::lib defaults for a one-shot installation process. This steals a feature from cpanm which has a --local-lib option:

% cpan -I Dancer

This version of cpan comes with v5.14, but you can always get the latest by installing App::Cpan.

AndrĂ© Philipp, who’s been submitted good corrections to Intermediate Perl, noticed a weird usage pattern. He did what local::lib suggested by setting the environment variables for his session:

export PERL_MB_OPT='--install_base /home/amelia/perl5'
export PERL_MM_OPT='INSTALL_BASE=/home/amelia/perl5'
export PERL5LIB='/home/amelia/perl5/lib/perl5/i386-linux:/home/amelia/perl5/lib/perl5'
export PATH="/home/amelia/perl5/bin:$PATH"

As session settings, cpan picks up and respects those. Actually, cpan doesn’t care about any of them, but the things it starts, such as Module::Build, do. There’s not much magic to local::lib; it merely sets environment variables.

Since AndrĂ© had set these, cpan‘s -I switch didn’t seem to do anything because he was always installing into the local::lib directories. The tools don’t care who set the environment variables as long as they are set.

If I always want to install into the local::lib directories, the session settings are fine and that’s what I should do. I, however, don’t always want to do that. In fact, I almost never want to do that. I added the -I switch for one off use assuming that I hadn’t set anything else to trigger local::lib.

The trick, then, is to manage expectations. If I map the various things a person might configure and how those interact, I found out that my -I feature might have some problems. What if I set the environment and use -I at the same time?

I’ve colored one endpoint red because I don’t know what happens there. It depends on what local::lib will do. People don’t care about that those. They have expectations about the interface. Someone used to unix tools will expect the closer settings will override distant ones. A tool will use command-line settings over environment over configuration files. That is, more transient settings override more permanent ones.

What does local::lib do in that case? I start by merely loading the module and doing nothing else. In that case, local::lib prints its settings:

% perl5.14.2 -Mlocal::lib
Attempting to create directory /Users/brian/perl5
export PERL_LOCAL_LIB_ROOT="/Users/brian/perl5";
export PERL_MB_OPT="--install_base /Users/brian/perl5";
export PERL_MM_OPT="INSTALL_BASE=/Users/brian/perl5";
export PERL5LIB="/Users/brian/perl5/lib/perl5/darwin-2level:/Users/brian/perl5/lib/perl5";
export PATH="/Users/brian/perl5/bin:$PATH";

What happens if I fool with the PERL_MM_OPT? local::lib replaces the environment variable, in all cases:

% export PERL_MM_OPT=/env/setting/perlmmopt
% perl5.14.2 -Mlocal::lib -E 'say $ENV{PERL_MM_OPT}'
% perl5.14.2 -Mlocal::lib=~brian -E 'say $ENV{PERL_MM_OPT}'

I don’t know if anyone expects this. I would have expected local::lib to use default settings already specified in the environment. The documentation doesn’t say which way it will go, although it says “On import, local::lib sets the following environment variables to appropriate values”. It doesn’t say what appropriate values are or that it replaces existing values with new ones.

There’s no reason I should really expect that, and that’s the problem with expectations. People expect different things because they have different assumptions and starting points, even if they don’t think they do. When I added that feature to cpan, I assumed it would be straightforward. I had my own assumptions, despite being the person (the author) who’s supposed to make all of that apparent.

I don’t think that local::lib is doing anything wrong. If it did it some other way, a different group of people would be confused because they would assume something else. There’s really no way to win. The best any interface can do is make it suck less.