Форум программистов, компьютерный форум, киберфорум
Perl
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
1

Объясните пожалуйста про @INC

21.06.2013, 22:03. Показов 3538. Ответов 16
Метки нет (Все метки)

Всем привет. Не скажу, что совсем не умею писать на Perl но до недавнего времени обходился файлами с процедурами, которые подключались через "do файл". Но вот дёрнул леший меня решить сделать всё по уму. После чего я медленно выпал в ступор, в котором до сих пор прибываю.

Итак. Дано простейший модуль, который лежит в /var/www/proga/modules/Module.pm
Далее дан скрипт, который этот модуль хочет использовать: /var/www/proga/script.pl
Но скриптов таких планируется очень много, а место положения /var/www/proga может меняться и поэтому возникает вполне здравая мысль сделат некий общий конфиг, который будет всегда лежать в одном месте: /etc/sysconfig/proga.pl и подключаться во все скрипты.

/etc/sysconfig/proga.pl
---------------------
use lib ('/var/www/proga/modules');
---------------------

/var/www/proga/script.pl
----------------------
#!/usr/bin/perl

do "/etc/sysconfig/proga.pl";

use Module;
----------------------

А не тут-то было!
Can't locate Module.pm in @INC (@INC contains: /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.8/i386-linux-thread-multi /usr/lib/perl5/5.8.8 .) at ./script.pl line 5.

При этом если строку
use lib ('/var/www/proga/modules');
перенести в сам script.pl, то всё чудненько работает.
Но я НЕ ХОЧУ в каждом своём скрипте указывать путь, которые может поменяться и как следствие менять потом каждый скрипт.

Подскажите, ну как же победить эту хрень?

P.S. Попутно выяснилось, что конструкция "use lib (путь)", требует, что ПУТЬ всегда был задан явно - подстановка переменных туда не катит! О чём в документации ни слова почему-то. Да, я понимаю, что use срабатывает в момент компиляции, когда значение переменной ещё не определено, но это понимание нисколько не помогает мне понять как решить проблему!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.06.2013, 22:03
Ответы с готовыми решениями:

Пожалуйста, объясните нерадивому
Удаление каждого третьего элемента. -module(sample). -export(). remove_each_third() -> ...

Объясните пожалуйста про Тиц
Ребят! Помогите пожалуйста разобраться! Месяца два назад сделал сайт, узконаправленный по...

Объясните, пожалуйста, про float и clear
Вот здесь здесь показан пример вёрстки с двумя блоками, для которых задан float left и right, и ещё...

Объясните пожалуйста немного про Vbulletin
И так, решил остановиться на выборе этого форума. Очень много версий и лицензий. Мне надо...

16
351 / 221 / 25
Регистрация: 30.09.2012
Сообщений: 548
23.06.2013, 16:05 2
Для теста написал 2 программки.
1-я: test_use.pl
Perl
1
2
3
4
5
6
7
8
#!perl
 
use strict;
do("test_use1.pl");
 
my $x = "Просто строка для привлечения внимания\n";
 
print Dumper(@INC);
2-я: test_use1.pl
Perl
1
2
3
4
#!perl
 
use Data::Dumper;
use lib('.');
При запуске даёт вывод
Код
$VAR1 = '.';
$VAR2 = 'C:/strawberry/perl/site/lib';
$VAR3 = 'C:/strawberry/perl/vendor/lib';
$VAR4 = 'C:/strawberry/perl/lib';
>Exit code: 0    Time: 0.322
1
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
24.06.2013, 09:25  [ТС] 3
Всё, так. в @INC оно попадает даже при push(@INC, значение), но при использовании use, perl забивает на изменения внесённые в @INC
0
351 / 221 / 25
Регистрация: 30.09.2012
Сообщений: 548
24.06.2013, 11:45 4
В программе test_use.pl не встречается подключение модуля Data:umper. Тем не менее он нормально отрабатывает, потому что был подключён при вызове test_use1.pl. Попробуйте в Ваш "библиотечный" файл включить не только изменение @INC, но и подключение Ваших библиотек с изменённым @INC.
0
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
24.06.2013, 12:18  [ТС] 5
Мдя, извращёненько. Но вроде работает. Спасибо!

Добавлено через 10 минут
Однако! Есть закавыка! Получается, что я должен перечислить все необходимые мне модули в test_use1.pl. Но мне-то нужно не все, а только те, что будут использоваться конкретным скриптом!

Добавлено через 1 минуту
Видимо придётся писать свой аналог use с анализом INC и прогрузкой файла модуля через require с последующим import.
Другого способа как это решить я не вижу.
0
173 / 170 / 19
Регистрация: 31.08.2010
Сообщений: 570
24.06.2013, 12:24 6
Настоятельно рекомендую почитать книгу "Шварц Р., Фой Б., Феникс Т. - Perl. Изучаем глубже. 2-е издание", там все об этом написано. Например в "главе 10. Разработка больших программ" в разделе "С помощью do" написано, что данный способ не влияет на %INC, @INC и не обрабатывает ситуацию отстутствия файла. (читать сноску).

Ну и дальше по тексту описывается, как решить вашу проблему.
1
351 / 221 / 25
Регистрация: 30.09.2012
Сообщений: 548
24.06.2013, 12:28 7
Если найдёте простой и удобный способ решения Вашей проблемы, отпишитесь здесь, если не затруднит. Это поможет тем, кто столкнётся с аналогичной задачей.
0
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
24.06.2013, 12:31  [ТС] 8
Проблему решил так:
1. config.pl находится в понятном месте:

Perl
1
2
3
4
$main::BASE_DIR = '/var/proga';
push(@INC, $main::BASE_DIR . "/modules");
 
do $main::BASE_DIR."/bootstrap.pl";
2. В bootstrap.pl добавлена в самом начале подпрограмма

Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sub Include {
  my ($module) = @_;
  
  # только если ещё не загружен
  if (!defined $main::INCLUDES{$module}) {
    # Добавляем .pm в конец и заменяем :: на /
    my $modname = $module.'.pm';
    $modname =~ s/::/\//g;
  
    foreach my $dir (@INC) {
      if (-f "$dir/$modname") {
        require "$dir/$modname";
        import $module;
        $main::INCLUDES{$module} = 1;
      }
    }
  }
}
3. Теперь в любом скрипте можно спокойно юзать:
Perl
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/perl
 
use strict;
 
do '/etc/sysconfig/config.pl';
 
Include('MyModules::Module');
 
# функция из MyModules::Module
print getCurrentDate()."\n";
Главное что мне теперь всё понятно что и откуда берётся и как работает. И ниаких неявных хитростей, типа необработки @INC и прочей шелупени.
0
173 / 170 / 19
Регистрация: 31.08.2010
Сообщений: 570
24.06.2013, 13:30 9
Это не совсем правильно - это будет работать только до тех пор, пока вы работаете на своем компьютере, а если будете разворачивать на хостинг или на CPAN, то этот код уже не будет работать, т.к. там не будет '/var/proga'.

См. предыдущее мое сообщение.

Приведу пример как надо:

1. Структура каталогов:

Код
my_inc/
  my_inc.pl
  lib/
    My/
      Utils.pm
Utils.pm

Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package My::Utils;
 
our @EXPORT = qw/sum/;
our @EXPORT_OK = qw/mul/;
use base qw/Exporter/;
 
sub sum {
  my $tmp = 0;
  $tmp += $_ for @_;
  $tmp;
}
 
sub mul {
  my $tmp = 1;
  $tmp *= $_ for @_;
  $tmp;
}
 
1;
my_inc.pl

Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/perl -w
use Modern::Perl;
use utf8::all;
 
use FindBin '$Bin';
use lib "$Bin/lib";
 
use My::Utils qw/sum mul/;
 
my $sum_numbers = sum(1, 2, 3, 4, 5); # -> 15
say $sum_numbers;
 
my $mul_numbers = mul(1, 2, 3, 4, 5); # -> 120
say $mul_numbers;
------------

Добавлять путь к массиву @INC лучше с помощью unshift, а не push, т.к. Perl автоматически устраняет возможные конфликты имен между вашими файлами и библиотеками, установленными в системе, отдавая приоритет вашим библиотекам.

Вот еще пример правильног подключения модулей

Добавлено через 10 минут
Написано на основании глав 10 и 15 книги "Шварц Р., Фой Б., Феникс Т. - Perl. Изучаем глубже. 2-е издание"
0
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
24.06.2013, 13:54  [ТС] 10
Не подходит. Потому что lib относительно вызываемого скрипта не всегда будет в одном и том же месте.
Например часть скриптов проекта может относится к командной строке, часть к веб-интерфейсу и лежать они будут в разных папках. Моя штука сработает, ваша - нет.

Цитата Сообщение от TheAthlete Посмотреть сообщение
т.к. там не будет '/var/proga'.
/var/proga там не будет, но ОДНА правка в config.pl и всё будет находиться без проблем.

Цитата Сообщение от TheAthlete Посмотреть сообщение
Добавлять путь к массиву @INC лучше с помощью unshift, а не push, т.к. Perl автоматически устраняет возможные конфликты имен между вашими файлами и библиотеками, установленными в системе, отдавая приоритет вашим библиотекам.
Тут вы правы, но это актуально только если есть пересечение имён. Его не будет, но я всё-таки ваше замечание учту, спасибо.
0
173 / 170 / 19
Регистрация: 31.08.2010
Сообщений: 570
24.06.2013, 14:32 11
Цитата Сообщение от corochoone Посмотреть сообщение
Потому что lib относительно вызываемого скрипта не всегда будет в одном и том же месте.
Например часть скриптов проекта может относится к командной строке, часть к веб-интерфейсу и лежать они будут в разных папках
В таком случае есть несколько вариантов (дополняя данный):
1) использовать дополнение списка @INC с помощью переменной PERL5LIB
Код
$ export PERL5LIB=/home/user/my_inc/lib
2) использовать дополнение списка @INC с помощью ключа -I
Код
$ perl -I/home/user/my_inc/lib my_inc.pl
Цитата Сообщение от corochoone Посмотреть сообщение
/var/proga там не будет, но ОДНА правка в config.pl и всё будет находиться без проблем.
Это только для простых проектов, а для сложных это уже накладно.

В любом случае это все относится к архитектуре проекта. Такая архитектура как вы описали будет непереносима между компьютерами. Лучше вместо того, чтобы прописывать пути к самописным библиотекам, лучше либо оформить как CPAN-модули для повторного использования либо лучше продумать архитектуру.

Добавлено через 9 минут
Цитата Сообщение от corochoone Посмотреть сообщение
Но скриптов таких планируется очень много, а место положения /var/www/proga может меняться и поэтому возникает вполне здравая мысль сделат некий общий конфиг, который будет всегда лежать в одном месте: /etc/sysconfig/proga.pl и подключаться во все скрипты.
Так тут же все понятно - как раз в примере выше я использовал модуль FindBin, который возвращает полный путь к каталогу со сценарием, посредством которого мы добавляем каталоги поиска в список. т.е. если определить в скрипте /var/www/proga/script.pl модуль FindBin, то $Bin будет указывать на '/var/www/proga'
0
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
24.06.2013, 15:33  [ТС] 12
Цитата Сообщение от TheAthlete Посмотреть сообщение
использовать дополнение списка @INC с помощью переменной PERL5LIB
И наступить по полной программе при использования веб-окружений

Цитата Сообщение от TheAthlete Посмотреть сообщение
использовать дополнение списка @INC с помощью ключа -I
и опять это уводит нас от единого конфига, заставляя в заголовок каждого сприта прописывать ключ -I

Цитата Сообщение от TheAthlete Посмотреть сообщение
Это только для простых проектов, а для сложных это уже накладно.
Чем?

Цитата Сообщение от TheAthlete Посмотреть сообщение
Такая архитектура как вы описали будет непереносима между компьютерами
Она будет непереносима между Windows и UNIX. В остальном никаких причин для непереносимости невижу. Достаточно подправить ОДИН config.pl
0
Эксперт С++
7175 / 3234 / 77
Регистрация: 17.06.2009
Сообщений: 14,165
24.06.2013, 20:11 13
Куча скриптов на серверах
Чтобы не парить голову в скриптах пишем так
Perl
1
2
3
#!/usr/bin/perl -I/wrun/lib/
 
use lib1; use lib2;
Это под Linux

А Windows для сервера вообще не годится
0
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
24.06.2013, 20:16  [ТС] 14
угу, а если вам понадобится сменить каталог с /wrun/lib вы будете каждый скрипт править? Спасибо, не надо
0
Эксперт С++
7175 / 3234 / 77
Регистрация: 17.06.2009
Сообщений: 14,165
25.06.2013, 17:11 15
Нам не требовалось

Если потребуется совсем нетрудно написать скрипт который делает рекурсивный обход и заменяет шапку скриптов

В конце концов можно просто:
выкачать скрипты, c помощью UltraEdit заменить во множестве файлов
закачать скрипты обратно
1
76 / 62 / 24
Регистрация: 21.06.2013
Сообщений: 330
26.06.2013, 23:23  [ТС] 16
Тогда нечего и огород городить:
use lib (путь);
и не надо извращаться с ключиком -I

Цитата Сообщение от odip Посмотреть сообщение
В конце концов можно просто:
выкачать скрипты, c помощью UltraEdit заменить во множестве файлов
закачать скрипты обратно
Да ну? А если их не одна сотня, а у вас модемное соединение?
Ладно, это всё лирика. Скажу просто - ваш ответ мне не подходит.

Добавлено через 1 час 35 минут
А ларчик открывается намного проще:

Perl
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/perl
 
BEGIN {
do "/etc/sysconfig/config.pl";
}
 
use Module;
 
# функция из модуля
print probe();
а в config.pl

Perl
1
use lib ("/var/proga/modules");
Вся соль в блоке BEGIN, который выполняет до компиляции скрипта и таким образом нужный мне путь попадает куда должно! Вот и всё, ребята
0
Эксперт С++
7175 / 3234 / 77
Регистрация: 17.06.2009
Сообщений: 14,165
27.06.2013, 10:36 17
На каждый вызов скрипта производится лишнее действие - вызов еще одного скрипта
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.06.2013, 10:36

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Объясните, пожалуйста, про график функции распределения
Есть задача: Стрелок стреляет по мишени до первого попадания или пока не израсходует 4 патрона....

Объясните пожалуйста про public List<NeighboringCellInfo> getNeighboringCellInfo ()
Суть вопрос: Есть метод public List&lt;NeighboringCellInfo&gt; getNeighboringCellInfo () в инструкции...

Знающие люди, пожалуйста, объясните про Rx550, rx560 и rx460
Начитался всякого, теперь не знаю... Вот в чем дело: Была у меня AMD (ATI) Radeon RX 550 Gigabyte...

Объясните про вордпресс
Добрый день, помогите мне как начинающему блогеру разобраться в одном вопросе) Я хочу создать в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.