Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Modules 101 :: Using a Local Module from CPAN

by redapplesonly (Sexton)
on Dec 06, 2022 at 17:10 UTC ( #11148616=perlquestion: print w/replies, xml ) Need Help??

redapplesonly has asked for the wisdom of the Perl Monks concerning the following question:

Hi Perl Monks,

So I'm a Perl newbie, making lots of rookie mistakes. I've made two posts on this website* already in my fumbling attempts to solve a singular problem: I need a way to ensure only one instance of my Perl script can run at a time. Stevieb was kind enough to recommend his Script::Singleton solution, but I was too much of a Perl beginner to realize what he'd handed to me at first.

It was a bolt of lightning when I realized that Script::Singleton was another script, and all I needed to do was copy that script from the site**, save it in a local directory, and then have my script run his script. Easy Peasy. Except, I'm struggling at that "have my script run his script part." (I think this is prob something you Perl Ninja Black Belts do all the time, so you can discuss the process in shorthand. But for newbs like me, the process is confusing.)

(FYI, I'm developing on a Ubuntu 20.04 machine, using Perl 5.30.0)

Let me show you actual code. First, here's Stevieb's script:

package Script::Singleton; use strict; use warnings; use Cwd qw(abs_path); use IPC::Shareable; our $VERSION = '0.03'; sub import { my ($class, %params) = @_; $params{glue} = abs_path((caller())[1]) if ! exists $params{glue}; IPC::Shareable->singleton($params{glue}, $params{warn}); } sub __placeholder {} 1;

I've saved this script in the same directory as, plus run a chmod 775 on it, just to be sure. Stevieb's script should be good to go.

Now for the part where I'm all thumbs. I've read through a few "Perl Module" tutorials, trying to puzzle how my script can use or require the module script. Here was what I thought would be the best attempt:

#!/usr/bin/perl use warnings; use strict; require '/home/demo/pullWorkload/scpLRSIControllerDir/toys/Singleton.p +m'; use Script::Singleton; # Line 6 :: Actually run the code in "Si" ??? package main; print "Starting script...\n"; sleep(10); print "I can use \"!\".\n";

But script output is:

me@/path/to/my/scripts/$ ./runTest.perl Can't locate Script/ in @INC (you may need to install the +Script::Singleton module) (@INC contains: /etc/perl /usr/local/lib/x8 +6_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_ +64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/pe +rl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64 +-linux-gnu/perl-base) at ./toy02.perl line 6. BEGIN failed--compilation aborted at ./runTest.perl line 6. me@/path/to/my/scripts/$

Okay, obviously my script is searching throughout all the directories in @INC for, but not looking in the local directory. Frustrating.

If things were working correctly, I'd hope that the first time the script runs, it would execute Stevieb's code, confirm that it is the only instance of this script running, then sleep for 10 seconds. In theory, a second execution of my script before those 10 seconds are up should... I dunno, not execute at all?

If I comment out Line 6 (which I thought was necessary to actually run Stevieb's code), then my script runs with no errors. But you can run multiple instances of my script at the same time, which is no bueno.

Anyway, I apologize for (A) essentially asking you guys the same question three times in a row, and (B) asking a question which is probably Perl 101 to you guys. I do research my questions before I post them, FWIW. Any comments or criticism is appreciated. Thank you!

*Full Disclosure :: My previous posts are: Ensure Only One Instance of Your Script is Running... with 'ps -ef' ?
Mechanism for ensuring only one instance of a Perl script can only run?
**The CPAN site where I found Stevieb's code is located:

Replies are listed 'Best First'.
Re: Modules 101 :: Using a Local Module from CPAN
by choroba (Cardinal) on Dec 06, 2022 at 17:28 UTC
    Instead of requiring the file with full path, see lib:
    use lib '/path/to/my/modules'; use Script::Singleton;

    If the module is located in a place relative to the script, you can use FindBin:

    use FindBin; use lib "$FindBin::Bin/lib"; use Script::Singleton;

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      Thanks choroba,

      I'm afraid either solution doesn't work. When I change my script to:

      use lib '/path/to/my/local/directory/'; use Script::Singleton; # Line 6

      ...the output is still:

      Can't locate Script/ in @INC (you may need to install the +Script::Singleton module) (@INC contains: /home/demo/pullWorkload/scp +LRSIControllerDir/toys/ /etc/perl /usr/local/lib/x86_64-linux-gnu/per +l/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5 +/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share +/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-ba +se) at ./testMe.perl line 6.

      I note that the use lib must specify the directory, not the .PM file, BTW.

      If the use lib doesn't add /path/to/my/local/directory/ to @INC, I'm at a loss on what might be the problem. Any thoughts...? Thank you for writing.

        Perl always expects each :: in a module name to translate to a path separator in the directory hierarchy. So for the module Script::Singleton it will look for the file in a subdirectory named Script underneath one of the directories specified in @INC.

        So if you want to reference it from /home/demo/pullWorkload/scpLRSIControllerDir/toys, you need to create /home/demo/pullWorkload/scpLRSIControllerDir/toys/Script (with mkdir), and put the file in that directory.

        I would recommend this as a temporary solution only. For CPAN modules it is almost always preferable to keep them in a separate place - see other people's suggestions for how to do that.

        The handling of :: in module names is not trivial to find in the documentation. From perldoc -f use you will see that use Script::Singleton; is exactly equivalent to BEGIN { require Script::Singleton; Script::Singleton->import(); }. You then need to understand that since Script::Singleton is not in quotes, it is what perl calls a "bareword", and then find the part of perldoc -f require that describes this:

        If EXPR is a bareword, "require" assumes a .pm extension a +nd replaces "::" with "/" in the filename for you, to make it + easy to load standard modules.
Re: Modules 101 :: Using a Local Module from CPAN
by Fletch (Bishop) on Dec 06, 2022 at 17:42 UTC

    Rather than copying things around willy nilly by hand you'll be better served using local::lib to set up a local directory you can use CPAN (or App::cpanminus) to actually install modules the "right" way.

    See also Yes, even you can use CPAN if there's administrative obstacles.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Modules 101 :: Using a Local Module from CPAN
by GrandFather (Saint) on Dec 07, 2022 at 02:36 UTC

    Just to elaborate a little on hippo's reply, when you use SomePackage;, you aren't "running the SomePackage script", you are effectively including the source code for SomePackage in your own script. There is more magic that goes on than that, but the essence is that SomePackage packages up some Perly goodness for you and makes it easy to use from your script.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

      What GrandFather said. My code isn't a script. In Perl parlance, it's a module. In general programming parlance, it's a library.

      In Perl, a script is something that is executed; ie. a 'binary'. A module is something that is loaded into the script, and you can use its functionality via its Application Programming Interface (ie. API). We include a library in perl script by use of the use or require "pragma". Other programming languages have similar techniques, named differently (eg. 'import', 'include' etc).

      In this specific module (Script::Singleton), things are a bit different. There is no API. Just by loading (ie. 'use') the module, all of its functionality is executed inline during the compile phase of the script build. If you're interested, I wrote an explanation of the build/run phases of a perl script many years ago. I can't vouch for how good it is though as I've not time to read it right now ;)

      OP: you're coming far young grasshopper. Keep up the good work.

Re: Modules 101 :: Using a Local Module from CPAN
by hippo (Bishop) on Dec 06, 2022 at 22:33 UTC
    It was a bolt of lightning when I realized that Script::Singleton was another script, and all I needed to do was copy that script from the site**, save it in a local directory, and then have my script run his script.

    As you've alluded to later on in your post this is in fact a module rather than a script - it is to be used rather than run. As such you should really install the module properly rather than just copy a single file. This (installing the module) will save you from your current problems of hunt-the-file.

    Here in the Monastery there are several Tutorials for installing modules and while they are quite old now, the principles are sound. See also the Perl FAQ: How do I install a module from CPAN?

    In the case of Script::Singleton you will also need the dependencies, if those are not already installed. Following the installation process as in the documents referenced above will at least inform you of what you are missing and in some cases, automatically install those dependencies as well.

    Hopefully this helps to clarify things but do come back if you have further questions or get stuck.


Re: Modules 101 :: Using a Local Module from CPAN
by bliako (Monsignor) on Dec 07, 2022 at 08:51 UTC

    Install modules as Re: Modules 101 :: Using a Local Module from CPAN has already said. This is the simplest and most orthodox way. There are caveats if you do that as root, for example you can mess up with system perl (rare but possible). So perhaps set up a local install dir as others said in order to install as normal user, or use perlbrew.

    BTW, (and jokingly) are you coming from a visual basic background at all?

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11148616]
Front-paged by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (1)
As of 2023-06-07 22:39 GMT
Find Nodes?
    Voting Booth?
    How often do you go to conferences?

    Results (29 votes). Check out past polls.