avarus.com.ar has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perlmonks :), I have some packages in /home/avarus/perl/myPackages/*.pm and what I want to do is to use that dir as a lib directory which is generally not a problem, but the first problem exists when I do the following:
my $libDir = "/home/avarus/perl/myPackages/"; use lib "$libDir";
This code does not really sets the lib path as expected but if I hard code this path instead of using this $libDir variable it simply works. So I decided to use a hardcoded lib path for testing purposes which exposed the next problem. In the directory "/home/avarus/perl/myPackages/" there is a package called "test.pm" which defines package "Test".
use lib "/home/avarus/perl/myPackages/"; use test; # works
this example works, but...
use lib "/home/avarus/perl/myPackages/"; my $packageName = "test"; use $packageName; # does not work, segfaults
At the moment I am working around this problem with "require" and bla::blub constructs but then I don't have the functionality I want to make use of as described in perldoc perlobj. When I solved all those problems the next one is how I can create a new instance like this:
my $objName = "foo"; my $testObj = new $objName();
this of course does not work, but that's like I wanna do that :). It would be great if you can give me some hints. Thanks in advance, Andreas Schipplock.

Replies are listed 'Best First'.
Re: Loading and using packages dynamically
by moritz (Cardinal) on Aug 30, 2007 at 11:42 UTC
    The first problem roots in the fact that the assignment to $libDir is executed at run time, but use is evaluated at compile time.

    One possible workaround is to do the assignement in a BEGIN block.

    use Foo qw(bar baz); is replaceable by require Foo; Foo->import(qw(bar baz)); which solves the next problem.

    You could also take a look at Module::Load.

Re: Loading and using packages dynamically
by bruceb3 (Pilgrim) on Aug 30, 2007 at 12:06 UTC
    The lines ...
    my $objName = "foo"; my $testObj = new $objName();

    work. Here is the code I used to test.

    #!/usr/bin/perl use strict; use warnings; package Foo; sub new { bless {}, shift; } package main; my $objName = "Foo"; my $obj = $objName->new(); my $obj1 = new $objName();

    BTW, you can use eval to use modules at runtime and capture problems finding the module, e.g.

    my $moduleName = "Foo"; eval "use $moduleName"; if ($@) { # could be problems with the loading of the module Foo .... }
      Special thanks to you! :-)
      sub new { bless {}, shift; }
      this really did the job!

      Thanks to all others helping me, too.

      See you, Andreas.
Re: Loading and using packages dynamically
by FunkyMonk (Bishop) on Aug 30, 2007 at 16:12 UTC
    Another way you can get round the problem you encountered with this code:
    use lib "/home/avarus/perl/myPackages/"; my $packageName = "test"; use $packageName; # does not work, segfaults

    is by "unwrapping" use. The documentation for use says

    [use] is exactly equivalent to BEGIN { require Module; import Module LIST; }
    Since your module is called Test, and doesn't import anything, you could just do
    my $file; # needs to be outside the BEGIN block BEGIN { $file = "Test.pm"; require $file; }

    You say your package is called Test, and defined in a file test.pm. Your operating system (Windows?) may treat Test.pm and test.pm as the same, but many other operating systems do not. You're better off getting in to the habit now of naming your package and file the same.

Re: Loading and using packages dynamically
by SFLEX (Chaplain) on Aug 30, 2007 at 13:15 UTC
    For your lib path I sometimes just add-in the path right to @INC
    push ( @INC, './home/avarus/perl/myPackages/'  );
    There could be danger in useing it or not...
      There are at least two problems with your suggestion:

    • It doesn't address the original problem that runtime actions are too late to help with use statements in the same file.

    • Qualifying the directory relative to the current directory, as you do in ./home/avarus/perl/myPackages/ makes the function dependent on the current directory. The script must be run in the directory where home/avarus/perl/myPackages lives for the modules to be found.

      Anno