Are keys and values of %INC platform-dependent or not?
Asked Answered
L

2

6

I'd like to get the full filename of an included module. Consider this code:

package MyTest;

my $path = join '/', split /::/, __PACKAGE__;
$path .= ".pm";

print "$INC{$path}\n";

1;

$ perl -Ipath/to/module -MMyTest -e0
path/to/module/MyTest.pm

Will it work on all platforms?

perlvar

The hash %INC contains entries for each filename included via the do, require, or useoperators. The key is the filename you specified (with module names converted to pathnames), and the value is the location of the file found.

Are these keys platform-dependent or not? Should I use File::Spec or what? At least ActivePerl on win32 uses / instead of \.

Update: What about %INC values? Are they platform-dependent?

Laocoon answered 23/2, 2010 at 14:15 Comment(2)
What do you want to do with the path? Please provide more context!Selfsacrifice
Say, I want to include more modules from there.Laocoon
S
2

Given that it's a standard module, go with the approach from Module::Loaded:

sub is_loaded (*) { 
    my $pm      = shift;
    my $file    = __PACKAGE__->_pm_to_file( $pm ) or return;

    return $INC{$file} if exists $INC{$file};

    return;
}

sub _pm_to_file {
    my $pkg = shift;
    my $pm  = shift or return;

    my $file = join '/', split '::', $pm;
    $file .= '.pm';

    return $file;
}
Selfsacrifice answered 23/2, 2010 at 15:3 Comment(4)
Actually this is the very same code I wrote. And it seems, that this module works on most platforms. Thank you. cpantesters.org/distro/M/Module-Loaded.html#Module-Loaded-0.06 Can you say anything about portability of %INC values?Laocoon
@Laocoon Which platforms do you have in mind? Remember that / is a valid path separator on Win32, and much nicer looking than obnoxious double-backwhacks. Don't let the Windows command shell's geb0rken interface mislead you.Selfsacrifice
I want to make as cross-platform code as possible, since I'm looking forward to post it on CPAN finally.Laocoon
/ is not a valid seperator on VMS (at least at an OS level - Perl can handle these and convert to the OS format).Puebla
G
1

Here's a reasonably robust implementation that will also work for modules that haven't been loaded yet.

use File::Find;
use File::Spec;

sub pkg2path (*) {
    my $file = join '[\\\/:]' =>
               map  "\Q$_"    =>
               split /::|'/   => "$_[0].pm";            # '

    /$file$/ and return File::Spec->rel2abs( $INC{$_} )
        for keys %INC;

    # omit the rest to only find loaded modules

    my $path; find {
        no_chdir => 1,
        wanted   => sub {
            $path = $_ and goto found if /$file$/
        }
    } => @INC;

    found: File::Spec->rel2abs($path or return)
}

say pkg2path Benchmark;
say pkg2path Devel::Trace;
Gean answered 26/2, 2010 at 21:36 Comment(2)
The same code is written better in Module::Find. But it doesn't answer my question.Laocoon
the first line of pkg2path has your answer. no, its not safe to trust that the entries in %INC will have a particular pattern (if only because %INC is user writable). That's why I wrote the regex builder (which is not found in Module::Find, and it doesn't even use %INC btw). Nice to know you appreciate the few people that took the time to think about and answer your questionGean

© 2022 - 2024 — McMap. All rights reserved.