andyford has asked for the wisdom of the Perl Monks concerning the following question:

I want to get some info from an error that I get when I try to load a module, so I tried this:
eval { use Cache::File; };
But, it didn't stop the error from killing the program.

Update Added readmore tags.

It's this kind of error:
/usr/lib/dld.sl: Can't shl_load() a library containing Thread Local Storage: /usr/lib/libpthread.1 /usr/lib/dld.sl: Exec format error Can't load '/usr/local/perl-5.8.7/lib/5.8.7/PA-RISC2.0/auto/DB_File/DB_File.sl' for module DB_File: Exec format error at /usr/local/perl-5.8.7/lib/5.8.7/PA-RISC2.0/XSLoader.pm line 68. at /usr/local/perl-5.8.7/lib/5.8.7/PA-RISC2.0/DB_File.pm line 251 Compilation failed in require at /usr/local/perl-5.8.7/lib/site_perl/5.8.7/Cache/File/Heap.pm line 29. BEGIN failed--compilation aborted at /usr/local/perl-5.8.7/lib/site_perl/5.8.7/Cache/File/Heap.pm line 29. Compilation failed in require at /usr/local/perl-5.8.7/lib/site_perl/5.8.7/Cache/File.pm line 26. BEGIN failed--compilation aborted at /usr/local/perl-5.8.7/lib/site_perl/5.8.7/Cache/File.pm line 26. Compilation failed in require at ./tryCache line 6. BEGIN failed--compilation aborted at ./tryCache line 6.

Now, my question is not how to fix the error, but is there something like eval, some trick, some procedure that will let me capture the error from the use statement and go on to take remedial action based on the error?
Do I have to launch a separate process and capture the STDERR?

Now here's the background:
My fix looks like this

# fix for Cache::File BEGIN { if (!defined($ENV{LD_PRELOAD})) { $ENV{LD_PRELOAD} = '/usr/local/perl-5.8.7/lib/5.8.7/PA-RISC2.0 +/auto/DB_File/DB_File.sl'; my $me = "export LD_PRELOAD='$ENV{LD_PRELOAD}' && $0"; {exec $me} print STDERR "couldn't exec $me\n"; } elsif ($ENV{LD_PRELOAD} =~ /DB_File.sl/) { print "LD_PRELOAD is $ENV{LD_PRELOAD}\n"; } else { $ENV{LD_PRELOAD} = '/usr/local/perl-5.8.7/lib/5.8.7/PA-RISC2.0 +/auto/DB_File/DB_File.sl'.":$ENV{LD_PRELOAD}:" ; my $me = "export LD_PRELOAD='$ENV{LD_PRELOAD}' && $0"; {exec $me} print STDERR "couldn't exec $me\n"; } }
Now I'm OK with this, but I'd like to make it resilient to changes in perl or module location/version, so I'm thinking, capture the error output, get the location of the shared library and then put the variable in my BEGIN block.

andyford
or non-Perl: Andy Ford

Replies are listed 'Best First'.
Re: stronger than eval?
by cephas (Pilgrim) on Sep 21, 2006 at 18:47 UTC
    use statements are evaluated at compile time, so a block eval won't catch it. You can use a string eval if you need to force the use statement to happen at runtime.
    BEGIN { eval "use Cache::File"; if($@) { # Do remedial action } }
      This works great except STDERR gets printed to the console and $@ just gets STDOUT. Any way to fix that? Just so the user gets clean output...

      andyford
      or non-Perl: Andy Ford

        That's not quite right; $@ will get the exception (aka "die" message). Anything directly written out to STDERR or STDOUT will not be caught, unless you tie those filehandles (only works for output by perl) or reopen them. If the output is due to a warn, you can catch it with a $SIG{__WARN__} handler.
Re: stronger than eval?
by chorny (Scribe) on Sep 21, 2006 at 18:51 UTC
    Try
    eval { require Cache::File; };
    or eval "use Cache::File;";
    Use is executed in BEGIN stage, before eval is executed. It is valid even for eval BLOCK. eval SCALAR is other case.
      with require, you'll have to handle import manually.

        I see that as a plus, since it probably doesn't make sense to import from something which is conditionally imported. However, it's not hard to import if so desired.

        BEGIN { eval { require Cache::File } or warn("Proceeding without Cache::File\n"); Cache::File->import(qw( ... )) if Cache::File->can("import"); }

        or

        BEGIN { my @imports = qw( ... ); eval "use Cache::File \@imports" or warn("Proceeding without Cache::File\n"); }

        The BEGIN ensures prototypes are properly loaded.

Re: stronger than eval?
by mreece (Friar) on Sep 21, 2006 at 19:08 UTC

      do this with UNIVERSAL::require
      which no one should ever do. It pollutes the UNIVERSAL class which means it affects every class and every object.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        i agree with the second sentence, but not the first. ;-)