Perl — Установка модулей perl в домашнюю директорию

Постепенно я прихожу к мысли, что лучше и проще для каждого приложения иметь свой набор модулей perl, не связанный ни с системой, ни с другими приложениями. Простой способ это обеспечить — устанавливать модули в домашнюю директорию. Это делает perlbrew + модуль App::cpanminus:

curl -L http://cpanmin.us | perl - App::cpanminus

Так как последняя версия Mojolicious не заработала в Debian Squeeze (Debian 6), установка perlbrew становится актуальной. Либо надо переходить на Debian 7, но и там только perl 5.14 .

Инструкцию я пишу по памяти, потом ещё раз проверю последовательность действий. Вкратце, устанавливаем нужную версию perl и /usr/local/perlbrew и добавляем модули при помощи cpanm. Perl получается один на сервер, но модули для него ставит каждый пользователь сам для себя. При обновлении версии perl (с сохранением major версии) надо будет каждому пользователю выполнить команду perlbrew switch

Мы создаём такую перловую инфраструктуру:

  • системный перл, /usr/bin/perl — перл из пакетов, в него не добавляется ничего кроме deb из репозитория;
  • ~/.perl5 — стандартная для системного перла директория, куда cpanm по-умолчанию будет класть модули из CPAN, при этом системная часть перла не трогается;
  • /usr/local/perlbrew — нужные версии перла, ставятся из-под пользователя perlbrew, выбор версии управляется вызовом perlbrew use или perlbrew switch
  • ~/.perl5-<версия perlbrew perl> — директория, куда cpanm будет класть модули для версий перла из perlbrew.

perl конфигурирутся на трёх уровнях:

  1. системный — по-умолчанию, вариант после вызова perlbrew off
  2. perlbrew — для текущего пользователя, вызовом perlbrew switch
  3. perlbrew — для текущего окружения (обычно инициализация окружения для конкретного перлового скрипта) вызовом perlbrew use

perl вызывается в разных окружениях, после интерактивного входа в систему — когда выполняются стандартные bashrc скрипты, и при вызове например из crontab, когда bashrc скрипты не выполняются.
В последнем случае надо вручную проинициализировать перловое окружение. Для инициализации будет написан скрипт .perlrc, устанавливающий нужные параметры. Это скрипт должен вызываться из .bashrc и из всех скриптов, запускающих перловые программы. Для разных версий perl нужны разные .perlrc, поэтому они будут именоваться .perlrc-<версия> , например .perlrc-5.16.3

perlbrew use и perlbrew switch, как мне кажется, надо вызывать из установочного скрипта (.perlrc) . Вообще говоря смысла в perlbrew switch при таком подходе нет.

Установить perlbrew

Создать пользователя perlbrew и дальше работать под ним. Можно и не создавать, но тогда perl будет установлен с рутовыми правами, и в рутовом окружении, что плохо.
Взять с http://perlbrew.pl и установить, например

#!shell
export PERLBREW_ROOT=/usr/local/perlbrew
# и не забыть сделать эту директорию с правами для perlbrew

# Вообще проще всего в /etc/profile прописать
# (и надо это сделать всё равно потом): 
#export PERLBREW_ROOT=/usr/local/perlbrew
#export PERLBREW_HOME=/tmp/.perlbrew

# PERLBREW_HOME=/tmp/.perlbrew рекомендуют авторы perlbrew
# для устранения странных ситуаций, но используется это при запуске
# *perlbrew switch*, так что далее я устанавливаю
# в ~/.perlrc export PERLBREW_HOME=~/.perlbrew. 

#mkdir /usr/local/perlbrew
#chown perlbrew.perlbrew /usr/local/perlbrew

aptitude install gcc make curl bison byacc
curl -kL http://install.perlbrew.pl | bash
perlbrew available
perlbrew install perl-5.16.3

сейчас при этом ставится и App::cpanminus, но может быть, потребуется запустить

#!shell
perlbrew install-cpanm

хотя не уверен что это имеет смысл делать — всё равно потом App::cpanminus придётся ставить под каждого пользователя.

Настроить cpanm — App::cpanminus

Это делается для каждого пользователя и для каждой версии перла. У одного пользователя может быть настроено несколько версий перла. Сначала казалось, что полезно для упрощения иметь для пользователя только одну версию, но эксперименты показали что иногда надо несколько.

Надо сделать файл ~/.perlrc , в котором будут лежать команды настройки перла. Можно было бы их поместить в ~/.bashrc , но если нужно выполнить скрипт из rc файла или из CRON, удобнее не выполнять весь .bashrc — там много ненужного. Но всё нужное надо перенести в .perlrc .

1) устанавливаем переменные окружения в ~/.perlrc-5.16.3

PERLBREW_ROOT устанавливается именно в .perlrc скрипте. Идеологически правильно устанавливать его в /etc/profile (там надо всё равно установить, под пользователем perlbrew это потребуется), но /etc/profile не вызывается из cron, а нам нужна унификация.

Oracle удобно настраивать тут же

#!shell
export LD_LIBRARY_PATH=/usr/local/lib/oracle/instantclient_10_2:$LD_LIBRARY_PATH
export PATH=/usr/local/lib/oracle/instantclient_10_2:$PATH
export PERLBREW_ROOT=/usr/local/perlbrew
export PERLBREW_HOME=~/.perlbrew
source ${PERLBREW_ROOT}/etc/bashrc
PERLVERSION=5.16.3
MY_PERL_LIB=~/perl5-$PERLVERSION
mkdir -p $MY_PERL_LIB
perlbrew use $PERLVERSION
export PERL_CPANM_OPT=" --local-lib=$MY_PERL_LIB"

export PATH=$MY_PERL_LIB/bin:$PATH
export PERL5LIB=$MY_PERL_LIB/lib/perl5:$PERL5LIB

Хитрость в том, что для каждой версии perl, которую установит perlbrew, надо иметь свою директорию, в которую cpanm будет ставить модули. Если perlbrew установлен один на всех пользователей — это мой случай — тогда его директория защищена от записи, cpanm не может установить модули в директорию в perlbrew, и ставит туда, куда указывает опция —local-lib . Почти невозможно (неудобно и с потенциальными трудноотлавливаемыми ошибками) для одного пользователя иметь несколько разных перлов как раз из-за того, что cpanm может принимать директорию с модулями от другой версии перла за свою собственную, поэтому надо ему всегда в явном виде указать perl5lib-<версия>

в .bashrc добавляем

#!shell
source ~/.perlrc-5.16.3

#или
#. ~/.perlrc

и не забываем сделать

#!shell
source ~/.bashrc

Теперь (после source ~/.perlrc-5.16.3) мы выбрали (для текущего окружения) версию perl и устанавливаем для него cpanm. Если не установить cpanm, будут трудноотлавливаемые ошибки.

#!shell
curl -L http://cpanmin.us | perl - App::cpanminus

при этом в $PERLBREW_HOME/init НЕ пишутся переменные для настройки версии перл, мы делаем не perlbrew switch, а perlbrew use

2) Устанавливаем gcc make

#!shell
aptitude install gcc make curl

Всё, теперь можно ставить модули

#!shell
cpanm Mojolicious
cpanm Data::Dump

Один из вариантов получения списка установленных где-то модулей и установки этих же модулей через cpanm:

#!shell
perl -MExtUtils::Installed -E 'say for ExtUtils::Installed->new->modules' > modules.txt
#PERL5LIB=~/perl5 perl -MExtUtils::Installed -E 'say for ExtUtils::Installed->new->modules' > modules.txt
cat modules.txt | cpanm --interactive --reinstall

После cpanm —interactive —reinstall я бы сделал ещё cpanm —interactive —install , чтобы увидеть возможные проблемы.

Использование в скриптах CRON и rc.local

Основное допущение, которое я сделал — каждый скрипт знает какая версия перла ему нужна, и сам её выбирает. Конечно, это можно было бы сделать и на уровне запускающего скрипт процесса, но тогда выбор версии перла перемещается на другой уровень, что ничем не лучше. Всё равно для каждого скрипта на perl надо ставить какие-то нестандартные модули.

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

#!shell
1-59/1 * * * * /home/user/script-home/bin/script-run.sh
#вместо
1-59/1 * * * * /bin/bash --rcfile ~/.perlrc -l /home/user/script-home/bin/script-run.sh

su - script-user -c "/bin/bash --rcfile ~/.perlrc -l ~/script-home/script-run.sh"

при этом script-run.sh доллжен содержать инструкцию

#!shell
. ~/.perlrc

su — script-user -c запустит .bashrc , но мы указали упрощённую его версию .perlrc .

или просто

#!shell
/bin/bash --rcfile ~/.perlrc -l ~/script-home/script-run.sh

Проблемы, на которые я нарывался

Не сработало:

#!shell
perlbrew install-cpanm

Причина — perlbrew был установлен в директорию, которая ему не принадлежала.Сработал другой способ:

#!shell
curl -L http://cpanmin.us | perl - App::cpanminus

но нет уверенности что это правильно.

PERLBREW_ROOT надо устанавливать обязательно!

Ссылки

Installing Multiple Perls with App::perlbrew and App::cpanminus

Leave a Reply