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,
MB
is forModule::Build
MM
is forExtUtils::MakeMaker
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 withuse
.- and,
PATH
which prepends thebin/
directory thatlocal::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 havelocal::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
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 likeperlbrew
makes this easy. You’ll still have to re-install all the modules when you install a newperl
, but you’ll get the cleaner "Can’t locate" error message if you forget one.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 thoughlocal::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:
I have various symlinks and stable path adjustments to I use the tool name and the version tag I gave it:
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.
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: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:Knowing that, you can have your per-version libraries by adding
$^V
in the path you give tolocal::lib
(still with the binary incompatibility problems):