How does Perl module(.pm) call corresponding .so? - perl

I just compiled and run a hello world Perl extension,but I don't know the principle.How does the .pm call .so?

It doesn't need to - the binary code defines some variables and functions in the module's namespace, they can be used just like regular variables. The .pm file only needs to ensure that .so is loaded when it is needed. This is done by the DynaLoader module. By inheriting from DynaLoader you make sure that your .so file is loaded when an unknown method is called on your class.

Related

Eliminate the UserName from the "use" command

All my Perl files start with the /home/UserName/lib use command. Is there a way to eliminate the hardcoded UserName from all my .pl files? I want to simplify duplicating of my website for different users and different domains. This is a Perl Templates website that takes the cfg=UserName param from the URL and renders the site according to the specific user format. But the lib files are all the same for all users!
Can you use something like this instead? use lib './lib';
Sorry, I have very limited knowledge of perl programming.
Example:
use lib '/home/UserName/lib';
use RT::RealTime;
use RT::Site;
....
Anyone who can help is appreciated.
If I'm understanding your quest correctly, one way is
use warnings;
use strict;
my $user_name;
BEGIN { $user_name = $ENV{USER} }
use lib "/home/$user_name/lib";
# use packages from that path...
This sets the username of the user who runs the script.
Better yet, in this particular case the use of BEGIN isn't really needed since %ENV is a global variable set up by the interpreter early enough, so you can simply say
use lib "/home/$ENV{USER}/lib";
or
use lib "$ENV{HOME}/lib"
However, this won't work for many other related needs, which is why I (first) showed a way to work out things which aren't handed to us at compile time, in a BEGIN block.
In that case, the little dance around BEGIN goes as follows. The use runs at compile-time, so $user_name must already be available; thus we set it up in a BEGIN block that must come before the use statement that uses the variable. However, we need to declare the variable outside of the block (and my is a compile-time statement).
All that can then be wrapped in another block, enclosing code from before my $user_name to after user lib..., to scope that $user_name variable so that it is not seen in the rest of the file.
Another option seems to be to simply move those packages to a user-neutral location, and then you don't need the username in that use lib statement ...?
Can you use something like this instead? use lib './lib';
Almost, but not quite.
The problem with use lib './lib'; is that it will look to the lib/ directory underneath the user's current working directory when they run the script. This means that the program will only work correctly if the user is in the correct directory when they run it. It also creates a potential security issue if they happen to be in a directory where an attacker has created a malicious lib/ subdirectory containing module files matching the names of modules your code uses.
Instead, the Perl idiom to do what you want is:
use FindBin '$RealBin';
use lib "$RealBin/lib";
When you use FindBin, it finds the file containing the Perl program you're running and sets $RealBin to the directory path where that file is located. The use lib will then use the lib/ directory under that path, regardless of what directory the program is started from.
To include libraries from a directory relative to the current file, use lib::relative:
# in file /home/user/project/foo.pl
use lib::relative 'lib'; # includes /home/user/project/lib
use lib::relative '../lib'; # includes /home/user/lib
This will convert it to an absolute path, it's a bad idea to have relative paths in #INC since it relies on the current working directory, which could be anything and can be changed at any time.
lib::relative can also be easily replicated using core modules as documented.

What do the chained namespace identifiers in Perl do?

I found a code snippet which goes like this:
package File::MP3;
use parent 'File'; # sets #File::MP3::ISA = ('File');
my $mp3 = File::MP3->new( 'Andvari.mp3', $data );
$mp3->save();
Here, I want to ask if File::MP3 is just a name (it is named that way just to show that it inherits from File)
OR
We have to name it that way if it inherits from File?
Update
I made a module named Module.pm in lib folder, & then named the package as package lib::Module
You're getting a little confused
When use or require is actioned, Perl will form a relative path from the package name by changing something like My::Other::Module to My/Other/Module.pm using the obvious substitutions
It will look for that relative path in the list of locations in the built-in #INC array, which contains some paths that were defined when perl was built and others that may be added at run time
Up until very recently, #INC contained the current working directory, ., so if you have your module in ./lib/My/Other/Module.pm then the Perl compiler will find it if you use lib::My::Other::Module.pm. But that's not how it's meant to work
You should add ./lib to #INC (using either use lib './lib'[1] or by adding to the value of the environment variable PERL5LIB) and then use My::Other::Module. That will work fine because perl is looking for the .pm file in in ./lib. The name and path to the .pm file, the package statement, and the use statement should all agree about what the name is
[1] Note that it is a security risk to add relative paths to #INC. That is why . is no longer included as standard in the release client for Perl v5.26. That means you shouldn't use lib './lib' as described above. Instead you need something like use lib '/var/users/Me/Perl/source/lib'
A package name like File::MP3 is just a name. Perl's only requirement is that it has to be unique
But modules are grouped into families in CPAN, and most file-related modules begin with File::. There is also Win32::, Net::, Math:: etc.
It is also used to indicate subsidiary modules in a suite. For instance, Mojo::Message contains the code common to both Mojo::Message::Request and Mojo::Message::Response. But that is a mnemonic for the programmer's convenience only
In the case of Math::Poisson, perl will look for a file Math/Poisson.pm which should have a package declaration package Math::Poisson. If you use that package name elsewhere then anything you declare will be inserted into the module's namespace
The File::MP3 in the package declaration is just a name. However, if you want to use that package then the name matters. The use dispatches to require, for which the name in require EXPR is
If EXPR is a bareword, require assumes a .pm extension and replaces :: with / in the filename for you, to make it easy to load standard modules. This form of loading of modules does not risk altering your namespace.
Thus if you want to use File::MP3 then an MP3.pm file had better be in a File/ directory, which needs to be in one of (the absolute-path) directories listed in #INC.
The class File from which File::MP3 inherits has nothing to do with the directory File/. The use parent (see parent) independently specifies the package to load for the class File, and its File.pm file also has to be found in #INC.
The MP3.pm file with the package may well be in a Media/ directory, in which case it would be best named as package Media::MP3; and would be loaded with use Media::MP3; – and it can still inherit from the File class by use parent File;
Placing file-related modules in a directory named File does make sense, of course.

Calling other CGI perl files within a file

Is there a way to call/access other cgi files within the same file. For example: in PHP, a require or include can call other php files. Something similar to that. I'm trying to avoid writing out a large file and trying to separate the codes in different files.
Are you able to use the standard method for importing modules in Perl?
Like this:
use mymodule;
at the beginning of your perl file. Then you will have another perl file named mymodule.pm in the same directory as your main program, and that perl file must begin with:
package mymodule;
in order to declare it as the mymodule module, and it must end with:
1;
in order to return success when your main program finished reading it.
You probably don't really want to call other CGI programs. I bet what you really want to do is to package up some common functionality into modules which you can then use in all of your CGI programs.

Add Perl module relative to script

im trying to add the module File-Copy-Recursive to my script as i have done with another module already, but when i try to use it i get an error i can not explain:
use lib "./cpan";
use Recursive qw(dircopy);
dircopy($path1, $path2);
the error i get is: Undefined subroutine &main::dircopy called at ...
I don't understand it, the module clearly has the function dircopy in it.
As other answers have already stated, this isn't working because you've moved the module's location in the include directory from File/Copy/Recursive.pm to just Recursive.pm.
Here's why that doesn't work:
A Perl module (file with a .pm extension) and a Perl package (collection of code under a specific namespace) are two completely different things. Normally, we'll put a package into a module which happens to have the same name, but this is really just to help us humans maintain our sanity. perl doesn't care one way or the other - one module can contain multiple packages, one package can be split across multiple files, and the names of the packages and the modules can be completely unrelated for all perl cares.
But, still... there's that convention of using the same name for both, which the use command exploits to make things a little more convenient. Behind the scenes, use Module; means require Module.pm; Module->import; - note that it calls import on the module name, not the name of the package contained within the module!
And that's the key to your issue. Even though you've moved the file out of the File/Copy/ directory, its contents still specify package File::Copy::Recursive, so that's where all of its code ends up. use Recursive attempts to call Recursive->import, which doesn't exist, so nothing gets imported. The dircopy function would be imported by File::Copy::Recursive->import, but that never gets called.
So, yeah. Move ./cpan/Recursive.pm to ./cpan/File/Copy/Recursive.pm so that the package name and the module name will match up again and sanity will be restored. (If you've been paying attention, you should be able to come up with at least two or three other ways to get this working, but moving the file to the proper place under ./cpan really is your best option if you need to keep the File::Copy::Recursive source in a subdirectory of your project's code.)
Use FindBin for relative lib path:
use FindBin;
use lib "$FindBin::Bin/./cpan";
use File::Copy::Recursive;
And you have to keep the whole 'tree' under ./cpan and the use line have to remain the same.
Files under ./cpan dir:
find ./cpan/
./cpan/File/Copy/Recursive.pm
The module name in Perl comes not only from the path, but also from its package declaration. You installed the module to ./cpan, but the package name specified is still File::Copy::Recursive.

Packaging Perl modules with Config files?

I am currently creating a Perl module for in house use. I used ExtUtils::ModuleMaker to generate a build script and skeleton for my Perl module. I would like to include .ini config files that my core modules need to run properly. Where do I put these files so they are installed with my module? What path do I need to use to access these config files across the main and sub modules?
P.S. this is the directory frame:
|-lib
|---Main.pm
|---Main
|-----subModule1.pm
|-----subModule2.pm
|-----subModule3.pm
|-scripts
|-t
If you are using Module::Install, you can use Module::Install::Share and File::ShareDir.
If you are using Module::Build, you may want to use its config_data tool and and a *::ConfigData module.
Taking a look at the generated Makefile, I would bet the better place to put it is under lib/Main and then you can direct your module to look at ~/.modulerc first, then PERLLIB/Main/modulerc.ini or something like that.
You could also embed the defaults in your module in a way that, in absence of ~/.modulerc, the module works using the default data.
To find the home directory, see File::HomeDir. You'll not want to use ~ (since that's a shell thing anyway).
I would suggest having your module work without the rc file as much as possible. If it doesn't exist, the code should fall back to defaults. This should be true, too, even if the file exists, but a particular flag is missing - it should fall back to the default, too.
You may want to look at Config::Any while you're at it. No point reinventing that wheel.