tags:

views:

160

answers:

4

If I am in some library code, how do I determine the path to the file of the code that is currently executing? I know how to get the path of the top perl file by looking at ARGV, but if I load a library, how can that library know which path it is at?

+3  A: 

The __FILE__ token will give you the full path including the file name. You can use File::Spec to split it into components:

my ($volume, $directory, $file) = File::Spec->splitpath(__FILE__);
Michael Carman
I think this will not handle relative paths properly.
Leon Timmermans
@Leon: That depends on what you mean by "properly." The value of `__FILE__` should match what you'd get from `%INC`. If you've added relative paths to `@INC` then you might get relative file paths back. `splitpath()` will handle that but the directory portion will be relative instead of absolute. You can use `File::Spec->rel2abs()` to convert a (possibly) relative path to an absolute one if that's a concern.
Michael Carman
Of course, `__FILE__` might not actually be the file. Try running `warn __FILE__` after saying `#line 42 foo.bar` somewhere in the file.
jrockway
+1  A: 

Any libraries included via use or require produce an entry in the special %INC hash. (See perlvar).

For example:

use strict;
use warnings;

use Data::Dumper;

print Dumper \%INC;

This will produce output similar to the following:

$VAR1 = {
      'warnings/register.pm' => '/usr/lib/perl5/5.8.8/warnings/register.pm',
      'bytes.pm' => '/usr/lib/perl5/5.8.8/bytes.pm',
      'XSLoader.pm' => '/usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/XSLoader.pm',
      'Carp.pm' => '/usr/lib/perl5/5.8.8/Carp.pm',
      'Exporter.pm' => '/usr/lib/perl5/5.8.8/Exporter.pm',
      'strict.pm' => '/usr/lib/perl5/5.8.8/strict.pm',
      'warnings.pm' => '/usr/lib/perl5/5.8.8/warnings.pm',
      'overload.pm' => '/usr/lib/perl5/5.8.8/overload.pm',
      'Data/Dumper.pm' => '/usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/Data/Dumper.pm'
    };

Additionally, there is a universal __FILE__ constant which will return the current filename. (See also __PACKAGE__).

friedo
+7  A: 

The easiest way to find the filename of the current executable is with FindBin:

use FindBin;
use File::Spec;

print "the directory of my script is: " . $FindBin::Bin . "\n";
print "the base name of my script is: " . $FindBin::Script . "\n";
print "the canonical location of my script is: " . File::Spec->catfile($FindBin::Bin, $FindBin::Script) . "\n";

Internally, you can get at some of this information by looking at $0 (the name of the script as invoked at the command line), and __FILE__, which is the name of the currently-executing file. (See perldoc perlvar.)

To extract the filename of the currently-executing module, start with examining __PACKAGE__, do some substitution magic and then look up the filename in %INC:

(my $filename = __PACKAGE__ ) =~ s#::#/#g;
$filename .= '.pm';
my $abs_filename = $INC{$filename};

I do this in one of my initialization libraries to find a configuration script in a path relative to the current module (I have several code branches installed side-by-side, each with slightly different configs):

# use the location of the current module as a guide for where to find configs
(my $filename = __PACKAGE__ ) =~ s#::#/#g;
$filename .= '.pm';

(my $path = $INC{$filename}) =~ s#/\Q$filename\E$##g; # strip / and filename
my $abs_config_file = File::Spec->catfile($path, $config_file);
MyApp->initialize($abs_config_file);
Ether
that will give him the name of the script executed form the commandline (I think) not the name of the "library module" being executed.
lexu
@lexu: I added that bit in the next paragraph (just after you left that comment) :)
Ether
@Ether: right you are, good answer, but a bit more complex than _ _ FILE _ _
lexu
A: 

This is the snippet I usually use to get the path for the executing code.

use Cwd qw/abs_path/;
my ($real_path) = abs_path($0) =~ m/(.*)myscript.pl/i;

This puts the actual directory path into $real_path. I usually also perform chdir $real_path after this to make sure my code is actually working out of the directory it should be (usually when I'm writing a Windows service using Win32::Daemon).

The abs_path subroutine I've exported gives the path to whatever file (name/handle) you supply as the argument. In this case I've supplied $0 which is the name of the Perl script being executed.

I would recommend checking out Cwd on Cpan for a little more guidance.

Weegee