динамический путь perl, заданный для «использования lib» - PullRequest
3 голосов
/ 31 декабря 2010

Итак, мой код (скрипты Perl и модули Perl) находится в дереве примерно так:

 trunk/  
   util/  
   process/  
   scripts/  

В каталоге 'util' есть утилиты, которые находятся в каталоге 'process /'необходимость.Они получают доступ следующим образом:

use FindBin;
use lib "$FindBin::Bin/../util";
use UtilityModule qw(all);

Эта конструкция не заботится о том, с чего вы начинаете, если вы на том же уровне в дереве, что и "util /".
Но я решилаэтот «сценарий /» становился слишком тесным, поэтому я создал

   scripts/scripts1  
   scripts/scripts2  

Теперь я вижу, что это не работает.Если я запускаю скрипт «trunk / scripts / scripts1 / call_script.pl» и он вызывает «/trunk/process/process_script.pl», то «process_script.pl» не сможет получить подпрограммы из UtilityModule (), потому чтопуть, который возвращает FindBin, - это путь вызывающего скрипта верхнего уровня.

Первые десять способов решить все это включали что-то вроде:

use lib $path_that_came_from_elsewhere;

, но, похоже, Perl не любит это делать, кроме как с помощью этого трюка с FindBin.

Я пробовал кое-что, касающееся блоков BEGIN {}, но я действительно не знаю, что я там делаю, и, скорее всего, в итоге просто произойдет рефакторинг.Но если у кого-то есть умное понимание проблемы такого типа, это хороший шанс заработать несколько очков!

Ответы [ 6 ]

6 голосов
/ 31 декабря 2010

Рассматривали ли вы использование lib :: abs ? Одна из особенностей $FindBin (которая может быть ограничением в некоторых случаях, подобных вашему), заключается в том, что он работает относительно исполняемого двоичного файла, а не относительно вызывающего lib :: abs, с другой стороны, работает относительно модуля, в котором он находится. Кроме того, вы также можете использовать глобусы, такие как:

use lib::abs qw{../modules/*/somelib};
3 голосов
/ 31 декабря 2010

use - скрытый блок BEGIN, поэтому все, на что он ссылается, также должно быть определено во время BEGIN. Это относится к переменным в модуле FindBin, но не обязательно для других переменных.

# this will fail: $path is not yet defined at BEGIN time
my $path = '../util';
use lib $path;

# this ought to work
my $path;
BEGIN { $path = '../util' }
use lib $path;

Что касается того, чтобы заставить FindBin возвращать правильный каталог для обоих скриптов в / scripts и / scripts / scripts [12], это кажется мне сложным. И ваш вопрос по этому вопросу все еще немного расплывчат. На мой взгляд, вы должны иметь все скрипты в каталоге scripts / scriptN; таким образом ../../util всегда решает в нужном месте. Но я не уверен, что это относится к вашему делу.

2 голосов
/ 31 декабря 2010

Без учета ваших конкретных потребностей я часто использую этот фрагмент ( source <- последний комментарий), чтобы использовать локальные библиотеки без жесткого кодирования.Вы, вероятно, могли бы выполнить пошив без особой работы. </p>

use Cwd 'abs_path';
use File::Basename;
use lib dirname( abs_path $0 );

Примечание: с perldoc perlvar $0 Содержит имя выполняемой программы.

1 голос
/ 31 декабря 2010

Если ваши возможные местоположения соединительных линий не содержат «сценариев» где-либо на их пути (например, не существует «/ usr / scripts / stuff / trunk / scripts /», вы можете использовать подход, описанный здесь:

Как использовать бета-модули Perl из бета-сценариев Perl?

В основном используется специальная библиотека, которая анализирует путь сценария и изменяет @INC на местоположение, абсолютно соответствующее этому.путь (например, в вашем случае он находит каталог "/ prefix / scripts /" и добавляет "/prefix/scripts/../utils/" в @INC , даже если скрипт не находится в "/ prefix / scripts/ "но в" / prefix / scripts / scripts1 "

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

# Must be at the very beginning of your scripts
use Cwd 'abs_path';
BEGIN {
    my $full_path_script_name = abs_path($0);
    if ($full_path_script_name =~ !^(.+)/scripts/!) {
        my $prefix = $1;
        unshift(@INC, "$prefix/../util");
    }
}
0 голосов
/ 02 января 2011

Если вы хотите переименовать util в lib, тогда вы можете использовать пакет perl FindBin::libs.См.

http://metacpan.org/pod/FindBin::libs

Тогда вы можете просто сказать

use FindBin::libs;
use UtilityModule qw(all);

Для каждого из родительских каталогов сценария он будет искать подкаталог lib и использовать егокак расположение ваших модулей.

В вашем случае ваши скрипты в trunk/scripts/scripts1 будут проверять наличие trunk/scripts/lib, а затем trunk/lib для ваших модулей.

0 голосов
/ 31 декабря 2010

Я обычно использую префиксную команду сценария оболочки (обычно называемую toolchain) для управления рабочими средами PERL5LIB.

  • Проект /
    • Библиотека /
    • Util / Набор инструментов
    • бен / приложение

Набор инструментов:

 #!/bin/sh
 export PERL5LIB=$PWD/lib:$PERL5LIB
 export PATH=$PWD/util:$PWD/bin:$PATH
 exec $*

Ограничением этого скрипта является то, что вы всегда должны вызывать его из каталога проекта.

Звоните:

 % ./util/toolchain application

Это исключает ненужные use lib path из библиотек и исполняемых скриптов. Это оставляет это до рабочей среды (где это должно быть). Это также позволяет легко перемещать скрипты и библиотеки для производственной установки.

...