initialization of LD_LIBRARY_PATH in BEGIN block fails - perl

I have to add /oracle/v10.2.0/lib to LD_LIBRARY_PATH to use DBI module to connect to Oracle.
If I set LD_LIBRARY_PATH in shell before executing perl script, everything is ok.
But it does not work from script:
BEGIN {
$ENV{'LD_LIBRARY_PATH'}='/oracle/v10.2.0/lib';
}
use DBI;
When I execute the script I get the error:
install_driver(Oracle) failed: Can't load '/usr/apps/perl5/site_perl/5.8.8/i686-linux/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/apps/perl5/5.8.8/i686-linux/DynaLoader.pm line 230.
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 /var/tmp/getTraceDB.pl line 23

BEGIN {
$ENV{'LD_LIBRARY_PATH'}.='/oracle/v10.2.0/lib';
exec($^X, $0, #ARGV);
}
use DBI;
Refer Runtime Linker and LD_LIBRARY_PATH for proper description.

Far better would be to have LD_LIBRARY_PATH set in your .profile or similar. It has to be visible at the time the ELF loader starts up, which is waaay before even /usr/bin/perl is running, let alone the BEGIN block of your script. The exec() trick works by restarting the entire binary if it had to add the path, but better would be for it to always exist in your environment always.

Related

Perl can't find module listed in same directory as script

I need to keep any custom modules in the same-ish directory as my script.
I keep getting this error suggesting that Perl can't "see" the module I'm declaring
Global symbol "$employment_type" requires explicit package name at early_enrollments_by_term.pl line 260.
Execution of early_enrollments_by_term.pl aborted due to compilation errors.
My module is Hash.pm and is in directory /home/pgb2/canvas/canvas-sis-feeds/scripts/lib/Custom
Hash.pm
package Custom::Hash;
My script is early_enrollments_by_term.pl and lives in /home/pgb2/canvas/canvas-sis-feeds/scripts/
early_enrollments_by_term.pl
#!/usr/bin/perl
use strict;
use DBI;
use lib qw(/home/pgb2/canvas/canvas-sis-feeds/scripts/lib);
use Custom::Hash;
my $enrollment_type = $Custom::Hash::enrollment_hash{$role}; # line 259
print "\nenrollment_type: $employment_type\n"; # line 260
Would anyone be able to tell why it's not finding the module?
Although you have shown very little of your code,
the problem would presumably be that you have declared $enrollment_type and tried to use $employment_type, which has not been declared
Had perl been unable to find the module, it is the use Custom::Hash statement that would throw the error

.exe crated using Par::Packer with script containing Net::SSH2 is not working

Am using Net::SSH2 module in my Perl script and trying to make an executable (.exe for windows) using Par::Packer. The script need to ssh to a linux box from a windows box using public keys and don't want to input password.
Am facing the below error while running the .exe
Can't load
'C:\Users...\AppData\Local\Temp\par-73656172756d7567616d\cache-a6d57d5a234829aae84d08c4a78a09ad307ea8d3\a9057da2.xs.dll'
for module Net::SSH2: load_file:The specified module could not be
found at C:/Strawberry/perl/lib/DynaLoader.pm line 193. at
C:/Strawberry/perl/vendor/lib/PAR/Heavy.pm line 123.
Tried to workaround with the below methods but none of them worked
Tried to pack from a portable version of Strawberry Perl
Tried to link a9057da2.xs.dll while packing using Par::Packer
Is there any workaround or fix for packing the perl scrip to .exe with Net:SSH2.
Or are there alternatives to Net::SSH2 for ssh from windows to Linux using public keys (not passing passwords)?
If you get something like:
Can't load D:\TEMP\par-76696b616d7768\cache-48ca417d0c47dd7f7245a1218d8d6614470afa93\7c34139c.xs.dll' for module XML::LibXML: load_file:The specified module could not be found at <embedded>/DynaLoader.pm line 193.
at <embedded>/PAR/Heavy.pm line 140.
BEGIN failed--compilation aborted at D:\TEMP\par-76696b616d7768\cache-48ca417d0c47dd7f7245a1218d8d6614470afa93\inc\lib/XML/LibXML.pm line 156.
Compilation failed in require at script/test.pl line 3.
BEGIN failed--compilation aborted at script/test.pl line 3.
then add the following test code
(check your path to Listdlls.exe and fix the below as needed)
#This is the code causing the issue
use XML::LibXML;
my $x = XML::LibXML->new();
ListPerlDLLs();
sub ListPerlDLLs
{
my #ret = `C:\\"Program Files"\\Sysinternals\\Listdlls.exe $$`; # $$ : current PID
foreach my $line (#ret)
{
$line =~ s/\s$//;
next if $line !~ /^0x\w+\s+\w+\s+(.+)/;
my $dll = $1;
next if $dll =~ /^c:\\windows\\/i;
print "$dll\n";
}
}
The Listdlls.exe is from Microsoft - see SysInternals \
First, double-click Listdlls.exe to accept the disclaimer
(will ask for approval on first launch).
When you run the Perl script, you will get something like this:
D:/strawberry-perl/perl/bin/perl.exe
D:/strawberry-perl/perl/bin/perl532.dll
D:/strawberry-perl/perl/bin/libgcc_s_seh-1.dll
D:/strawberry-perl/perl/bin/libwinpthread-1.dll
D:/strawberry-perl/perl/bin/libstdc++-6.dll
D:/strawberry-perl/perl/lib/auto/Encode/Encode.xs.dll
D:/strawberry-perl/perl/lib/auto/Fcntl/Fcntl.xs.dll
D:/strawberry-perl/perl/lib/auto/Storable/Storable.xs.dll
D:/strawberry-perl/perl/lib/auto/Data/Dumper/Dumper.xs.dll
D:/strawberry-perl/perl/lib/auto/IO/IO.xs.dll
D:/strawberry-perl/perl/vendor/lib/auto/XML/LibXML/LibXML.xs.dll
D:/strawberry-perl/c/bin/libxml2-2__.dll
D:/strawberry-perl/c/bin/libiconv-2__.dll
D:/strawberry-perl/c/bin/liblzma-5__.dll
D:/strawberry-perl/c/bin/zlib1__.dll
D:/strawberry-perl/perl/lib/auto/List/Util/Util.xs.dll
if you build your EXE and run it, you will get something like:
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/test.exe
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/perl532.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/libgcc_s_seh-1.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/libwinpthread-1.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/libstdc++-6.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/5461bd7b.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/1ed3ae5b.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/89b9c18b.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/18f23f26.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/0e796a00.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/5d0ea4ea.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/d3d27bc6.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/d8bcc032.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/64916f0f.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/76c6a0cc.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/6b1ff21f.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/4eceebd6.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/ebaed210.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/831f407e.xs.dll
D:/TEMP/par-76696b616d7768/cache-48ca417d0c47dd7f7245a1218d8d6614470afa93/7c34139c.xs.dll
D:/strawberry-perl/c/bin/libxml2-2__.dll
D:/strawberry-perl/c/bin/liblzma-5__.dll
D:/strawberry-perl/c/bin/zlib1__.dll
D:/strawberry-perl/c/bin/libiconv-2__.dll
The last four are the missing DLLs -
add them with --link parameters:
call pp test.pl -o test.exe --link D:/strawberry-perl/c/bin/libxml2-2__.dll --link D:/strawberry-perl/c/bin/liblzma-5__.dll --link D:/strawberry-perl/c/bin/zlib1__.dll --link D:/strawberry-perl/c/bin/libiconv-2__.dll
Probably you are not packing the libssh2 and openssl DLLs inside the executable.
Par::Packer does not detect DLL dependencies automatically, you need to tell it explicitly which ones your program needs (a simple way to discover which DLLs your program needs is to use Process Monitor, an utility which allows one to monitor process activity).
Another option is to use my module Win32::Packer to pack the application which does find DLL dependencies automatically.

twiki "Failed to load the perl module FindBin."

I am trying to get TWIKI to work (virtual Server Hosteurope .. PLESK 11 CentOS 6).
When I run the configure script the following error appears:
[root#lvpsx.x.x.x bin]# ./configure
Failed to load the perl module FindBin. The module was found at /usr/share/perl5/FindBin.pm
Please ensure that:
1 FindBin is installed,
2 that the module is available on the #INC path,
3 that the webserver user (root) has permission to read the FindBin.pm file.
The detailed error seen was:
Subroutine export_fail redefined at /usr/share/perl5/Carp.pm line 25.
Compilation failed in require at /usr/share/perl5/FindBin.pm line 95.
BEGIN failed--compilation aborted at /usr/share/perl5/FindBin.pm line 95.
Compilation failed in require at (eval 3) line 2.
BEGIN failed--compilation aborted at (eval 3) line 2.
I have only marginal knowledge about the usage of shells and much less experience with Perl.
I run the configure script as root. As Far as I know Apache runs as root too(PLESK 11).
FindBin.pm is located in the named dir and I already tried to set it to 777.
Try installing VMS::Filespec, which seems to be the module FindBin is trying to require.
On the shell:
cpanm VMS::Filespec
If that doesn't work (the command fails), then try first:
cpan App::cpanminus
...and then try the first command again.
HTH
Francisco

%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?
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;
}
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.
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
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.
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.

Compiling perl source using pp

I have a perfectly functioning perl script (written in bash terminal on debian linux) that fails to execute (on either linux or windows) when compiled using pp. This may relate to unmet dependencies in the build, but I do believe the following command packages all dependencies into the executable:
pp -o out.exe in.pl
When I say it is perfectly functioning, I mean that the intended output is generated with no errors if I invoke ./in.pl from a bash terminal.
I would like to create an executable that will run on either linux or windows (if a separate file is required for each OS, so be it).
These are the packages that are included in the source:
use strict;
use warnings;
use charnames ":short";
binmode(STDOUT,":utf8");
use Term::ANSIColor;
use Number::Format;
use Finance::Quote;
use Finance::QuoteHist;
use Date::Manip; # this may be included by Finance::QuoteHist
If it helps, here is the error message I get (warning, it's long):
ERROR: [config_var] invalid zone in SetDate
ERROR: [config_var] invalid zone in SetDate
Could not load either Text::CSV_XS or Text::CSV_PP : Can't locate Text/CSV_PP.pm in #INC (#INC contains: CODE(0x1422320) /tmp/par-username/cache-addd1cc2ee9285c150584c1853c2b67c0c482e7e/inc/lib /tmp/par-username/cache-addd1cc2ee9285c150584c1853c2b67c0c482e7e/inc CODE(0x11675b0) CODE(0x116ebc8)) at (eval 30) line 2.
BEGIN failed--compilation aborted at (eval 30) line 2.
at Finance/QuoteHist.pm line 13
Compilation failed in require at Finance/QuoteHist.pm line 13.
BEGIN failed--compilation aborted at Finance/QuoteHist.pm line 13.
Compilation failed in require at script/in.pl line 10.
BEGIN failed--compilation aborted at script/in.pl line 10.
Judging from the run-time errors, the problem may relate to unmet recursive dependencies (for instance, dependencies within Finance::QuoteHist). Perhaps these recursive dependencies should be included explicitly? This is my first time attempting to compile perl into an executable, so thanks for any guidance you can provide.
You might try to use the -x flag to pp as seen in the docs. It runs the script and checks for dependencies as it goes, which is more accurate than simply scanning for dependencies. I have needed this when using Tk and it worked wonders.