I have a perl script that used to run in a chroot, and now I'd like it to run outside the chroot. That means that I have to somehow point perl to only look for libraries and modules in /where/chroot/used/to/be/usr/lib instead of /usr/lib. I tried adding the new directories inside the script with push #INC, but then the dependencies are still broken, looking in the old dirs.
Is there any way to tell perl when I run the script that I only want it to look in certain dirs for libraries and modules?
Or is there another better way to make sure dependecies still work when the regular dirs (/usr/bin, /usr/lib etc) are replaced by nonstandard ones?
To change the #INC from the command line, use the -I option:
perl -lIadded -e 'print for #INC'
In a program, you need to modify #INC early enough, i.e. during compile time. This can be done with
BEGIN { unshift #INC, '/path/...' }
or by using lib
use lib '/path/...';
You can also set the PERL5LIB environment variable:
export PERL5LIB=/path/...
perl -e 'print for #INC'
you can use lib to put any new directory in your program.
example
use lib "path";
in your case just add this line in the beginning of your program
use lib "/usr/lib/";
hope this will work for you.
Related
I'm trying to add the HTML::Entities module path to #INC. I did export PERL5LIB=/mypath/HTML/ followed by source ~/.bashrc. That path is reflected in PERL5LIB, but not in #INC. Is there an additional step that I'm missing?
I'm using perl 5.26.2 on CentOS6.5
Edit:
I (wrongly) assumed that my path wasn't being added to #INC because when I run my perl script I get
Can't locate HTML/Entities.pm in #INC (you may need to install the HTML::Entities module)
(#INC contains:
/home/hek/anaconda3/bin/aux/lib/perl5
/home/hek/anaconda3/lib/site_perl/5.26.2/x86_64-linux-thread-multi
/home/hek/anaconda3/lib/site_perl/5.26.2
/home/hek/anaconda3/lib/5.26.2/x86_64-linux-thread-multi
/home/hek/anaconda3/lib/5.26.2
)
(Line breaks added for readability)
But it does appear below
echo $PERL5LIB
/opt/rh/devtoolset-2/root//usr/lib64/perl5/vendor_perl:/opt/rh/devtoolset-2/root/usr/lib/perl5:/opt/rh/devtoolset-2/root//usr/share/perl5/vendor_perl:/opt/perl/lib/site_perl/5.14.2/x86_64-linux-thread-multi/HTML/
perl -e 'use Data::Dumper; print Dumper(\#INC), "\n"'
$VAR1 = [
'/opt/rh/devtoolset-2/root//usr/lib64/perl5/vendor_perl',
'/opt/rh/devtoolset-2/root/usr/lib/perl5',
'/opt/rh/devtoolset-2/root//usr/share/perl5/vendor_perl',
'/opt/perl/lib/site_perl/5.14.2/x86_64-linux-thread-multi/HTML/',
'/home/hek/anaconda3/lib/site_perl/5.26.2/x86_64-linux-thread-multi',
'/home/hek/anaconda3/lib/site_perl/5.26.2',
'/home/hek/anaconda3/lib/5.26.2/x86_64-linux-thread-multi',
'/home/hek/anaconda3/lib/5.26.2',
'.'
];
Why would there be this discrepency?
I do have multiple versions of perl installed, but which perl returns the version that I need to use, ~/anaconda3/bin/perl.
I tried changing the shebang in my script from #!/usr/bin/env perl to #!/~/anaconda3/bin/perl, but that didn't help.
Two possibilities:
Either the PERL5LIB env var wasn't set in the parent of the perl process giving the error (e.g. you launched it from a web server), or
The -T command line switch was provided to perl process giving the error (since this causes PERL5LIB to be ignored).
In either case, you can use use lib in the source instead of PERL5LIB.
use HTML::Entities looks for a file HTML/Entities.pm in the directories in #INC. No such path is found because it's looking for ones like /opt/perl/lib/site_perl/5.14.2/x86_64-linux-thread-multi/HTML/HTML/Entities.pm.
Leave off the HTML/ part in the directory you're trying to add to the search path and you might have better luck.
Edit: There's still the version mismatch, but as long as the module is pure Perl without any XS components I don't think that will be a big problem. Still better to get it in the right path for the version of perl you're actually using. Do that and you shouldn't have to manipulate the search path at all.
This is to summarize the problems and state what seems to be the simplest solution.
From the output of your test one-liner it is clear that a module installed under v5.14.2 is used in a program meant to run under v5.26.2. That is not good, even if it happens to work.
So install HTML::Entities under the perl build that needs it, v5.26.2.
That also solves the problem you are asking about, since then you won't have to muck about with PERL5LIB or anything else.
Further, the #INC in your one-liner test clearly isn't loaded in your real run, just as you suspected. Possible reasons are given in ikegami's answer, as well as the solution, to use lib "...";. But then you need to use the module version installed for v5.26.2, and once you installed it with that perl there'll actually be no need to specify extra library paths.
Finally, if you end up needing to add that path for some reason, leave off the HTML (last) directory, as Shawn's answer indicates. With use HTML::Entities the directory HTML will be searched (for Entities.pm file) and you only need to provide the directory that contains it.
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 ...
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;
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.
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.