2010-03-26 48 views
13

如果我的Perl程序使用Perl模塊,它將如何確定在哪裏找到包含模塊代碼的文件?Perl程序如何知道在哪裏可以找到包含它使用的Perl模塊的文件?

例如,如果該程序包含:

use MyModule1;    # Example 1 
use This::Here::MyModule2; # Example 2 

會在哪裏看?

+0

我找不到這個問題的綜合答案,因此我可以鏈接到所以我決定創建一個。如果下面提供的答案需要添加/更正,請使用:) – DVK

回答

13

Perl解釋器(運行你的Perl程序)將使用一種叫做@INC搜索包含該模塊的文件中的特殊陣列。

@INC陣列中的每個值都是目錄名稱(,但請參閱下面的註釋); Perl將使用下面指定的規則在循環內搜索這些目錄。 (請參閱this SO post for details of how the contents of @INC are determined)。

如果用盡@INC後未找到該模塊的文件,程序的編制將與錯誤中止。如果在@INC中指定的其中一個目錄中找到該模塊的文件,則搜索結束時不會查看@INC的其餘部分。

Perl的搜索中的每個在@INC列出的目錄的模塊文件中的方法如下:

  • 首先,它將模塊名的層次組件(用::分隔單詞),分離成最後一個組件 - 將用於形成一個文件名 - 以及一個層次結構路徑(最後一個::之前的所有組件)。

    如果模塊名稱只有一個組件(不是::,例如上面的MyModule1),層次結構路徑是空的,文件名是模塊的名稱。在這個問題的第二個例子中,最後一個組件是MyModule2,層次結構路徑是This::Here

  • 預期的文件名稱會被用.pm擴展附加模塊名稱的最後一個組件來確定。例如。在我們的例子中爲MyModule1.pmMyModule2.pm

    注意:模塊的名稱顯然是區分在Unix和其他操作系統的敏感地方的文件/目錄命名是區分大小寫的。

  • 該模塊的目錄將被確定:

    1. @INC考慮的下一個目錄 - 讓我們說/usr/lib/perl作爲一個例子

    2. 通過採取分層形成目錄的子目錄模塊名稱的路徑(如果有的話),用/或操作系統用作目錄分隔符的任何字符替換「::」。在我們的兩個示例中,將在/usr/lib/perl(無子目錄)中搜索第一個模塊,並在/usr/lib/perl/This/Here中搜索第二個模塊。

    3. :以上是輕微的簡化 - @INCmay also contain subroutine references and object references,因爲它們的自定義代碼指定的,而不是如在#指定上述2個邏輯執行在目錄中的查找其加載模塊。該功能似乎很少使用,本文假定整個@INC只包含目錄。

讓我們在一個具體的例子,假設你的@INC包含兩個子目錄: ("/usr/lib/perl", "/opt/custom/lib")

那麼Perl會搜尋如下:

 
========================================================================== 
| Module    | Try # | File to try    
========================================================================== 
| MyModule1    | Try 1 | /usr/lib/perl/MyModule1.pm 
| MyModule1    | Try 2 | /opt/custom/lib/MyModule1.pm 
========================================================================== 
| This::Here::MyModule2 | Try 1 | /usr/lib/perl/This/Here/MyModule2.pm 
| This::Here::MyModule2 | Try 2 | /opt/custom/lib/This/Here/MyModule2.pm 
========================================================================== 

請記得,Perl解釋器將停止嘗試搜索一次找到的位置之一的文件,而試圖查看該文件是在後面的位置以及。例如。如果/usr/lib/perl/This/Here/MyModule2.pm存在,那麼Perl不會查找,也不在意/opt/custom/lib/This/Here/MyModule2.pm的存在。

注意:只要Perl解釋器使用類似require的機制來導入Perl模塊,就會使用@INC。這包括:

  • require指令本身
  • use MyModule聲明(相當於要求+進口)
  • use base(相當於要求+ 「推@ ISA」)
+2

可能值得注意的是@INC的內容來自哪裏。這甚至可能是OP正在尋找的答案。簡要總結:主要的默認內容是內置的(顯然,路徑的確切細節取決於您的安裝)。在腳本之外修改它的主要方法是設置環境變量PERL5LIB(冒號分隔的路徑列表)或在運行時爲可執行文件提供「-I/path/to/dir」選項。 (這些前置到數組) – Cascabel

+0

任何人都有一個很好的權威列表,究竟如何構建@INC? perldoc perlvar中的一個似乎缺少任何提及的PERL5LIB,以及'$ Config {sitelib}/sitecustomize.pl'機制(它必須在編譯時內置)。 – Cascabel

+0

@DVK:太棒了!由於對問題的評論以及事實已經非常徹底,錯誤地認爲你已經完成了。 – Cascabel

2

按照perlfunc documentation on use

use Module LI ST

將一些語義從命名模塊導入到當前包中,通常是將某些子例程或變量名稱混入到包中。它完全等同於

BEGIN { require Module; Module->import(LIST); } 

除了該模塊必須是空白字。

所以require確實繁重,而require documentation提供

如果EXPR是一個裸字,則需要承擔一個".pm"延伸,並在文件名與"/"取代"::"你,以方便加載標準模塊。這種模塊加載方式不會改變你的名字空間。

換句話說,如果你試試這個:

require Foo::Bar; # a splendid bareword 

require函數實際上將查找"Foo/Bar.pm"文件中@INC數組中指定的目錄中。

5

雖然這並不直接回答問題,但下面是一些簡單的技巧,用於確定要使用的模塊文件的完整路徑。

要查看@INC陣列的默認內容,有很多的其他信息一起,在命令行:

perl -V  

如果你想知道Carp模塊的位置:

perldoc -l Carp 

在腳本中,打印%INC散列的內容對於確定您正在使用的實際模塊非常有用,特別是如果您已從其默認值修改@INC

use Carp; 
print $INC{'Carp.pm'}; 

這個簡單的腳本也可以用於Find installed Perl modules matching a regular expression並識別不同目錄中的任何重複模塊。

+0

@toolic - 此答案與OP問題,但我覺得它與它有些分離(例如,「我導入的模塊來自哪裏」)。你介意把它作爲一個單獨的Q + A發佈在SO上(我會鏈接到它),或者讓我同意將它作爲一個單獨的Q併發布你的答案(或者讓我重新發布你的答案)? – DVK

+0

完成! http://stackoverflow.com/questions/2527990/how-do-i-find-which-file-contains-perl-module-my-script-uses – DVK

+0

@DVK - 如果我有我的Windows路徑中的兩個版本的Perl環境變量,那麼系統如何知道哪個perl可以選擇?它是第一個嗎?我對我的機器上安裝的不同軟件有不同的perls。它們隨軟件一起安裝。 – stack1

相關問題