syncing perlbrew and cpan install locations - perl

I'm using perlbrew to run a local perl in my home directory, and cpan to install new modules. However, I seem to have something configured wrong. When I use cpan it always installs libraries to the ~/perl directory, but my perlbrew is located in ~/perl5 directory. This is causing some issue with creating appropriate PERL5LIB directory, rather I should include perl or perl5 libs and in what order. I seem to keep running into chicken and the egg problem where including either first results in loading a wrong module or complaints about the wrong version used. Specifically it complains that the 5.8.8 perl version (first I installed before deciding to upgrade to a slightly-less-ancient version, and still the version of /bin/perl) conflicts with the 10.1 libraries I'm using.
I figure this can likely be fixed by updating configuration files, but I'm not sure what to change. I look at my cpan config.pm and I don't see anything defining installation direction, in fact I'm not sure how cpan knows to install locally rather then trying to install to the global cpan directory.
Can anyone point me to the appropriate configuration values I need to change to get cpan to update my perlbrew library, rather then getting two separate libraries?
Edit
Okay I'm very blind. The answer was right in my configuration file at ~/.cpan/CPAN/MyConfig.pm. I swear I looked at the file a few times, even doing a search for the word perl to hunt down any line that may point to my ~/perl directory, and yet somehow missed the blindingly obvious configuration option I was looking for...not sure how.
Anyways, once I saw it I just had to change where it pointed, which took a little trial in error. I changed this line:
'makepl_arg' => q[PREFIX=~/perl],
to
'makepl_arg' => q[PREFIX=~/perl5/perlbrew/perls/perl-5.10.1/],
which of course is the location of the perl version I'm using for perlbrew. This appears to fix my problem, and should have been easy if I wasn't blind.
I do have one annoyance, I have both this line and my PERL5LIB variables, set in ~/.bashrc, effectively hard coded to point to the perl-5.10.1 version of perllib, meaning if I decide to switch to another perl version I would need to update both references or have issues again. I'm not sure how to make cpan, or my PERL5Lib for that matter, know to infer which version of perl from the perls directory it should use. That's not too big of a problem to me, I don't think I'll be allowed to upgrade past 5.10.1 (even though I want to) so it's unlikely I'll ever change this value. Otherwise it works fine now.

Two problems.
Your CPAN is partially configured overriding the location at which it should install modules. Remove this override by clearing makepl_arg.
From within cpan:
o conf makepl_arg ""
o conf commit
From sh:
echo -e -n 'o conf makepl_arg ""\no conf commit\n' | cpan
Your PERL5LIB is telling your perl to look for modules where it shouldn't. Unset it by removing the instruction that sets it in ~/.bashrc.
You may have other problems, but we'd need to know the output of the following sh command to know for sure:
set | grep ^PERL ; echo 'o conf' | cpan | grep 'makepl_\|make_\|mbuild_'

Related

How is local::lib supposed to handle XS and different versions of Perl?

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 for Module::Build
MM is for ExtUtils::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 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.
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.
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.
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";

CPAN fails to compile C, how can I configure CCFLAGS?

I have a new FreeBSD 9.0 installation that is having trouble installing modules that require C via CPAN. It seems to be down to cc being called without -I/usr/local/include. I've tried overriding that by starting CPAN with INC="-I/usr/local/include" - while that fixes the problem for some modules, it breaks for others as it seems to be overriding any defaults set in makefiles.
I've got another box with pretty much the same setup on it (slightly older installation, but still FreeBSD 9.0), perl -V on the old box shows that ccflags contains -I/usr/local/include, whereas it doesn't on the new box.
I'm guessing this is why CPAN is calling cc without it.
Question is, how can I configure it?
The settings used by CPAN modules come from the Config module which is part of core Perl. It records the compilation options and settings used when Perl was compiled.
For whatever reason, the person compiling Perl on your new FreeBSD 9.0 installation decided not to include -I/usr/local/include.
Fighting the settings in the Config module is hard work, as you've already discovered. On the whole, it is simplest not to fight it. If you want Perl to use /usr/local/include, then compile Perl so as to do so. You'll probably want to specify -l/usr/local/lib too.
You should check whether the versions of Perl are the same or not on your two similar systems.
If it works, your best bet is probably to add it to the ccflags entry in the file returned by
perl -E'require "Config_heavy.pl"; say $INC{"Config_heavy.pl"};'
Otherwise, there is surely a means of specifying this to ExtUtis::MakeMaker and to Module::Build installers. If so, you can set this cpan using o conf makepl_arg and o conf mbuildpl_arg. (Don't forget to commit!)

Uninstall all perl modules installed by cpan

Yesterday I wanted to test some software and in the documentation it said, to install I just needed to type
cpan -i Software
I never used cpan, I just know that it is the perl package manager. (Is it..?) However, it turned out that I needed loads of dependencies, and stupid as I am, I just installed all of them. (First, I had to set up cpan which asked me lots of questions) Long story short, I just want to remove all of it again. I googled a bit, and it seems like cpan does not have an uninstall routine, especially for all the packages at once.
Can I just remove some directory or will I run into troubles?
the cpan command isn't really a package manager like apt-get is. It is more a tool that downloads and installs from CPAN (the site, or one of its mirrors). After it has finished this task it doesn't remember much about what was done before, at least not enough to remove previously installed modules, at least not reliably, cleanly or dependency-safely. (Update: After looking at App::pmuninstall, it can be used to handle dependencies, but it does so by connecting to outside (read: web) sources, which compute these separately, which is fine, but I stand by the previous statement that CPAN.pm doesn't do this.)
I used to worry about removing modules, but now I realize that most Perl modules take up so little room that I just don't worry about having a few extra modules installed that you will never use. So unless you are on a computer with a REALLY small disc, I would just let it be.
On Windows or if you are using a non-system Perl on Linux/Mac you could just remove Perl and reinstall it. I would not recommend this if you are using the system installed Perl on Linux/Mac however as you could break your OS doing this (you might be ok if you were careful, but not worth it to save a few Mb!).
In the future, you can easily install a local version of Perl using perlbrew, there are tutorials all over the web if the docs aren't sufficient (they should be). This also has the bonus of letting you play with the newest and greatest Perl versions, which your system likely doesn't come with yet. Then if you install a mountain of junk, or even break it doing something crazy, remove that version and reinstall/install a different version.
Another nice tool is cpanminus (or cpanm for short) which is a newer, more user friendly cpan tool. All the cool kids are using it.
You can uninstall individual modules with cpanplus (ships with Perl) like this:
cpanp uninstall SQL::Abstract
You can view all modules installed with the cpan script like this:
perldoc perllocal
Putting the two together:
for module in $(perldoc -u perllocal | grep -F 'C<Module> L<' | sed 's/^.*L<\(.*\)|.*>$/\1/') ; do
cpanp uninstall "$module"
done
I'm not sure about removing "all of it". But to remove a single module you can use App::pmuninstall with it's sole script pm-uninstall to uninstall modules. You might then be able to write some kind of script to recursively remove the deps.
If you can't use cpan any more because there are incompatible modules in you path, you can remove all installed modules by hand. For example, I upgraded from Fedora 22 to Fedora 23 and the Perl version changed. All modules installed previously via cpanm into /usr/local/lib64/perl5 did not work any more and prevented me from using cpanm.
$ cpanm --uninstall Apache::DBI
Attempt to reload Scalar/Util.pm aborted.
Compilation failed in require at /usr/share/perl5/vendor_perl/File/Temp.pm line 18.
...
I could solve this by moving that directory:
$ mv /usr/local/lib64/perl5 /root/usr-local-lib64-perl5
The name of that directory may vary on your system.
Carefull: If a module installed files outside of that directory, for example system library files, these files will remain there.
I will change Flimm's answer to use cpanm and optionally uninstall cpanm itself in the end of the script:
#!/usr/bin/env bash
for module in $(perldoc -u perllocal | grep -F 'C<Module> L<' | sed 's/^.*L<\(.*\)|.*>$/\1/' | sort | uniq) ; do
if [[ "$module" =~ "App::cpanminus" ]]; then
continue
fi
echo "Uninstalling $module..."
yes | cpanm --uninstall "$module"
done
cpanm --uninstall App::cpanminus
I think the best option is uninstall Perl and install it again.

How do I install a CPAN module site-wide while local::lib is present?

I've recently set up a new system and wanted to install Padre to check it out. The Padre install instructions specifically said to install local::lib, so I did so (although I've never had need of it before). I then went on my way installing several other modules, running CPAN from my normal user account with sudo to handle the root-required portions of the installation.
Then time came to test out one of the web apps these modules were needed to support and, lo and behold, apache couldn't find them. They loaded fine from the command line and a quick look in ~/perl5 confirmed my suspicion that local::lib had hijacked my CPAN sessions and installed these modules there instead of in a site-wide location, despite my CPAN config including
makepl_arg [INSTALLDIRS=site]
mbuildpl_arg [--installdirs site]
What do I need to do to my CPAN config so that modules will be installed site-wide even though local::lib is installed? Or will Padre work without it and I can just remove local::lib entirely?
(I do not want any modules installed under ~/perl5 unless Padre insists on them being there. My code under development has its own project-specific directory locations and everything else should be site-wide. I have no need for a private catch-all location.)
Got it. Per the instructions on local::lib's CPAN page, I had set export PERL_MM_OPT='INSTALL_BASE=~me/perl', which was overriding the setting in my CPAN config. A quick export PERL_MM_OPT= got me back to a proper install location.
On the one hand, that's what I get for following the instructions blindly. On the other, I would have expected o conf to show the actual config settings that are being used rather than those which are in the saved CPAN config (even if an environment variable is overriding them).
A quick export PERL_MM_OPT= got me back to a proper install location.
This didn't help me when I tried to install Starman globally. I had to edit /root/.bashrc to comment (or to delete) next lines:
export PERL_LOCAL_LIB_ROOT="$PERL_LOCAL_LIB_ROOT:/root/perl5";
export PERL_MB_OPT="--install_base /root/perl5";
export PERL_MM_OPT="INSTALL_BASE=/root/perl5";
export PERL5LIB="/root/perl5/lib/perl5:$PERL5LIB";
export PATH="/root/perl5/bin:$PATH";
Based on this comment, it seems that local::lib installs its own version of CPAN.pm. If this is the case, you may need to find the original CPAN.pm and make sure that that one is loaded when you run your CPAN shell. Something like:
perl -I /usr/lib/perl5 -MCPAN -e shell
might do it. You might also find perl -V useful to see what include path the Perl compiler is using for its modules.

How do I stop cpan from reconfiguring each time? + More

I'm running on a Mac (version 10.6.3) and am struggling to understand what is going on with my Perl installation.
I let the system do a copy from my previous mac, and I appear to have a second perl installed, which appears earlier in my path. I can't tell (or remember) if I might have installed it with fink, macports or CPAN or what.
type -a cpan
cpan is /opt/local/bin/cpan
cpan is /usr/bin/cpan
I'm seeing two oddities. (To start with!) When I run cpan, and let it configure in ~lcuff/.cpan, each time I run it, it wants to reconfigure, giving the message:
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters...
Also, when I try to install File::Find::Rule (so I can list my CPAN modules, per the FAQ) I end up with an error message that I can't decipher or Google a solution for:
Use of inherited AUTOLOAD for non-method Digest::SHA::shaopen() is deprecated at /opt/local/lib/perl5/vendor_perl/5.8.9/darwin-2level/Digest/SHA.pm line 55.
Catching error: "Can't locate auto/Digest/SHA/shaopen.al in \#INC (\#INC contains: /sw/lib/perl5 /sw/lib/perl5/darwin /opt/local/lib/perl5/site_perl/5.8.9/darwin-2level /opt/local/lib/perl5/site_perl/5.8.9 /opt/local/lib/perl5/site_perl /opt/local/lib/perl5/vendor_perl/5.8.9/darwin-2level /opt/local/lib/perl5/vendor_perl/5.8.9 /opt/local/lib/perl5/vendor_perl /opt/local/lib/perl5/5.8.9/darwin-2level /opt/local/lib/perl5/5.8.9 /Users/lcuff) at /opt/local/lib/perl5/vendor_perl/5.8.9/darwin-2level/Digest/SHA.pm line 55\cJ" at /opt/local/lib/perl5/5.8.9/CPAN.pm line 359
CPAN::shell() called at /opt/local/bin/cpan line 198
I just went through my first migration to a new Mac last week, including a switch from fink and system perl to MacPorts and custom perl, so I remember the pain all too well...
As Schwern said, /opt/local is the default install location for MacPorts; fink uses /sw.
I did encounter a similar problem with CPAN configuration, although I didn't make any attempt to determine whether it was repeatable or not.
The first time I ran CPAN config, it said that I had an existing CPAN dir at ~/.cpan and stored the configuration there.
The second time, it wanted to configure into an existing CPAN dir at ~/Library/Application Support/.cpan. I didn't feel like repeating the CPAN configuration, so I broke out, did a quick cd ~/Library/Application Support/.cpan ; rm -rf .cpan ; ln -s ~/.cpan ., and it's worked great for me since then.
Hopefully this will at least help get you pointed in the right direction.
Have a look at Perlbrew.
Perlbrew allows you to install and manage mulitple versions for Perl under your home directory at ~/perl5
Installation is easy:
curl -LO http://xrl.us/perlbrew
chmod +x perlbrew
./perlbrew install
and simply follow the instructions.
Been using it for past few months on Mac OSX and it worked like a charm!
/I3az/