Perl - Use lib with perl module which have dependencies - perl

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';

Related

Perl Module install to mentioned directory

I want to install a Perl module to a particular directory which I am mentioning while executing a command.
I want this module to be installed in a mentioned path.
Command I tried is
$ env PERL_MM_OPT='INSTALL_BASE=/home/vinod/my_test_folder/perl_practice/scripts' cpanm Log::Log4perl
But this by default installed in /home/vinod/my_test_folder/perl_practice/scripts/lib/perl5.
What could be the reason? How to install the module in particular directory which I am mentioning?
See the documentation of INSTALL_BASE. You seem to be interested in changing just the INSTALLPRIVLIB path. Maybe you want to set the LIB attribute only, described in the next section?

Can't locate Config.pm in #INC

I have a Perl app on my development server that I would like to replicate on my local machine (mac osx). I'm not a perl programmer by trade (I'm a PHP/Rails developer), and the developer of this app is no longer around so I can't contact him for help. I've gotten pretty close to getting it to work. I was able to install all the packages using CPAN (at least I think I got them all) but I keep running into the following error:
Can't locate WebCNP/Config.pm in #INC (
#INC contains: /Library/Perl/5.16/darwin-thread-multi-2level
/Library/Perl/5.16
/Network/Library/Perl/5.16/darwin-thread-multi-2level
/Network/Library/Perl/5.16
/Library/Perl/Updates/5.16.2/darwin-thread-multi-2level
/Library/Perl/Updates/5.16.2
/System/Library/Perl/5.16/darwin-thread-multi-2level
/System/Library/Perl/5.16
/System/Library/Perl/Extras/5.16/darwin-thread-multi-2level
/System/Library/Perl/Extras/5.16 .
)
at webcnp_lib.pl line 30.
On the server, the app's file structure looks like this:
/var/www/cgi-bin (empty dir)
/var/www/conf
/var/www/error
/var/www/html (empty dir)
/var/www/icons
/var/www/perl (the config file is located in this directory)
- /WebCNP/Config.pm
/var/www/ssi (all the .pl files for the app are located here, including all the JS and CSS files)
Line 30 of /var/www/ssi/webcnp_lib.pl has the following:
use WebCNP::Config;
Any ideas what I could be doing wrong?
Just so you know I've copied the file structure of the app from my development server to my local machine and created a virtual host so that it points to the app's root directory (/var/www).
Thanks in advanced for any insight!
was able to fix this with a symbolic link
ln -s /path/to/my/app/WebCNP /Library/Perl/5.16/WebCNP
I take this isn't a module from CPAN.
I would be a bit hesitant to use a symbolic link. This will work, but you're basically linking in a file you have under your own control to the master /Library directory on MacOS X. You delete your file, and that link won't be pointing to anything.
You can use use lib to add directories that contain your modules to the #INC directory:
use lib qw(/path/to/my/app);
This will now include this path for module searches.
If you rather install the module itself, why not simply copy it into /Lbrary/Perl/5.16 itself? It's what cpan would have done. At least this way, you're Perl module directory isn't dependent upon a link that can be removed.
/var/www/perl isn't present in #INC, so Perl won't look there. The most common approach to solve this for CGI scripts would be to add the following to your scripts (but not modules):
use FindBin qw( $RealBin );
use lib "$RealBin/../perl";
I was able to fix this with a symbolic link
ln -s /path/to/my/app/WebCNP /Library/Perl/5.16/WebCNP
Not sure if this is the most elegant approach, but seems to work well for this app. Thanks everyone for your replies! This has been very insightful.
Old post, I know, but there is a much more portable way. When you install the modules, you need to do two things.
Add the installation path to PERL5LIB (i.e. PERL5LIB=$PERL5LIB:/My/Module/Path/lib) in your environment configuration (.profile or other files which get read on system initialization)
Add a PREFIX to your perl Makefile.PL call (perl Makefile.PL PREFIX=/My/Module/Path)
It goes without saying that you need to make certain your Makefile.PL is written correctly.

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

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.

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.

How can I create a portable perl when I can't install modules on the target host?

I need to run Perl applications I develop on cygwin Windows on HP unix / Solaris hosts. I am not a superuser on the unix machines and I can't touch the default Perl module location nor can I install modules to the default Perl module location. Also the unix installation lacks most basic modules and I can't change that.
For example, I have a Perl application that needs Expect which has native C compiled parts to it. How would I roll out this application to unix with its required dependencies without having to install anything else on that box?
Is there way to build the entire Perl application under Cygwin Windows and then just roll out one executable to unix and run it from my home directory there?
EDIT addition based on answers so far:
Thanks in particular to brian, the local LIB dir solution seems to work in case of native Perl, but in case of Perl module needing C components, cross platform compiling, ie compiling on cygwin to run on Solaris, is not really possible as I feared.
However would having an other linux installation help, i.e. would this be possible easier between different flavors of Unix like package Perl on linux and then deploy to Solaris/HP? And what about something like lcc ?
Also I'd still like to hear little more if somebody has rolled out a native Perl package on Windows that includes all dependencies for a complicated Perl app that can then be moved to unix as just one file? (I do now understand that it won't work in case native C code is included like in in Expect.pm, but what about in case of app only using pure perl modules?)
Basically for many reasons I am trying to minimize time I need to spend being logged into these "production" unix hosts and do as much as possible locally beforehand.
Added a new cross-compile question, since I felt I was maybe veering too far from the original perl question.
EDIT -- Par looks promising for pure Perl, although same deal, it doesn't look to solve the cross platform compile problem for native extensions
In this case, I'd consider delivering a complete application complete with its own Perl. You get to choose any version you like and any modules you like. Compile everything, organize everything into a directory, then tar the result. To deploy, copy the file and untar. Use the advice that others have already noted about library search paths, etc. In essence, your application gets its own stack.
Now, the trick there is the cross compilation. Why are you developing on Cygwin? Is that a target too? Is there a reason you don't have an HP/UX or Solaris development machine? What architecture are you targeting (RISC, SPARC, Intel, etc). If you can't get hardware to run those, get some virtual machines for your targets and develop there.
Aside from that, you can install modules anywhere you have permissions. See perlfaq8:
How do I keep my own module/library directory?
How do I add the directory my program lives in to the module/library search path?
How do I add a directory to my include path (#INC) at runtime?
I haven't tried this particular feature, but perl2exe says it supports cross platform builds.
Compiling a Perl script with all its dependencies on Windows with Cygwin and running it Solaris is just not going to work.
Now the question is: do you have access to a compiler on that Solaris computer? It's not because you do not have root access that you cannot compile and install Perl modules in your home directory by using:
perl Makefile.PL PREFIX=$HOME
If you have CPAN available on your Solaris system you can set the prefix in the CPAN shell this way:
start the shell perl -MCPAN -e shell;
change the prefix with conf makepl_arg PREFIX=/path/to/your/home/directory
For your script to run, you can either start perl with the -I $HOME command-line switch, e.g.:
perl -I $HOME script.pl
Your other option would be to place this at the begining of your script
use lib $ENV{'HOME'};
Set your environment variable PERLLIB to your personnal Perl lib directory or use the -I command line switch to Perl to indicate it.
If you have access to the HP-UX machine you can compile Expect there and install it in your directory. But cross compilation from Windows to HP-UX is probably much more difficult. You would have to build a GCC cross compiler.
If you have a compiler on each of your systems (and some other tools needed by configure like grep), you should not only be able to compile modules, but you should also be able to build your own perl executables.
You'll want local::lib. Once you've done that, the pure Perl modules should work cross platform, but you'll have to identify and reinstall the compiled modules on the foreign platform. Do the initial install on a real unix, cpan on cygwin is slow.
I've run across this several times on my work systems. We have a base install of Perl 5.8 and I don't have the ability to add modules. Here's the solution I use:
Create a folder called 'lib' in your
project root (ex:
~/projects/MyProject/lib)
Any
modules you download from CPAN
should have a Makefile as well as a
directory called "lib". Copy the contents of the lib folder into your newly created lib folder. Some modules may only contain a single .pm file, and no lib structure. Just copy the .pm file.
Your code should do the following: first, use any modules that have been installed normally, then unshift your #INC environment variable to use your local libraries:
# Declare Includes --------------------------------------------------------------------------------
use Getopt::Long;
use vars qw($VERSION);
use DirHandle;
use FileHandle;
# Force perl to use our local 'lib' directory for imported modules, this allows us to
# use modules without having to install them in th emain perl assembly. However, this
#also prevents these modules from being used in other projects.
BEGIN { unshift #INC, "lib"; }
use Error qw(:try);
use SOAP::Transport::HTTP;
#use LWP::Protocol::https;
use XML::Simple;
use XML::Writer;
use XML::Writer::String;
The caveat to this method is that some Perl modules don't use the 'lib' method or have additional dependencies. If you run into problems, examine the Makefile.PL for the module and see what it's doing.