How is use local::lib different from use lib? - perl

I don't understand what use local::lib does that regular use lib doesn't. Could someone explain it?

local::lib
Defaults to ~/perl5 if you don't specify a directory (while use lib; is a no-op).
Resolves relative paths to absolute paths before adding them to #INC. (lib just adds the relative path as-is.)
Expands ~ and ~user in the directory name.
Appends /lib/perl5 to the directory you specify. (So use local::lib '/foo'; is somewhat equivalent to use lib '/foo/lib/perl5';.)
Prepends DIR/bin to your PATH, so you can use scripts installed by local modules.

use lib adds a directory to your module search path (#INC). It has no effect on anything outside of the program or module which contains the use lib directive.
local::lib is intended to be used to enable a private module installation directory and, if you configure your shell environment in the way that it recommends, this private directory will be used for all Perl module installations (whether via CPAN or manual make install) and modules installed there will be made available to all Perl programs/modules run from within your local::lib-aware shell environment.

Regular use lib foo is almost as simple as:
BEGIN { unshift(#INC, foo) }
Whereas use local::lib sets many other Perl environment variables to make sure you can install modules locally, see the source.

Related

perl - package name: Can I use path from root?

I am reading documentation about use. It is the same as
BEGIN{ require Namespace::NameOfModule; }
And the perl interpreter loads the module and translate the double colon :: to system path's separator (UNIX / and WINDOWS \\, if I remember correctly). I just wondered, If I am able to load module from root. Because in that case, for example module DateTime.pm in dir /home/nickname/dir. It would be (according to double colons rule) ::home::nickname::dir, which is wrong (like it should even look like terrible package path). So how - if even - is possible to load a module from root dir? And Does the path starts from current dir by default? (That is from dir where is the perl script located in), or only from #INC dirs?
The module namespace is relative to #INC directories only. These are by default set up according to where Perl was installed, with privlib (core modules installed with Perl), sitelib (modules installed by a CPAN client), and vendorlib (modules installed by a vendor package manager), and architecture-specific versions of each of these. Additional #INC directories may be added by local::lib, and before Perl 5.26 #INC also included . (the current working directory), but this was a bad idea.
When you invoke use or require on a bareword package name, it does the translation you described (convert :: to path separator and append .pm), and then appends it to each directory in #INC until it finds a file. (It also checks for .pmc but this is rarely relevant.) The package statement inside the file is expected to match the module path used to look it up for the import component of use.
You can modify #INC manually, but it is best to do it with one of the following mechanisms, so that architecture-specific and version-specific subdirectories will be respected if present.
lib - use lib '/path/to/lib';
-I - perl -I/path/to/lib ...
PERL5LIB - env PERL5LIB=/path/to/lib perl ...
These options should only be used to insert absolute paths into #INC, since relative paths will have the same vulnerability as . used to, in that they may mean something different when the current directory is changed. To add a path relative to the script wherever it may be, lib::relative can be installed to simplify the process, or its documentation describes equivalent functionality using core modules.
use lib::relative '../lib';
Once you have added your custom location(s) to #INC, that directory will be searched first for any further use calls.
use Foo::Bar; # now checks /path/to/lib/Foo/Bar.pm first
# which should contain package Foo::Bar
Even if you could load the module like that, you'd have numerous other problems.
The module's package directive would have to be package ::home::nickname::dir::SomeModule; for import to be found.
You'd have to use ::home::nickname::dir::SomeModule->some_method to call a static method.
You'd have to use ::home::nickname::dir::SomeModule::some_sub to call a sub.
That's obviously the wrong approach.
For modules installed in a position relative to a script, use the following in the script to tell perl where to look:
use FindBin qw( $RealBin );
use lib "$RealBin/../lib"; # Or whatever.
For modules installed for any script to use, use the following environment variable:
export PERL5LIB="$HOME/dir" # Or whatever.

Perl - Use lib with perl module which have dependencies

I have a Perl script which uses the module Net::SSH::Any. Since it does not belong to the “default” Perl installation, I have to use the use lib functionality to include it in my script.
Now, I have the directory c:\lib\net\ssh\any\ on my drive and I specify this: use lib c:/lib; at the beginning of my script.
It “works”: it didn’t say that the module is missing but it says that it couldn’t locate auto/Net/SSH2/autosplit.ix and at the end no backend available at...
When I add the auto directory (containing the correct structure) in the c:\lib\ directory and launch the script, I get this error:
No backend available at...
Which is an internal error of Net::SSH::Any mentioning it could not access the backend directory (which is already included :/)
Does anyone know how to solve something like that? I hope I was clear enough.
You need to use Local::Lib.
This will let you install and load a whole bunch of libraries and their dependencies in an alternate location. I use cpanm to manage my modules and a command something like this (which I put in a wrapper script).
cpanm -L $cpandir $M --no-skip-installed
Where $cpandir is your locallibdir and $M is the module you are trying to install.
Then in your code you would specify
use local::lib '~/foo';
However, I recommend setting a PERL5LIB environment variable, which will append your custom location to #INC and make the extra use local::lib line unnecessary. You would typically edit .bashrc or .profile in your home directory with a line like:
export PERL5LIB=/home/myusername/mymods/
The issue was caused by the fact that the module was downloaded and installed on a 32bits windows but I tried to run it on a perl 64bits installation! So the Net::SSH2 required module couldn't be executed properly.
To resume:
-How to detect the issue: by executing this command: (thanks to Salva)
"perl -Ic:\lib -MNet::SSH2 -e1"
-Modules definitions in my script:
use lib 'c:\lib';

Having issues with Perl dependencies

I've taken over a project written in Perl that has a few dependencies such as Template::Toolkit, Image::ExifTool, and GD to name a few. Currently, these dependencies are built into a directory ("deps" folder) using the --prefix option in make. In the main Perl script, I have something like the following to import the necessary modules:
use File::Spec::Functions qw(catdir);
use lib "lib";
use lib catdir(qw(deps lib perl5 site_perl));
catdir is used to stray away from certain system requirements (such as assuming '/' is the folder separator; if someone has another alternative, I'm open to suggestions!). The "lib" folder contains my modules, and the "deps/lib/perl5/site_perl" folder is where my dependencies were installed on my original machine.
However, after building the dependencies on another machine, it seems the needed libraries have moved around to different folders. I now need to use these statements for my script to run correctly:
use File::Spec::Functions qw(catdir);
use lib "lib";
use lib catdir(qw(deps lib perl 5.14.2));
use lib catdir(qw(deps share perl 5.14.2));
I was wondering if there was anyway specify the prefix directory ("deps") and have the use lib pragma recursively search through that directory for my dependencies. Also, the users of this script do not have access to the Internet, so compiling my project as a CPAN module would be counterproductive.
Thanks for all the help!
Use INSTALL_BASE for the Makefile.PL and --install_base for Build.PL when installing modules. They provide stable install locations. PREFIX and --prefix try to emulate how perl has its system libraries laid out and is more useful for making packages.
Also you'll want to run rel2abs over the path before feeding it to lib to give you an absolute path. This will protect you in case your code chdirs and then tries to require a module. Or you can use lib::abs.
And ikegami is correct, it's unnecessary to make the file paths passed to lib portable. Just pass them in Unix style. Perl will figure it out.

Why is prefix=/path/to/perllib not enough to set PERL5LIB?

If I create a Perl module and install it as
perl Makefile.PL prefix=/path/to/perllib
Then I would expect to be able to set PERL5LIB to /path/to/perllib and the module be found. This doesn't seem to be the case. The module gets installed to /path/to/perllib/site_perl/5.8.5/, so that's what PERL5LIB has to be set to (or passed to "use lib").
Am I doing something wrong in how I install the modules or how I set PERL5LIB?
You're conflating PREFIX= and LIB=.
A distribution consists of more than just modules. Documentation, for one, isn't installed in the same directory as the modules themselves. PREFIX= tells Perl the base path for all components.
LIB= tells Perl where to install modules.
Use (for example)
perl Makefile.PL PREFIX=~ LIB=~/lib/perl5
Then you'd use
export PERL5LIB=~/lib/perl5
No, that's how it works. The prefix indicates the root of the installation, but the library directories are usually somewhere deeper within that directory structure.
If you install multiple modules with the same prefix, they should all be able to use the same PERL5LIB value, though.
Long story short, use INSTALL_BASE instead of PREFIX. It works more like the --prefix of other installers and creates a predictable install pattern. Then you can set PERL5LIB to <INSTALL_BASE>/lib/perl5 and go.
ExtUtils::MakeMaker::FAQ explains:
The behavior of PREFIX is complicated and depends closely on how your Perl is
configured. The resulting installation locations will vary from machine to machine
and even different installations of Perl on the same machine. Because of this, its
difficult to document where prefix will place your modules.
In contrast, INSTALL_BASE has predictable, easy to explain installation locations.
Now that Module::Build and MakeMaker both have INSTALL_BASE there is little reason
to use PREFIX other than to preserve your existing installation locations. If you
are starting a fresh Perl installation we encourage you to use INSTALL_BASE. If you
have an existing installation installed via PREFIX, consider moving it to an
installation structure matching INSTALL_BASE and using that instead.
What version of perl? You should only have to specify the path up to 'site_perl'. For libraries not under site_perl, you should also specify the path up to 'perllib'. More recent versions of perl (5.8 or better?) are better at letting you specify only these two directories, without having to specify version and architecture directories.

Where do I install Perl modules that I wrote?

I wrote some modules, and trying to run them. How I tell where to take the module from?
I am writing in Windows, and tried to put it in c:\perl\lib but it didn't help.
Can I put it in the same directory, as the file that calls the module?
Perl uses the paths in:
#INC
to search for modules. (.pm files)
If you:
perl -e 'print join "\n", #INC;'
you'll see what paths are currently being searched for modules. (This #INC list is compiled into the perl executable)
Then you can:
BEGIN { unshift #INC, 'C:\mylibs' }
or
use lib 'C:\mylibs'
and place MyModule.pm inside C:\mylibs to enable:
use MyModule;
This is exactly what local::lib is designed to handle. By default, use local::lib; will prepend ~/perl5 to your module search path (#INC), but you can easily tell it to add another directory.
If you're doing it with a fixed directory (rather than one relative to your home directory), then you're probably just as well off with use lib 'PATH'.
If this is for code that will only be run from the command line, another option would be to create a PERL5LIB environment variable which points to your personal module directory. This would affect all Perl run by your user account from the command line, so you wouldn't need to modify your Perl code at all with this method, but it's trickier to set up for non-command-line code (e.g., web scripts) and, if the code will be run by multiple users, PERL5LIB will need to be set for all of them.
I wouldn't recommend mucking about with #INC directly in any case. There are plenty of easier ways to do it these days.
For application-specific libraries the common approach is to use the FindBin module to locate the application directory and then use lib to add the application's library to #INC:
use FindBin;
use lib "$FindBin::Bin/lib";
use AppModule;
For general-purpose modules, I recommend developing them the same way you would for a CPAN release (e.g. start with module-starter) and install them with perl (usually under site/lib). See also: Which framework should I use to write modules?
If you can't install with perl (i.e. you don't have the necessary permissions) you can have a personal library instead. See How do I keep my own module/library directory? in perlfaq8.