skip to Main Content

I love the idea of local::lib. At least, I find it preferable to the default system-wide installs that cpan/perl defualts to in most every way. However, I’m having difficulties with modules that install XS and distribution upgrades to newer Perls. The instructions for local::lib call for adding this line to your .bashrc (or like file)

eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"

That executes arbitrary shell code, which is fine. You can see the code it executes by running

perl -I$HOME/perl5/lib/perl5 -Mlocal::lib

In my case it returns this code,

PATH="/home/ecarroll/perl5/bin${PATH:+:${PATH}}"; export PATH;
PERL5LIB="/home/ecarroll/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
PERL_LOCAL_LIB_ROOT="/home/ecarroll/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
PERL_MB_OPT="--install_base "/home/ecarroll/perl5""; export PERL_MB_OPT;
PERL_MM_OPT="INSTALL_BASE=/home/ecarroll/perl5"; export PERL_MM_OPT;

In the above, we’re setting the default options for the two most widely used module build systems,

We’re telling those system to install to /home/ecarroll/perl5. The rest of the command sets

  • PERL5LIB which is used in setting @INC. The @INC variable in Perl is used to resolve calls with use.
  • and, PATH which prepends the bin/ directory that local::lib installs to.

So basically, install perl modules in your home directory, and look first for files installed in your home directory.

My question is what happens when you install something that has XS? In my case, I have an XS file,

/home/ecarroll/perl5/lib/perl5/x86_64-linux-gnu-thread-multi/auto/Class/Load/XS/XS.so

This was installed, with local::lib using an earlier version of Perl. I’ve since ran a Debian dist-upgrade and got a newer version of Perl (v5.36). Now a lot of utilities produce an obtuse error about this, including ones installed through the distro itself like in my case Dist::Zilla dzil which I installed with Debian’s libdist-zilla-perl package.

$ dzil
XS.c: loadable library and perl binaries are mismatched (got first handshake key 0xeb00080, needed 0xeb80080)

Which is all a result of this module’s XS,

perl -MClass::Load::XS -e1
XS.c: loadable library and perl binaries are mismatched (got first handshake key 0xeb00080, needed 0xeb80080)

This seems like very routine use of local::lib:

  • Am I using local::lib in the way intended? What else should I be doing?
  • How is local::lib supposed to handle XS?
  • Is there a way to make local::lib support multiple versions of Perl? My distro reads and writes the XS it manages to /usr/share/perl/$PERL_VERSION. This means a dist-upgrade leaves all the XS from the old version behind. It would be nice to have local::lib install not to /home/ecarroll/perl5/lib/perl5/ but instead to /home/ecarroll/perl5/lib/perl5.30/? Note the added minor version. Then at least a dist-upgrade wouldn’t break the distribution.

3

Answers


  1. Perl doesn’t maintain ABI compatibility between versions. (5.34.x -> 5.36.y, for example.) After installing a new version of Perl, you will need to re-install modules that install themselves in arch dirs (XS modules and a few others). Might be easiest and safest to remove (rename) the local lib directory (/home/ecarroll/perl5) and start from scratch.

    That’s why I avoid using anything but distro-provided modules with distro-provided perl. The package manager ensures you always have compatible builds of the modules.

    If that’s not good enough, I recommend installing your own builds of perl instead of using local::lib. Tools like perlbrew makes this easy. You’ll still have to re-install all the modules when you install a new perl, but you’ll get the cleaner "Can’t locate" error message if you forget one.

    Login or Signup to reply.
  2. I rarely use local::lib, but I’m also a minimalist when it comes to administration. The more layers you have, the worse things get. As you see, you’re own answer (now deleted) proposes even more complexity to deal with complexity that isn’t likely appropriate for your situation.

    But, local::lib has a way to set the locations of everything. You are trying to use the same location for everything instead of changing the locations based on what you are trying to do. However, even though local::lib lets you do that, you’re likely to forget to switch things up.

    My solution is simpler. I merely install a perl for whatever I’m doing (or reuse a suitable perl). I don’t change the default locations at all. I never have to manage that. I simply call the perl I want:

    $ ls -d /usr/local/perls/*
    /usr/local/perls/perl-5.10.1    /usr/local/perls/perl-5.24.3    /usr/local/perls/perl-5.32.0
    /usr/local/perls/perl-5.12.5    /usr/local/perls/perl-5.26.1    /usr/local/perls/perl-5.32.1
    /usr/local/perls/perl-5.14.4    /usr/local/perls/perl-5.26.2    /usr/local/perls/perl-5.34.0
    /usr/local/perls/perl-5.16.3    /usr/local/perls/perl-5.28.0    /usr/local/perls/perl-5.34.1
    /usr/local/perls/perl-5.18.4    /usr/local/perls/perl-5.30.0    /usr/local/perls/perl-5.35.11
    /usr/local/perls/perl-5.20.3    /usr/local/perls/perl-5.30.1    /usr/local/perls/perl-5.36.0
    /usr/local/perls/perl-5.22.4    /usr/local/perls/perl-5.30.2    /usr/local/perls/perl-5.8.9
    

    I have various symlinks and stable path adjustments to I use the tool name and the version tag I gave it:

    % cpan5.36.0 ...
    % cpan5.32.1 ...
    

    People use all sorts of tools such as perlbrew, plenv, and now some other tool that you think might solve it. It’s a big red flag if you have to constantly create new tools to deal with the tools that you are using. I’d rather spend my time doing something else.

    Login or Signup to reply.
  3. I stand by my other answer—this is too much complexity and you should reduce that. But, lets work with that constraint. You want to use local::lib.

    The problem is that you are trying to force the same set of modules on any particular perl, no matter how it was compiled. As ikegami explained, you can’t assume that two different perls, or the same library compiled with different perls, are compatible. The version of the perls does not matter. Two different perl5.36, or any version, can be incompatible with each other.

    But local::lib gives you what you need to set the appropriate values. The module itself can supply some starter values:

    $ perl -I$HOME/perl5/lib/perl5 -Mlocal::lib
    Attempting to create directory /Users/brian/perl5
    PATH="/Users/brian/perl5/bin${PATH:+:${PATH}}"; export PATH;
    PERL5LIB="/Users/brian/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
    PERL_LOCAL_LIB_ROOT="/Users/brian/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
    PERL_MB_OPT="--install_base "/Users/brian/perl5""; export PERL_MB_OPT;
    PERL_MM_OPT="INSTALL_BASE=/Users/brian/perl5"; export PERL_MM_OPT;
    

    But, you don’t need to use those values everywhere. You can have as many sets of those variables as you like. You can have a different set for every project, every perl, or however you want to organize it. The only trick is how you select the right set.

    The synopsis of local::lib indicates that it expects you to set the appropriate value for your project:

    use FindBin;
    use local::lib "$FindBin::Bin/../support";  # app-local support library
    

    Knowing that, you can have your per-version libraries by adding $^V in the path you give to local::lib (still with the binary incompatibility problems):

    use FindBin;
    use local::lib "/my/modules/$^V"; 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search