Как использовать модуль Perl из относительного местоположения?

У меня есть dir foo, и у меня есть lib и bin. Скрипты в bin нуждаются в материалах в lib. Я делаю что-то вроде этого:

#!perl
use strict;
use warnings;
use lib '../lib';
use Foo; # <-- comes from lib

Но это означает, что я должен быть в директории bin для запуска script. Конечно, есть лучший способ. Каков правильный способ сделать это?

Ответ 1

Стандартный FindBin модуль делает то, что вы хотите.

use FindBin;
use lib "$FindBin::Bin/../lib";

perldoc FindBin для более.

Ответ 2

Проведите полный путь к вашему .pl через __FILE__, а затем нажмите ../lib в конце или выскочите последний элемент split(/\//,__FILE__) и добавьте /lib к этому.

Ответ 3

Модуль "FindBin" будет работать только в том случае, если каталог, в котором находится perl script, находится в вашей системе PATH, иначе он потерпит неудачу. Чтобы преодолеть этот, вы можете манипулировать значением $0, чтобы получить информацию о своем пути к perl-модулю и передать значение use lib.

Что-то вроде этого -

BEGIN {
    use File::Spec::Functions qw(rel2abs);
    use File::Basename qw(dirname);

    #Covert the script path to absolute and get its directory name
    our $path = dirname( rel2abs($0) );

    #Replace the bin tag with lib to get module directory
    $path =~ s{bin/?$}{lib};
}

use lib $path;

EDIT: Модуль FindBin работает отлично и может быть использован, как описано в Майкл, ответьте. Мое понимание его работы было неполным, и поэтому привело меня к тому, чтобы сделать первый комментарий, который я теперь отвлекаю. Во всяком случае, я не вижу причин, почему этот метод не должен работать, хотя и с несколькими строками, чем может быть достигнуто с помощью FindBin (TMTOWTDI).

Ответ 4

Я обычно использую эту технику. Его печально вдохновили мои PHP-дни:

Его удобно в ситуациях, когда вы знаете, где данный файл будет относиться к текущему, и не уверены в точках входа, которые он может вызывать, или в окружающей среде во время вызова.

Однако я обычно использовал бы эту технику только для тестовых скриптов, которым нужны фиктивные библиотеки для эмуляции вещей.

use File::Basename ();
use Cwd            ();
my $base_dir;
my $relative_path; 
BEGIN {
    $realitive_path = '../../' # Path to base of project relative to the current file
    $base_dir = Cwd::realpath( File::Basename::dirname(__FILE__) .'/' . $relative_path );
}


use lib "${base_dir}/lib";
use Foo;

В идеале должен быть какой-то модуль где-то, который делает это, а если нет, то я получу соблазн написать один:

use Some::Module ();
use lib Some::Module::relative_self('../../lib', __FILE__ ); 

Ответ 5

Мое решение:

use lib substr(__FILE__, 0, rindex (__FILE__, "/"));

Ответ 6

Просто чтобы добавить свои собственные два цента в эту подборку ответов, я обычно решаю эту проблему, используя что-то в этих строках:

use lib do {
    use Cwd 'realpath';
    my ($dir) = __FILE__ =~ m{^(.*)/};  # $dir = path of current file
    realpath("$dir/../lib");            # path of '../lib' relative to $dir
};

Мне нравится использовать блок do, потому что все необходимое так аккуратно содержится в нем. Если вам когда-либо понадобится скопировать/вставить или попытаться понять ваш код позже, вам не придется искать отдельный блок BEGIN или что-то в этом роде.

В приведенном выше коде наивно предполагается, что / используется как разделитель dir/filename.

Ответ 7

use lib './';

работает для меня с Perl v5.14.2 в linux box, чтобы включить файлы в тот же каталог, что и мой script.

Возможно, вам будет полезно перемещать каталоги lib и bin в рабочем каталоге script и пытаться ссылаться на них с помощью

use lib './bin/';

Ответ 8

Как насчет:

BEGIN: {
    push @INC, '/full/path/to/lib';
}

Для выполнения относительной ссылки предполагается, что вы сохраните ее в каталоге bin, поэтому вместо этого вставьте вместо нее относительную ссылку.