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

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

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

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

8 ответов


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

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

perldoc FindBin дополнительные.


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


Я обычно использую эту технику. Его печально вдохновил из моих дней 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__ ); 

модуль "FindBin" будет работать только в том случае, если каталог, в котором находится скрипт perl, находится в вашем системном пути, иначе он потерпит неудачу. Преодолеть это вы можете манипулировать значение, чтобы получить информацию о пути к 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() );

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

use lib $path;

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


мое решение:

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

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

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 разделитель.


use lib './';

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

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

use lib './bin/';

Как насчет:

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

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