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

Dear all Monks:

I have writen a perl script, and It will be placed on both i386 and x86_64 arch boxes. I write it in a x86_64 box, and install the x86_64 modules I need in the local project directory, not the default /usr/lib or /usr/local/lib directory,like these:

"./lib/perl5/site_perl/5.8.5"; "./lib64/perl5/5.8.5/x86_64-linux-thread-multi"; "./lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi";
my crrent work directory is "/home/larry/project/client_script". And I add 'use lib...' to instruct the script to find the local modules, like these:
use lib "./lib/perl5/site_perl/5.8.5"; use lib "./lib64/perl5/5.8.5/x86_64-linux-thread-multi"; use lib "./lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi";
it works well in x86_64 box, but when I put this script in a i386 box, and also install the i386 modules I need in these directory:
"./lib/perl5/5.8.5/i386-linux-thread-multi"; "./lib/perl5/site_perl/5.8.5/i386-linux-thread-multi";
and add these "use lib...." to my script:
use lib "./lib/perl5/5.8.5/i386-linux-thread-multi"; use lib "./lib/perl5/site_perl/5.8.5/i386-linux-thread-multi";
so, finally, I install both i386 and x86_64 modules in my local project directory:
"./lib/perl5/site_perl/5.8.5"; "./lib64/perl5/5.8.5/x86_64-linux-thread-multi"; "./lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi"; "./lib/perl5/5.8.5/i386-linux-thread-multi"; "./lib/perl5/site_perl/5.8.5/i386-linux-thread-multi";
and add these "use lib..." in my script:
use lib "./lib/perl5/site_perl/5.8.5"; use lib "./lib64/perl5/5.8.5/x86_64-linux-thread-multi"; use lib "./lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi"; use lib "./lib/perl5/5.8.5/i386-linux-thread-multi"; use lib "./lib/perl5/site_perl/5.8.5/i386-linux-thread-multi";
then I try to run this script in i386 and x86_64 box respectively, It doesn't work!! This script can't find the right modules in both i386 and x86_64 boxes. For example, there are two arch "threads" module placed in my project directory:
./lib/perl5/5.8.5/i386-linux-thread-multi/threads.pm ./lib64/perl5/5.8.5/x86_64-linux-thread-multi/threads.pm
and when I try to run the script in a x86_64 box, it throws this error:
Can't load '/home/larry/project/client_script/lib/perl5/5.8.5/i386-lin +ux-thread-multi/auto/threads/threads.so' for module threads: /home/la +rry/project/client_script/lib/perl5/5.8.5/i386-linux-thread-multi/aut +o/threads/threads.so: cannot open shared object file: No such file or + directory at /usr/lib64/perl5/5.8.5/x86_64-linux-thread-multi/XSLoad +er.pm line 68.
when run in i386 box, it throws this error:
Can't load '/home/larry/project/client_script/lib64/perl5/5.8.5/x86_64 +-linux-thread-multi/auto/threads/threads.so' for module threads: /hom +e/larry/project/client_script/lib64/perl5/5.8.5/x86_64-linux-thread-m +ulti/auto/threads/threads.so: cannot open shared object file: No such + file or directory at /usr/lib/perl5/5.8.5/i386-linux-thread-multi/XS +Loader.pm line 68.
But, if I preserve the only right arch "use lib ..." respectively, It works well on both i386 and x86_64 boxes.
My question is: Is there any way to instruct the perl to load the right arch modules in both i386 and x86_64 boxes?

Replies are listed 'Best First'.
Re: How to instrust Perl to load the right modules based on architecture?
by perrin (Chancellor) on Oct 06, 2008 at 06:48 UTC
    You should not need to do any of this. When you say "use lib 'foo'" it also adds the architecture-dependent directories under foo/ automatically. This is documented in the man page for lib.
Re: How to instrust Perl to load the right modules based on architecture?
by GrandFather (Saint) on Oct 06, 2008 at 04:29 UTC

    You may be able to use Config's $Config{archname64} value to determine which include path to use. The following (untested) code may get you started:

    BEGIN { use Config; if ($Config{archname64}) { use LIB './lib64/perl5/5.8.5/x86_64-linux-thread-multi'; use LIB './lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-mul +ti'; } else { use LIB './lib64/perl5/5.8.5/i386-thread-multi'; use LIB './lib64/perl5/site_perl/5.8.5/i386-thread-multi'; } }

    Perl reduces RSI - it saves typing
      Aside from mispelling "lib", the order of execution is totally wrong. Your code is equivalent to:
      BEGIN { require Config; Config::->import(); require lib; lib::->import('./lib64/perl5/5.8.5/x86_64-linux-thread-multi'); require lib; lib::->import('./lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-m +ulti'); require lib; lib::->import('./lib64/perl5/5.8.5/i386-thread-multi'); require lib; lib::->import('./lib64/perl5/site_perl/5.8.5/i386-thread-multi'); if ($Config{archname64}) { # empty } else { # empty }

      Note that all four directories are added to @INC unconditionally because use statements are executed as soon as they are compiled. Fix:

      BEGIN { use Config; require lib; if ($Config{archname64}) { lib->import(qw( ./lib64/perl5/5.8.5/x86_64-linux-thread-multi ./lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi )); } else { lib->import(qw( ./lib64/perl5/5.8.5/i386-thread-multi ./lib64/perl5/site_perl/5.8.5/i386-thread-multi )); } }

      Update: Markup changes.

        Thanks, it works now.
        But I still a little confused with the "use lib" and the BEGIN block, which one is executed first, the "use lib" or the BEGIN block?
        And, I find that the BEGIN block's location makes difference. If I put it ahead of the script like this:
        use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use lib "$FindBin::Bin/lib/perl5/site_perl/5.8.5"; BEGIN { use Config; require lib; print "archname:$Config{archname}\n"; if ($Config{archname} =~ /^x86_64/) { print "x86_64\n"; lib->import( "$FindBin::Bin/lib64/perl5/5.8.5/x86_64-linux-thread-multi", "$FindBin::Bin/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread +-multi"); } else { print "i386\n"; lib->import( "$FindBin::Bin/lib/perl5/5.8.5/i386-linux-thread-multi", "$FindBin::Bin/lib/perl5/site_perl/5.8.5/i386-linux-thread-mul +ti"); } } use utf8; use threads; use Carp; use IO::Socket::SSL; use IO::Select; use Log::Log4perl;
        My script works well, but if I put the BEGIN block at the tail like this:
        use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use lib "$FindBin::Bin/lib/perl5/site_perl/5.8.5"; use utf8; use threads; use Carp; use IO::Socket::SSL; use IO::Select; use Log::Log4perl; BEGIN { use Config; require lib; print "archname:$Config{archname}\n"; if ($Config{archname} =~ /^x86_64/) { print "x86_64\n"; lib->import( "$FindBin::Bin/lib64/perl5/5.8.5/x86_64-linux-thread-multi", "$FindBin::Bin/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread +-multi"); } else { print "i386\n"; lib->import( "$FindBin::Bin/lib/perl5/5.8.5/i386-linux-thread-multi", "$FindBin::Bin/lib/perl5/site_perl/5.8.5/i386-linux-thread-mul +ti"); } }
        It throw the error "Can't locate Net/SSLeay.pm in @INC", and I can't find the right path in @INC.
        Where the BEGIN block exactly should be? The very beginning of the script, even before "use strict; use warnning"?

        I also change the $Config{archname64} to $Config{archname} and, use $Config{archname} =~ /^x86_64/ to decide whether It is a x86_64 host. Because I find that $Config{archname64} is empty(although existed) in both i386 and x86_64 Perl.

Re: How to instrust Perl to load the right modules based on architecture?
by Animator (Hermit) on Oct 06, 2008 at 06:48 UTC

    From perldoc lib:

    For each directory in LIST (called $dir here) the lib module also checks to see if a directory called $dir/$archname/auto exists. If so the $dir/$archname directory is assumed to be a corresponding architecture specific directory and is added to @INC in front of $dir. lib.pm also checks if directories called $dir/$version and $dir/$version/$archname exist and adds these directories to @INC.

    This means that:

    $ perl -V:archname
    archname='i486-linux';
    
    $ perl -V:version
    version='5.8.8';
    
    $ perl -wle 'use lib "TempLib";print for grep /TempLib/, @INC;'
    TempLib
    
    $ mkdir -p TempLib/i486-linux/auto
    $ perl -wle 'use lib "TempLib";print for grep /TempLib/, @INC;'
    TempLib/i486-linux
    TempLib
    
    $ mkdir -p TempLib/5.8.8/auto
    $ perl -wle 'use lib "TempLib";print for grep /TempLib/, @INC;'
    TempLib/5.8.8
    TempLib/i486-linux
    TempLib
    
    $ mkdir -p TempLib/5.8.8/i486-linux/auto
    $ perl -wle 'use lib "TempLib";print for grep /TempLib/, @INC;'
    TempLib/5.8.8/i486-linux
    TempLib/5.8.8
    TempLib/i486-linux
    TempLib
    
    $ find TempLib/
    TempLib/
    TempLib/i486-linux
    TempLib/i486-linux/.auto
    TempLib/i486-linux/auto
    TempLib/5.8.8
    TempLib/5.8.8/auto
    TempLib/5.8.8/i486-linux
    TempLib/5.8.8/i486-linux/auto
    

    So the proper solution is to not include sepecific directory's in your use lib code but to create the correct directorys and let use lib figure out which architecture to use.

    update: Added output of find

      Finally, the 'use lib...' statements comes like this:
      use lib "$FindBin::Bin/lib/perl5"; use lib "$FindBin::Bin/lib/perl5/site_perl"; use lib "$FindBin::Bin/lib64/perl5"; use lib "$FindBin::Bin/lib64/perl5/site_perl";
      And, the script works well in both i386 and x86_64 boxes. But what's the difference between "lib/perl5" and "lib/perl5/site_perl", the lib module wouldn't add the 'site_perl' subdirectory automatically. what does "site_perl" mean?

        On my machine, I have lib and site\lib in my Perl directory. The former houses the core modules (those that come with Perl). The latter houses the rest. I suspect there is a parallel.