Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use an external lib in a BEGIN block

Tags:

perl

I want to use an external library in the BEGIN block of a Perl script. The first test which I did was to check whether my @INC is getting popullated if I push some values:

use strict;
use warnings;

BEGIN {
    push @INC, "d:/external_pm/";

    use Data::Dumper;
    print Dumper @INC;
}

Which works as expected and shows:

$VAR1 = 'D:/perl/5163/site/lib';
$VAR2 = 'D:/perl/5163/lib';
$VAR3 = '.';  # I am not sure about this one?!
$VAR4 = 'd:/external_pm/';

Now I want to import a module right after the push:

use strict;
use warnings;

BEGIN {
    push @INC, "d:/external_pm/";

    use Data::Dumper;
    print Dumper @INC;
    use ExtScript;
}

The error which follows is showing me that @INC was not updated:
Can't locate ExtScript.pm in @INC (@INC contains: D:/perl/5163/site/lib D:/perl/5163/lib .) at file.pl line 9. BEGIN failed--compilation aborted at file.pl line 9.

Why the @INC it's not updating? I can't import a module in the BEGIN block? Or is a missusage of Perl?

like image 736
John Doe Avatar asked Dec 11 '22 09:12

John Doe


1 Answers

use statements are executed at compile time (specifically, during the BEGIN phase), whereas normal code is run later. Let's look at this simplified snippet:

BEGIN {
  push @INC, "some/dir";
  use Example;
}

If we spell out all phases explicitly, that would be equivalent to:

BEGIN {
  push @INC, "some/dir";
  BEGIN { require Example; Example->import() }
}

So the Example module will be imported before the push runs.

There are a number of ways to address this.

The simplest way is to put only the @INC manipulation into a BEGIN block, and import the module outside:

BEGIN { push @INC, "some/dir" }
use Example;

A better solution is to use the lib pragma to handle @INC:

use lib "some/dir";
use Example;

However, there is a major difference: use lib puts additional directories at the beginning of the module search path, so you may accidentally override other modules. push @INC only adds directories to the end, as a fallback if a module wasn't found in other locations.

like image 135
amon Avatar answered Jan 03 '23 01:01

amon