如果我的Perl程序使用Perl模塊,它將如何確定在哪裏找到包含模塊代碼的文件?Perl程序如何知道在哪裏可以找到包含它使用的Perl模塊的文件?
例如,如果該程序包含:
use MyModule1; # Example 1
use This::Here::MyModule2; # Example 2
會在哪裏看?
如果我的Perl程序使用Perl模塊,它將如何確定在哪裏找到包含模塊代碼的文件?Perl程序如何知道在哪裏可以找到包含它使用的Perl模塊的文件?
例如,如果該程序包含:
use MyModule1; # Example 1
use This::Here::MyModule2; # Example 2
會在哪裏看?
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.pm
和MyModule2.pm
。
注意:模塊的名稱顯然是區分在Unix和其他操作系統的敏感地方的文件/目錄命名是區分大小寫的。
該模塊的目錄將被確定:
從@INC
考慮的下一個目錄 - 讓我們說/usr/lib/perl
作爲一個例子
通過採取分層形成目錄的子目錄模塊名稱的路徑(如果有的話),用/
或操作系統用作目錄分隔符的任何字符替換「::」。在我們的兩個示例中,將在/usr/lib/perl
(無子目錄)中搜索第一個模塊,並在/usr/lib/perl/This/Here
中搜索第二個模塊。
注:以上是輕微的簡化 - @INC
may 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」)可能值得注意的是@INC的內容來自哪裏。這甚至可能是OP正在尋找的答案。簡要總結:主要的默認內容是內置的(顯然,路徑的確切細節取決於您的安裝)。在腳本之外修改它的主要方法是設置環境變量PERL5LIB(冒號分隔的路徑列表)或在運行時爲可執行文件提供「-I/path/to/dir」選項。 (這些前置到數組) – Cascabel
任何人都有一個很好的權威列表,究竟如何構建@INC? perldoc perlvar中的一個似乎缺少任何提及的PERL5LIB,以及'$ Config {sitelib}/sitecustomize.pl'機制(它必須在編譯時內置)。 – Cascabel
@DVK:太棒了!由於對問題的評論以及事實已經非常徹底,錯誤地認爲你已經完成了。 – Cascabel
按照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
數組中指定的目錄中。
雖然這並不直接回答問題,但下面是一些簡單的技巧,用於確定要使用的模塊文件的完整路徑。
要查看@INC陣列的默認內容,有很多的其他信息一起,在命令行:
perl -V
如果你想知道Carp模塊的位置:
perldoc -l Carp
在腳本中,打印%INC散列的內容對於確定您正在使用的實際模塊非常有用,特別是如果您已從其默認值修改@INC:
use Carp;
print $INC{'Carp.pm'};
這個簡單的腳本也可以用於Find installed Perl modules matching a regular expression並識別不同目錄中的任何重複模塊。
@toolic - 此答案與OP問題,但我覺得它與它有些分離(例如,「我導入的模塊來自哪裏」)。你介意把它作爲一個單獨的Q + A發佈在SO上(我會鏈接到它),或者讓我同意將它作爲一個單獨的Q併發布你的答案(或者讓我重新發布你的答案)? – DVK
完成! http://stackoverflow.com/questions/2527990/how-do-i-find-which-file-contains-perl-module-my-script-uses – DVK
@DVK - 如果我有我的Windows路徑中的兩個版本的Perl環境變量,那麼系統如何知道哪個perl可以選擇?它是第一個嗎?我對我的機器上安裝的不同軟件有不同的perls。它們隨軟件一起安裝。 – stack1
我找不到這個問題的綜合答案,因此我可以鏈接到所以我決定創建一個。如果下面提供的答案需要添加/更正,請使用:) – DVK