%ENV不起作用,我不能使用共享库

时间:2011-12-28 14:15:39

标签: perl oracle dbi dbd env

我不能在我的Perl脚本上使用%ENV var来使用Oracle库。

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'}似乎一切正常,但是,当我运行我的脚本时,我有错误:

  

install_driver(Oracle)失败:无法为模块DBD加载'/usr/local/lib64/perl5/auto/DBD/Oracle/Oracle.so':: Oracle:libclntsh.so.10.1:无法打开共享对象file:/usr/lib64/perl5/DynaLoader.pm第200行没有这样的文件或目录。    在(评估3)第3行   在(eval 3)第3行的require中编译失败。   可能未在预期的位置安装所需的共享库或dll    在persistence.perl第22行

在网上搜索我发现在Perl上设置env变量的正确方法是使用%ENV哈希。

通过unix shell(ORACLE_HOME)导出LD_LIBRARY_PATHexport LD_LIBRARY_PATH=...,它可以正常工作。有什么建议吗?

5 个答案:

答案 0 :(得分:10)

在程序启动之前,必须先设置LD_LIBRARY_PATH环境变量 - 在perl本身加载之前。在BEGIN{}中更改它会影响您启动的新程序,但它不会影响共享库的加载 - 在这种情况下(尽管我已经从未使用DBD :: Oracle)您正在将Oracle .so加载到已经运行的程序中,因此更改LD_LIBRARY_PATH“为时已晚”。动态链接器/lib/ld.so(或左右)在perl之前启动,因此在编译脚本并运行BEGIN{}时,它已经设置好了。

可以尝试重新执行你的脚本作为自己的继承者或者其他东西*,但是短的shell脚本几乎肯定是最简单的解决方案:

  #!/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 "$@"

* - 这有点疯狂,但是TIMTOWTDI:

  eval { 
     use DBD::Oracle foo bar baz; …
  };
  if ($@ =~ /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\n$@\n";
     exec { $0 } $0 => @ARGV;
  }

答案 1 :(得分:1)

我写了一些测试脚本来验证更改%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脚本正在运行test.sh,它打印出在我的Perl脚本中设置的$FOO环境变量的值。正在运行test.pl

This is what I got bar-bar

这表明Perl不仅设置了环境变量,而且还导出了这些变量,因此所谓的shell脚本可以访问它们。

您可以尝试使用类似的方法来验证LD_LIBRARY_PATHORACLE_HOME在使用之前是否已设置。我怀疑你会发现确实发生了这种情况,但是当你设置%ENV时你的程序仍无法正常工作。

这指出了一个结论:在Perl脚本启动时,设置LD_LIBRARY_PATHORACLE_HOME的环境可能发生得太晚了。我相信操作系统会在Perl启动之前检查LD_LIBRARY_PATH。我发现这是在LD_LIBRARY_PATH上搜索:

  

LD_LIBRARY_PATH是一个环境变量,您设置为为运行时共享库​​加载器(ld.so)提供一组额外的目录,以便在搜索共享库时查找。可以列出多个目录,用冒号(:)分隔。此列表前置于给定可执行文件的现有已编译加载程序路径列表以及任何系统缺省加载程序路径。

因此,LD_LIBRARY_PATH用于ld.so运行时共享库​​加载器,如果已加载ld.so,则更改LD_LIBRARY_PATH将不会执行任何操作。

我在Perl Monks上发现了类似的讨论。我注意到有人发现rerunning env似乎有效。

答案 2 :(得分:0)

一种解决方案是修改/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

答案 3 :(得分:0)

您可以将export命令放入unix shell的启动脚本中,您应该有权编辑它。这样,每当你启动一个新shell时都会设置环境变量,所有使用Oracle的脚本和程序都会选择它们。

答案 4 :(得分:-1)

我刚刚经历过类似的事情。我必须确保在其他任何调用它之前设置了Oracle环境。确保BEGIN块在任何其他“use”语句之前。在我的情况下,在Apache的httpd.conf文件中调用了一些东西,所以我不得不在那里而不是在我的包中设置我的环境。