perloracle-databasedbidbdenv

%ENV doesn't work and I cannot use shared library


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?


Solution

  • 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;
      }