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

发布于 2024-12-23 13:11:58 字数 960 浏览 2 评论 0原文

我无法在 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::Oracle 的“/usr/local/lib64/perl5/auto/DBD/Oracle/Oracle.so”:libclntsh.so.10.1:无法打开共享对象文件:/usr/lib64/perl5/DynaLoader.pm 第 200 行没有这样的文件或目录。 在 (eval 3) 第 3 行 (eval 3) 第 3 行的 require 编译失败。 也许所需的共享库或 dll 没有安装在预期的位置 在 persistence.perl 第 22 行

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

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

I cannot use %ENV var on my Perl script to use 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;
};

If I print $ENV{'ORACLE_HOME'} and $ENV{'LD_LIBRARY_PATH'} all seems ok but, when I run my script I have the error:

install_driver(Oracle) failed: Can't load '/usr/local/lib64/perl5/auto/DBD/Oracle/Oracle.so' for module DBD::Oracle: libclntsh.so.10.1: cannot open shared object file: No such file or directory at /usr/lib64/perl5/DynaLoader.pm line 200.
at (eval 3) line 3
Compilation failed in require at (eval 3) line 3.
Perhaps a required shared library or dll isn't installed where expected
at persistence.perl line 22

Searching on web I saw that the correct way to set env vars on Perl is to use %ENV hash.

Exporting ORACLE_HOME and LD_LIBRARY_PATH through unix shell (export LD_LIBRARY_PATH=...) it works correctly. Any advice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你在我安 2024-12-30 13:11:58

LD_LIBRARY_PATH 环境变量必须在程序启动之前设置 - 在 perl 本身加载之前。在 BEGIN{} 中更改它会影响您启动的新程序,但不会影响共享库的加载 - 在本例中(虽然我从未使用过 DBD::Oracle)您正在将 Oracle .so 加载到已经运行的程序中,因此更改 LD_LIBRARY_PATH 已经“太晚了”代码>.动态链接器 /lib/ld.so (或 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;
  }

The LD_LIBRARY_PATH environment variable has to be set before your program starts — before perl itself is loaded. Changing it in BEGIN{} will affect new programs that you start, but it won't affect the loading of shared libraries — in this case (although I've never used the DBD::Oracle) you're loading an Oracle .so into the already-running program, so it's “too late” to change the LD_LIBRARY_PATH. The dynamic linker /lib/ld.so (or so) is started before perl, so by the time your script is compiled and BEGIN{} runs, it's already set up.

You could try to re-exec your script as its own successor or something*, but a short shell script is almost certainly going to be the simplest solution:

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

*- this would be kinda crazy, but 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;
  }
茶色山野 2024-12-30 13:11:58

我编写了一些测试脚本来验证当您更改 %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< /code> 不会做任何事情。

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

I wrote a few test scripts to verify that the environment is being set when you change %ENV:

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

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

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

This prints out:

printing out bar-bar

which is what I expected.

I then tried this:

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

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


system qq(./test.sh);

and created a test.sh program that looks like this:

#! /bin/sh

echo This is what I got: $FOO;

In this case, my Perl script is running test.sh which prints out the value of the $FOO environment variable that was set in my Perl script. Running test.pl I get:

This is what I got bar-bar

This shows that not only is Perl setting the environment variables, but that it is also exporting those variables, so called shell scripts have access to them.

You can try a similar technique to verify that both LD_LIBRARY_PATH and ORACLE_HOME are being set before they're used. I suspect you'll find that this is indeed happening, but that your program still isn't working when you set %ENV.

This points to one conclusion: Setting the environment for LD_LIBRARY_PATH and ORACLE_HOME might be occurring too late by the time your Perl script starts. I believe the operating system examines LD_LIBRARY_PATH before Perl starts. I found this doing a search on LD_LIBRARY_PATH:

LD_LIBRARY_PATH is an environment variable you set to give the run-time shared library loader (ld.so) an extra set of directories to look for when searching for shared libraries. Multiple directories can be listed, separated with a colon (:). This list is prepended to the existing list of compiled-in loader paths for a given executable, and any system default loader paths.

So, LD_LIBRARY_PATH is for the ld.so runtime shared library loader, If ld.so has already been loaded, changing LD_LIBRARY_PATH won't do anything.

I found a similar discussion on Perl Monks. I noticed someone found rerunning env seemed to work.

他是夢罘是命 2024-12-30 13:11:58

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

One solution is to modify /etc/ld.so.conf

On CentOS/RHEL 6.4, you could create etc/ld.so.conf.d/oracle with this:

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

Obviously, modify as suits your ORACLE_HOME.

Then run

ldconfig -v
半夏半凉 2024-12-30 13:11:58

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

You could put the export commands into the start up script for your unix shell which you should have permission to edit. That way, the environment variables will be set whenever you start a new shell and all scripts and programs that use Oracle will pick them up.

極樂鬼 2024-12-30 13:11:58

我刚刚经历过类似的事情。我必须确保 Oracle 环境在其他任何调用之前已设置完毕。确保 BEGIN 块位于任何其他“use”语句之前。就我而言,Apache 的 httpd.conf 文件中正在调用某些内容,因此我必须在那里设置我的环境,而不是在我的包中。

I just went through something similar. I had to make sure that the Oracle environment was setup before anything else called it. Make sure the BEGIN block is before any other "use" statements. In my case, something was being called in Apache's httpd.conf file, so I had to setup my environment there instead of in my package.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文