http://www.perlmonks.org?node_id=1001090

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

Hi Monks,

I'm looking for some wisdom regarding inclusion of custom libs in a project. Bear with me, for this problem is a bit trickier than just a simple:

use lib qw(/path/to/my/libs);

In all of my searching, I have not found a good answer for this one, so perhaps the enlightened can assist?

First, the restrictions for this project:

  1. Modules which need to be compiled may NOT be installed.
  2. Custom modules may NOT be added to the system lib paths.
  3. Environment variables may NOT be modified.
  4. The MyApp package can be installed anywhere on a system.

Next, a visual to understand the contents of the project.

~/MyApp |_ /1.0 |_ /1.1 |_ /1.2 |_ /bin |_ script1.pl |_ /util |_ script2.pl |_ /lib |_ /perl |_ Module1.pm |_ Module2.pm |_ /plugins |_ /default |_ plugin1.pl |_ /custom |_ plugin2.pl |_ plugin3.pl |_ /Dir1 |_ Dir2 |_ plugin4.pl

Every perl script in /bin and /plugins needs to have access to the custom modules in ~/lib/perl, regardless of how deep into the directory tree the script is.

To tackle this problem, I have been adding the following block to the header of all the scripts. Basically, I climb the directory tree, until I find the toplevel that looks like the version number, "1.2", and then include /lib/perl from there.

use strict; use warnings; use File::Spec; use Cwd 2.17 qw(realpath); eval { use lib (eval { my @dirs = File::Spec->splitdir( (File::Spec->splitpath(realpath($0)))[1] ); while (scalar(@dirs) and $dirs[-1] !~ /\d+\.\d+/) { pop(@dirs); } return File::Spec->join(@dirs, 'lib', 'perl'); } ); use Module1; use Module2; }; if ($@) { die "Failed to load custom modules.\n"; }

It works perfectly, but it looks and feels clunky. Also, the eval{} blocks raise eyebrows, and I'd feel better if they weren't there.

Is there a cleaner way to do this? Can I get rid of the eval{} blocks completely? Have I overlooked a much simpler way to do this?

--Many Thanks!

Replies are listed 'Best First'.
Re: Creative way to include custom modules without eval?
by tobyink (Canon) on Oct 26, 2012 at 14:36 UTC

    I'm pretty sure that FindBin::libs could help you out here.

    Either way, the evals seem a bit pointless. do would do the trick...

    use strict; use warnings; use File::Spec; use Cwd 2.17 qw(realpath); use lib do { my @dirs = File::Spec->splitdir( (File::Spec->splitpath(realpath($0)))[1] ); pop @dirs while (scalar(@dirs) and $dirs[-1] !~ /\d+\.\d+/); File::Spec->join(@dirs, 'lib', 'perl'); }; use Module1; use Module2;
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Ah! Many thanks, tobyink.

      That is a much nicer block of code. Using 'do' never even occurred to me!

      +10 Karma points for you.

Re: Creative way to include custom modules without eval? (FindLib)
by tye (Sage) on Oct 27, 2012 at 06:09 UTC
Re: Creative way to include custom modules without eval?
by Anonymous Monk on Oct 26, 2012 at 15:29 UTC