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

Hi, I have looked at internet but could not any info. Therefore I have to ask this stupid question:

I have installed Unicode::Map for Perl 5.8.5 as follows:

perl Makefile.PL PREFIX=/home make make install
I see then Unicode modules have been installed into:
/home/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi/auto/Unico +de /home/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi/Unicode

Now in this case when I run,

#!/usr/bin/perl -w use lib ("/home/lib/perl5/site_perl/5.8.5"); use Unicode::Map; print "RUNS\n";

I get

Can't locate Unicode/Map.pm in @INC (@INC contains: /home/lib/perl5/site_perl/5.8.5 /usr/lib64/perl5/5.8.5/x86_64-linux-thread-multi /usr/lib/perl5/5.8.5 /usr/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi /usr/lib64/perl5/site_perl/5.8.4/x86_64-linux-thread-multi...

Since all module I install go to /home/lib/perl5/site_perl/5.8.5, I thought it must be enough to use this directory and Perl is fairly intelligent to get Unicode directory. Now my questions:

  1. Why did installation put the Unicode stuff into 64-bit directories? My machine is 64-bit, is it default installation behaviour?
  2. Shall I explicitly add "use lib" argument for /home/perl5/site_perl/5.8.4/x86_64-linux-thread-multi?
  3. Is there any way in Perl to let all these lib-search stuff to the interpreter, so that I shan't worry about all these?
I know, these might be stupid questions but I can't find such simple information on internet. Thanks in advance and sorry for simple questions.

Replies are listed 'Best First'.
Re: Unicode::Map cannot be loaded
by graff (Chancellor) on Sep 27, 2008 at 16:15 UTC
    For some reason, when a module has to involve architecture-specific or perl-build-specific components (e.g. "x86_64-linux-thread-multi"), the sub-paths for keeping this distinct are not automatically included as part of the "additional" paths in @INC.

    So, even though you have "/home/lib/perl5/site_perl/5.8.5" already in @INC, this does not automatically extend to include the "x86_64-linux-thread-multi" subdirectory of that path, which is where essential components of this module got installed.

    To get around that, add to your normal shell environment a setting for "PERL5LIB", which includes both "/home/lib/perl5/site_perl/5.8.5" and "/home/lib/perl5/site_perl/5.8.5/x86_64-linux-thread-multi".

    Or, whenever you write a script that uses that module, add "-I" on the shebang line, with that latter path; or push that path onto @INC and then "require" the module.

    Both approaches (fixing the shell environment, adding the path in your scripts) have their down-sides for portability (every user has to modify their shell env., or every script has to have hard-coded paths). Maybe there's yet another way that's better, and if so, I hope someone will post that.

    (BTW: please use <code> tags, as per Writeup Formatting Tips, not <pre>, so that long strings get wrapped sensibly -- and/or, edit your post to add line breaks to the error message.) Thanks for fixing the formatting.

    UPDATE: In testing out the code snippet suggested in my second reply below, I came to understand the difference between these two shell environment variables that control perl's @INC at run-time:

    PERLLIB=... # does NOT interpolate to include OS/build-specific subpa +ths PERL5LIB=... # DOES interpolate to include OS/build-specific subpaths
    The proof (on my macosx/darwin/perl5.8.8 system) was that when I set "PERLLIB" to "/Users/graff/perl5/5.8.8", my script actually added "/Users/graff/perl5/5.8.8/darwin-thread-multi-2level" (because it existed but was not in @INC).

    But if I "unset PERLLIB" and instead set PERL5LIB to "/Users/graff/perl5/5.8.8", my script doesn't do anything, because @INC already has the "darwin-thread-multi-2level" subdir there.

Re: Unicode::Map cannot be loaded
by graff (Chancellor) on Sep 28, 2008 at 17:52 UTC
    Two additional follow-ups:

    First, why are you even using Unicode::Map in the first place? What does it do for you that Encode (or PerlIO encoding layers) can't do?

    Second, to answer your questions 1 and 3, which I didn't answer in my first reply:

    1. This problem comes up for perl programmers who are using a machine where they want to install non-core modules but don't have root privileges (and so cannot write stuff into the standard /usr directory tree). When the desired module involves any sort of OS/cpu dependency (usually, when parts of the module involve compiling code in C), the standard module install process will look at the current perl being used -- i.e. the version/build of perl that is first in the current path -- and create an OS/build-specific place for the compiled code.

    This applies to non-root installations, going into some user-writable path like "/home/lib/perl5". It's good for the cases where this path might be shared by multiple machines having different builds of perl (or even by different perl builds available on a single machine, e.g. with and without thread support).

    3. I think there would be a fairly easy, generally useful way to "elaborate" your default @INC inventory, but it would involve always using "require" (not "use") for modules that you expect to find in a non-root installation path. Other monks should be able to improve on this in significant ways:

    # get the current perl version as a string: my $pversion = join(".",map{ord()}split //,$^V); # find paths in @INC that contain or end in that string: my %inc; my $build; for (sort grep m!/\Q$pversion\E(?:/|$)!, @INC) { if ( m!/$pversion$! ) { $inc{$_} = 0; } elsif ( m!(.*?$pversion)/([^/]+)$! ) { $inc{$1} = 1; $build ||= $2; } } for ( keys %inc ) { if ( $inc{$_} == 0 and -d "$_/$build" ) { warn "adding $_/$build to INC array\n"; push @INC, "$_/$build"; } } # now we can "require" modules that have build-specific components # in paths that have just been added.
    (updated to fix indenting)

    If it's a problem that comes up a lot, I might wrap that in a module... (and make the warning message go away, or only show up when invoked with a "verbose" option).

    Even with that, the person writing the script that depends on the "non-root installed" modules still needs to know which modules fall into that category, so as to "require" them after going through the gyrations above, and not just "use" them.

    I am absolutely not an expert on this matter. I hope someone more knowledgeable will show us some better way of handling it.