% ENV не работает, и я не могу использовать общую библиотеку

Я не могу использовать %ENV var на моем Perl script для использования Oracle libs.

BEGIN {
    $ORACLE_HOME = "/usr/lib/oracle/10.2.0.3/client64";
    $LD_LIBRARY_PATH = "$ORACLE_HOME/lib";
    $ORACLE_SID="prod";
    $ENV{ORACLE_SID}=$ORACLE_SID;
    $ENV{ORACLE_HOME}= $ORACLE_HOME;
    $ENV{LD_LIBRARY_PATH}= $LD_LIBRARY_PATH;
};

Если я печатаю $ENV{'ORACLE_HOME'} и $ENV{'LD_LIBRARY_PATH'}, все выглядит нормально, но когда я запускаю свой script, у меня есть ошибка:

install_driver (Oracle) не удалось: невозможно загрузить '/usr/local/lib64/perl5/auto/DBD/Oracle/Oracle.so' для модуля DBD:: Oracle: libclntsh.so.10.1: не удается открыть общий объект file: Нет файла или каталога на /usr/lib 64/perl5/DynaLoader.pm строке 200.  на (eval 3) линии 3 Не удалось выполнить компиляцию в строке (eval 3) 3. Возможно, требуемая общая библиотека или dll не установлены там, где это ожидалось  на persistence.perl строка 22

Поиск в Интернете Я видел, что правильный способ установки env vars на Perl - использовать хеш %ENV.

Экспорт ORACLE_HOME и LD_LIBRARY_PATH через оболочку unix (export LD_LIBRARY_PATH=...) работает корректно. Любые советы?

Ответ 1

Переменная среды LD_LIBRARY_PATH должна быть установлена ​​до запуска вашей программы - перед загрузкой perl. Изменение его в BEGIN{} повлияет на запуск новых программ, но это не повлияет на загрузку разделяемых библиотек - в этом случае (хотя я никогда не использовал DBD:: Oracle) вы загружаете Oracle .so в уже запущенную программу, поэтому "слишком поздно" изменить LD_LIBRARY_PATH. Динамический компоновщик /lib/ld.so (или так) запускается до perl, поэтому к моменту скомпилирования script и BEGIN{} он уже настроен.

Вы можете попытаться повторно выполнить свой script как свой собственный преемник или что-то еще, но короткая оболочка script почти наверняка станет самым простым решением:

  #!/bin/sh
  export LD_LIBRARY_PATH=/usr/lib/oracle/10.2.0.3/client64/lib
  export ORACLE_SID=prod
  exec /usr/local/bin/your-db-program "[email protected]"

* - это было бы сумасшедшим, но TIMTOWTDI:

  eval { 
     use DBD::Oracle foo bar baz; …
  };
  if ([email protected] =~ /install_driver\(Oracle\) failed/) {
     $ENV{LD_LIBRARY_PATH} .= ':/usr/lib/oracle/10.2.0.3/client64/lib';
     $ENV{ORACLE_SID} = 'prod';
     warn "Restarting with LD_LIBRARY_PATH reset:\n\[email protected]\n";
     exec { $0 } $0 => @ARGV;
  }

Ответ 2

Я написал несколько тестовых скриптов, чтобы убедиться, что среда задается при изменении %ENV:

use strict;
use warnings;
use feature qw(say);

BEGIN {
    my $foo = "bar-bar";
    $ENV{FOO} = "$foo";
}

system qq(/bin/echo printing out \$FOO);

Это выдает:

printing out bar-bar

что я и ожидал.

Затем я попробовал это:

use strict;
use warnings;
use feature qw(say);

BEGIN {
    my $foo = "bar-bar";
    $ENV{FOO} = "$foo";
}


system qq(./test.sh);

и создал программу test.sh, которая выглядит так:

#! /bin/sh

echo This is what I got: $FOO;

В этом случае мой Perl script работает test.sh, который выводит значение переменной среды $FOO, которая была установлена ​​в моем Perl script. Запуск test.pl Я получаю:

This is what I got bar-bar

Это показывает, что не только Perl задает переменные среды, но и экспортирует эти переменные, так называемые shell-скрипты имеют к ним доступ.

Вы можете попробовать аналогичную технику, чтобы убедиться, что оба параметра LD_LIBRARY_PATH и ORACLE_HOME устанавливаются до их использования. Я подозреваю, что вы обнаружите, что это действительно происходит, но ваша программа все еще не работает, когда вы устанавливаете %ENV.

Это указывает на один вывод: установка среды для LD_LIBRARY_PATH и ORACLE_HOME может произойти слишком поздно к моменту запуска вашего Perl script. Я считаю, что операционная система проверяет LD_LIBRARY_PATH до начала Perl. Я нашел это, выполнив поиск по LD_LIBRARY_PATH:

LD_LIBRARY_PATH - это переменная среды, для которой вы устанавливаете значение , чтобы предоставить загрузчику разделяемой библиотеки времени выполнения (ld.so) дополнительный набор каталогов для поиска при поиске разделяемых библиотек. Можно указать несколько каталогов, разделенных двоеточием (:). Этот список добавляется к существующему списку скомпилированных путей загрузчика для данного исполняемого файла и к любым путям загрузчика по умолчанию.

Итак, LD_LIBRARY_PATH предназначен для загрузчика разделяемой библиотеки ld.so, если ld.so уже загружен, изменение LD_LIBRARY_PATH ничего не сделает.

Я нашел аналогичное обсуждение Perl Monks. Я заметил, что кто-то нашел reerunning env, похоже, работал.

Ответ 3

Одним из решений является изменение /etc/ld.so.conf

В CentOS/RHEL 6.4 вы можете создать etc/ld.so.conf.d/oracle с помощью этого:

/oracle/sw/product/11.2.0/dbhome_1/lib

Очевидно, измените, как подходит ваш ORACLE_HOME.

Затем запустите

ldconfig -v

Ответ 4

Вы можете поместить команды export в начало script для вашей оболочки unix, которая должна иметь разрешение на редактирование. Таким образом, переменные среды будут устанавливаться всякий раз, когда вы запускаете новую оболочку, и все сценарии и программы, использующие Oracle, будут их подбирать.

Ответ 5

Я просто прошел через нечто подобное. Я должен был убедиться, что среда Oracle была настроена до того, как ее еще называют. Убедитесь, что блок BEGIN находится перед любыми другими операциями использования. В моем случае что-то вызывалось в файле Apache httpd.conf, поэтому мне пришлось настраивать свою среду там, а не в моем пакете.