setting up perl packages in a different dir - perl

I am looking into rewriting a old application in Perl.
Setting up three packages and running subroutines from them makes a lot of sense for what I'm going to be doing, but I'm not very familiar with setting up packages.
I want the packages to be in the same place as my other Perl scripts, i.e. nothing other than scripts in this bin directory will need to call these packages.
My question is how can I point Perl to know where my packages are (and how do I install them in a place other then the default) and is this an okay/smart thing to do?

This is a common task. The PERL5LIB environment variable contains a list of directories to look for a module in. You can also use the the lib pragma to specify directories a specific script should look for module in:
#!/usr/bin/perl
use strict;
use warnings;
use lib "$ENV{HOME}/lib";
You might also want to look into cpanm and local::lib.

If the packages and scripts are in the same location, I'd recommend using FindBin:
use FindBin '$Bin';
use lib $Bin;

Related

FindBin for perl modules that reside in my script's directory

I have a script that uses modules that are external to the standard Perl library and would like for some way to use them. I don't have permissions to install them into the Perl lib directory and was wondering if I could just have these external modules reside in my scripts directory.
I have read about using FindBin but it seems to not work. Am I using it correctly?
Right now I want to use 3 modules I want to use (2 being directories). So lets say my script is in Dir1, then my modules will be in a subdirectory of Dir1 called Dir2.
So assuming FindBin finds Dir1, then all I have to do is this?
use FindBin '$Bin';
use Dir2 "$Bin/Dir2";
use Dir2::SubDir_ofDir2_1::Module1;
use Dir2::Module2;
use Dir2::Module3;
My program seems to run but it doesn't do anything. So I am pretty sure it is not importing the modules correctly.
Thanks
The proper way to do it would more likely be either:
use lib "$FindBin::Bin/Dir2";
use SubDir::Module1;
or:
use lib $FindBin::Bin;
use Dir2::Subdir::Module;
Both would find the files, behavior would then depend on whether the modules declare themselves as inside package Dir2 or not.
Check out FindBin and lib's documentation.

How can I include Perl modules with paths relative to the program?

I have a Perl script which uses installed packages. One is a Perl package another one is Perl XS package.
Now I want to call this script but use not installed packages, but packages with the same name by path.
I used perl -I /home/.../lib script.pl but it doesn't work
How can I do it?
For various ways of affecting where your modules are loaded, please review this SO posting:
How is Perl's #INC constructed? (aka What are all the ways of affecting where Perl modules are searched for?)
You can use the lib pragma to prepend directories to the path perl uses to find modules.
So, if there is a module named Foo installed in the default directories and a different version installed in /home/cowens/perl5 you can say
use lib "/home/cowens/perl5";
use Foo;
and perl will find the version in /home/cowens/perl5.
Can you show us a recursive listing of the directory where you're storing the modules you want to use? An ls -R could help us figure out if you have the right paths.
When you use the -I switch, you have to ensure you get the right path in there. If you use a module:
use Some::Module;
Perl actually looks for:
$lib/Some/Module.pm
The $lib is one of the directories in #INC. Another way to say that though, is that if the particular directory is not in #INC, Perl isn't going to look in it. This means that Perl won't automatically look in subdirectories for you
If your module is not at that location, Perl is not going to rummage around in that $lib to look for it. Your XS module is probably not stored like that. It might have a Perl version and archtype in the path, so you might find it in:
$lib/5.10.1/darwin-2level/Some/Module.pm
You need to add those paths yourself if you are using -I.
However, you can load modules on the command line. It's much easier to use lib, which adds the extra directories for you:
perl -Mlib=/path/to/lib ...

How do I use Perl modules from their distribution directory?

Assume I downloaded Date::Calc from http://guest.engelschall.com/~sb/download/.
Now, I have a script, xxx.pl, which resides in the same directory as the untar-ed "thing" that I downloaded from the link above
When untar-ed, it creates a "Date-Calc-5.6" folder with tons of stuff.
How do I include Date::Calc in xxx.pl? (I keep getting "Can't locate Date/Calc.pm in #INC" errors)
You first need to install the module.
In your #INC statement, specify the directory containing your Perl modules. Or use the statement: use lib "path" to be able to load modules via additional use statements.
You have to install the module. In most cases, this is best achieved by ignoring the source code tarball and using the cpan utility (on *nix) or the PPM manager (on ActivePerl for Windows).
Installing is the preferred method, but if you just want to try it without installing you can do this.
use strict;
use warnings;
use lib '/home/jeremy/Desktop/Date-Calc-5.8/lib';
use Date::Calc;
Please switch out my directory with where yours is unzipped. Also please read about lib.
You don't necessarily need to build and install the module. If the module is pure Perl and the build process doesn't create any new code files, you may be able to use a module while it's "still in the box". Assuming that's the case, there's more than one way to do it.
EDIT: It doesn't look like Date::Calc is pure Perl. You will probably at least have to build it before you can use the module.
Set the $PERL5LIB environment variable to include the package distribution directory.
Invoke perl with the -I switch
perl -I/the/distribution/dir myscript.pl
Put the -I switch on the #! (first) line of the script
#!/usr/bin/perl -I/the/distribution/dir
Use use lib in the script
use lib qw(/the/distribution/dir);
use The::Package;
Put the distribution directory into the #INC variable
push #INC, "/the/distribution/dir";
require The::Package;
or
BEGIN {
push #INC, "/the/distribution/dir";
}
use The::Package;

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 my Perl script find its module in the same directory?

I recently wrote a new Perl script to kill processes based on either process name / user name and extended it using Classes so that I could reuse the process code in other programs. My current layout is -
/home/mutew/src/prod/pskill <-- Perl script
/home/mutew/src/prod/Process.pm <-- Package to handle process descriptions
I added ~/src/prod in my $PATH variable to access the script from anywhere. On running the script from any directory other than its resident directory leads to a "Can't locate Process.pm in #INC" (which is understandable given that other than the shared directories in /usr, #INC includes only the current directory - '.'). One workaround that I have been using is the use lib directive as so -
use lib '/home/mutew/src/prod';
but this is a major portability issue. Any solutions which will also allow me to export the script to other systems without and changes?
EDIT
I chose 'depesz' answer as the correct one because of its simplicity and core module usage.
brian d foy's answer though suggests other methods to accomplish the same (TMTOWTDI), his contribution in perlfaq8 renders this question absolutely redundant.
I am curious why the simplistic solution
use File::Basename;
use lib dirname (__FILE__);
use SomeModuleLocatedInTheSameDirectoryAsThisPerlScriptOrModule;
did not come up. The FindBin module seems to have some issues if the file is not the main executable perl script, but simply a non-executable Perl module. At least that's how I interpret the comment in the documentation. Did not really test it.
To have any other path relative to the location of this Perl file, do something like
use File::Basename;
use lib dirname (__FILE__) . "/MyModules";
The simplest approach I found it to use FindBin module. Like this:
use FindBin;
use lib $FindBin::Bin;
Generally I prefer to have my scripts provided in such a way that programs are in whatever/bin, and libraries are in whatever/lib
In these situations I use a slightly more complicated approach:
use Cwd qw(abs_path);
use FindBin;
use lib abs_path("$FindBin::Bin/../lib");
The abs_path call is to make the #INC contain whatever/lib, and not whatever/bin/../lib - it's just a slight change, but makes reading error messages easier.
From perlfaq8, which answers "How do I add a directory to my include path (#INC) at runtime?". There are several other answers for questions around this issue too.
How do I add a directory to my include path (#INC) at runtime?
Here are the suggested ways of modifying your include path, including environment variables, run-time switches, and in-code statements:
the PERLLIB environment variable
$ export PERLLIB=/path/to/my/dir
$ perl program.pl
the PERL5LIB environment variable
$ export PERL5LIB=/path/to/my/dir
$ perl program.pl
the perl -Idir command line flag
$ perl -I/path/to/my/dir program.pl
the use lib pragma:
use lib "$ENV{HOME}/myown_perllib";
The last is particularly useful because it knows about machine dependent architectures. The lib.pm pragmatic module was first included with the 5.002 release of Perl.
Besides the already stated solutions:
use FindBin / lib
Perl Faq 8 How do I add a directory to my include path (#INC) at runtime?
'The simplest approach' (™) that I use while dev/testing a module prior
to deploying it (in /usr/local/lib/site_perl/ or elsewhere in #INC) is
to modify #INC before loading the module as follows:
#!/usr/bin/perl
use strict;
use warnings;
# Modify #INC prior to module loading.
BEGIN { unshift #INC, '.'; }
use YourModuleInCWD;
(Add current working directory to #INC? - PerlMonks)
You can make perl look in any directory by using the -I flag. Here, -I stands for #INC which is the array of paths in which perl looks for modules. Using -I adds the given path to the #INC array for this execution.
eg:
perl -I lib bin/script.pl
where lib contains the modules I want to use.
I know that this works for perl 5. I am not at sure about other versions.
Take a look at Par::Packer. It creates an executable with all of the script's dependencies included. It makes distribution easy. You also could also provide your users a version of your module that can be installed on their systems. See Module::Starter for an easy way to build all of the files required to make a standard CPAN-style distribution.
The path can be included in perl script in first line, marked with #!
#!/usr/bin/perl -I.
use anymodule;
To convert relative links to absolute and add to #INC, I normally use ex::lib. Of course, this is useful only if you plan to keep the relative locations of the script and the module identical on all machines where you plan to run your script.
Just keep it simple. There is no need to import any libraries; just find out your current working directory:
use lib "$ENV{PWD}/relativ_path_own_perllib";
For similar problems, you can read out the environment variable which gives your information about where you are, your home directory, operating system stuff, and so on, with just one row of programming code in the shell-terminal, like:
perl -e 'map { print; print " : ". $ENV{$_}." \n\r"; } sort keys %ENV '
There is no need to bind some libraries; just use the %ENV-Hash.
FindBin::libs will find all your libs placed at reasonable places relative to the path from where your script is running.