I am using GNU\Linux system and below perl version is been already installed.
This is perl, v5.10.1 (*) built for x86_64-linux-thread-multi
Here I want to install a perl module Net::SFTP::Foreign to build some script (say example transfer_file.pl) which should transfer files from local server to remote server.
Problem is I don't have permission to install the modules. So what I was thinking is, let me create a lib directory where I am writing transfer_file.pl and manually create a directory/file Net/SFTP/Foreign.pm inside lib and add the content from metacpan. In this case I can use something like this in my transfer script shebang line - #!/usr/bin/perl -I/path/to/the/current/location/lib
I don't know whether it's a right approach or not, since I don't have permission to install anything in the server I thought of doing in this way.
Again, if I add Net/SFTP/Foreign.pm manually in lib folder obviously there would be dependency on Net::SFTP::Foreign, so dependency tree I am checking using Gabor Szabo's script below in my local windows system:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
use MetaCPAN::API;
my $name = 'Net::SFTP::Foreign';
my $mcpan = MetaCPAN::API->new;
my $dist = $mcpan->release( distribution => $name );
say Dumper $dist;
When I execute the above script I am getting below error:
Failed to fetch 'https://fastapi.metacpan.org/v1/release/Net::SFTP::Foreign': Not Found at C:/Strawberry/perl/site/lib/MetaCPAN/API/Release.pm line 42.
What could be the problem here?
Any alternate ways to check the dependency in
https://metacpan.org/ site itself?
Even if above script executes properly do I need to add all the
dependency modules manually? Is it necessary?
Related
I have a standalone Perl module that I want to use, however I cannot get 'set lib' to work. What am I doing wrong?
I am working off the terminal in Mac OS and the module is located in a folder on my desktop /Users/John/Desktop/HT/Conlang.
#! perl -w
package HT::Conlang::S17;
use strict;
use vars qw($VERSION #EXPORT_OK);
use base 'Exporter';
use lib '/Users/John/Desktop/HT/Conlang';
use HT::Conlang::S17;
How can I get this to work?
Problem #1. It doesn't make sense to use use lib inside a module. It belongs in scripts. And even then, if it's an absolute path (as opposed to a path relative to $FindBin::RealBin), it's far better to set env var PERL5LIB than to use use lib.
Problem #2. If your module uses package HT::Conlang::S17, it should be loaded using use HT::Conlang::S17;, which means Perl will search for HT/Conlang/S17.pm, so the entry to add to #INC should be /Users/John/Desktop.
Problem #3. /Users/John/Desktop contains more than just Perl modules. You should have a directory dedicates to being a Perl library directory.
Solution, part 1. Move /Users/John/Desktop/HT to /Users/John/perl5/lib/HT.
Solution, part 2. Have your login process add /Users/John/perl5/lib to the env var PERL5LIB.
I'm working on an application that is written in Perl. The application is so large now that I want to move each class out into a separate file. This complicated building and installing the program; when it was only file it could easily be copied in place anywhere. Now I have to use a build system like Build::Module or ExtUtils::MakeMaker.
I have structured my source tree so that I have two directories: bin where the program launcher is, and lib where a number of modules are. Bin contains an executable Perl script which the user invokes, and it loads the necessary module from the lib directory.
The problem that I have is that I want the user to be able to specify a prefix where they want the program installed, similar to the --prefix option offered by packages based on GNU Autotools. Since this might not be a standard path where Perl looks for modules (for example /opt/program) the user will see a message saying something like Can't locate Program.pm in #INC.
Is there a way to make the program detect where the modules should be loaded frm and dynamically add that path to #INC? I don't want the user to have to manually work with environment variables like PERL5LIB in order to get the program running.
Couldn't you use findbin and lib ?:
use FindBin qw($Bin);
use lib "$Bin/lib";
If I understand you, you're breaking up a big large program into smaller components. Good for you! That's great programming technique. Making each class a true Perl module is a great idea. It makes your program so much easier to maintain.
I do this all of the time. First, I use the module name Local:: as my prefix. CPAN will never use Local as a module prefix, so I know I will never clash with some CPAN Module. Then, I put my Local module directory in the same directory as my script. In most standard Perl installations, when Perl searches #INC for modules, the last directory it searches for is the current directory (.). Since my module names will never clash with any CPAN modules, I know Perl will find my modules and only my modules under that ./Local directory.
You can now distribute the entire directory structure to other users. All a user has to do is install your entire directory (which includes the scripts and modules) and run the script. No need to go through an entire install process.
The following code works for me. You supply a command line option like (--prefix abc) and that value is appended to the lib path very early in your script. So all following modules will be searched with the dynamically set path.
use strict;
use warnings;
use Getopt::Long;
my $prefix = '';
BEGIN {
GetOptions ('prefix=s' => \$prefix );
$prefix = $prefix || '.';
}
use lib "$prefix";
use mymod; # uses the dynamical search path
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.