2009-04-25 26 views
35

Tôi có một thư mục có tên là foo và trong đó tôi có libbin. Các tập lệnh trong bin cần nội dung trong lib. Tôi làm điều gì đó như sau:Làm cách nào để sử dụng mô-đun Perl từ một vị trí tương đối?

#!perl 
use strict; 
use warnings; 
use lib '../lib'; 
use Foo; # <-- comes from lib 

Nhưng điều đó có nghĩa là tôi phải ở trong thư mục bin để chạy tập lệnh. Chắc chắn có một cách tốt hơn. Cách tốt nhất để làm điều này là gì?

+1

câu trả lời của bạn không cho tôi biết làm thế nào để sử dụng một mô-đun từ một vị trí tương đối –

Trả lời

47

Mô-đun tiêu chuẩn FindBin làm những gì bạn muốn.

use FindBin; 
use lib "$FindBin::Bin/../lib"; 

perldoc FindBin để biết thêm.

+0

Theo [PerlMonks] (http://www.perlmonks.org/) người ta nên tránh FindBin: “[FindBin bị hỏng (RE: Làm thế nào để tôi có được đường dẫn đầy đủ để thực thi tập lệnh?)] (Http: // www.perlmonks.org/?node_id=41213) ”. - Mặc dù, phải thừa nhận rằng bài đăng đó đã hơn 10 năm (từ năm 2000) và tôi không chắc chắn rằng nó vẫn chính xác. – zrajm

+0

Tuyệt vời! Đó là giải pháp duy nhất hoạt động ra khỏi hộp. Tôi đã thử những khẩu súng lớn như Begin {push @INC, "$ mypath"}, và họ không bao giờ làm việc suôn sẻ. Cảm ơn bạn! – kakyo

5

phân tích ra các đường dẫn đầy đủ đến .pl của bạn thông qua __FILE__ và và tack ../lib ở cuối dòng hoặc bật ra khỏi yếu tố cuối cùng của split(/\//,__FILE__) và thêm /lib đó.

+0

Tại sao điều này lại bị bỏ phiếu? Điều này có vẻ như câu trả lời tốt nhất vì nó sẽ luôn hoạt động ... –

+0

Điều này đòi hỏi phải sửa đổi tất cả các tệp perl. – ojblass

-3

Làm thế nào về:

BEGIN: { 
    push @INC, '/full/path/to/lib'; 
} 

Để làm được một tham chiếu tương đối sẽ cho rằng bạn đang đi để giữ nó trong thư mục bin, vì vậy chèn tài liệu tham khảo tương đối có để thay thế.

+0

lưu ý câu hỏi: điều này không thực sự cho tôi biết cách sử dụng tương đối. –

+0

Bạn có thể muốn đặt các đường đặc biệt ở mặt trước của @INC thay vì ở cuối. –

+0

nhập quá nhanh: -) ... @frew - mã nguồn dành cho đường dẫn đầy đủ - trong ghi chú của tôi tôi giải thích để chèn đường dẫn tương đối. @bdf - Có bạn là prb. đúng, để làm điều đó sẽ là một 'unshift' thay vì push. –

3

Mô-đun "FindBin" sẽ chỉ hoạt động nếu thư mục mà tập lệnh perl nằm trong PATH hệ thống của bạn, nếu không nó sẽ thất bại. Để khắc phục điều đó , bạn có thể điều chỉnh giá trị $0 để nhận thông tin về đường dẫn đến mô-đun-perl và chuyển giá trị cho use lib.

Something như thế này -

BEGIN { 
    use File::Spec::Functions qw(rel2abs); 
    use File::Basename qw(dirname); 

    #Covert the script path to absolute and get its directory name 
    our $path = dirname(rel2abs($0)); 

    #Replace the bin tag with lib to get module directory 
    $path =~ s{bin/?$}{lib}; 
} 

use lib $path; 

EDIT: Module FindBin hoạt động giống một cách hoàn hảo và có thể được sử dụng như mô tả trong Michael's answer. Sự hiểu biết của tôi về hoạt động của nó là không đầy đủ và do đó đã dẫn tôi đưa ra nhận xét đầu tiên mà bây giờ tôi rút lại. Dù sao, tôi không thấy bất kỳ lý do tại sao phương pháp này không nên làm việc mặc dù với một vài dòng hơn có thể đạt được bằng cách sử dụng FindBin (TMTOWTDI).

+0

Điều này gần đây bit tôi vì rel2abs có thể sẽ trả lại đường dẫn Windows sai. File :: Spec :: Win32 :: rel2abs có thể kết thúc gọi Cwd :: getdcwd và trả về điều sai. Tôi đã phải gửi một bản vá để lưu trữ :: Trích xuất để có được xung quanh này: http://rt.cpan.org/Public/Bug/Display.html?id=43278 –

+0

FindBin hoạt động tốt cho các địa điểm không có trong con đường. IIRC không thành công nếu có tệp (khác) có cùng tên với tập lệnh của bạn trong đường dẫn của bạn. –

+0

Phương pháp của bạn thực sự giống với những gì FindBin đã làm, nhưng không có tình yêu đa nền tảng. Có thật không. FindBin là con đường để đi. –

3

Tôi thường sử dụng kỹ thuật này. Cảm hứng đáng buồn của nó từ những ngày PHP của tôi:

Tiện dụng trong trường hợp bạn biết vị trí của một tệp nhất định sẽ tương ứng với hiện tại và không chắc chắn về điểm vào có thể được gọi trong hoặc xung quanh môi trường tại thời gian gọi.

Tuy nhiên, tôi thường sử dụng kỹ thuật này chỉ cho tập lệnh thử nghiệm cần thư viện giả để mô phỏng mọi thứ.

use File::Basename(); 
use Cwd   (); 
my $base_dir; 
my $relative_path; 
BEGIN { 
    $realitive_path = '../../' # Path to base of project relative to the current file 
    $base_dir = Cwd::realpath(File::Basename::dirname(__FILE__) .'/' . $relative_path); 
} 


use lib "${base_dir}/lib"; 
use Foo; 

Lý tưởng nhất là nên có một số nơi mô-đun mà thực hiện điều này, nếu không muốn nói, tôi nửa cám dỗ để viết một:

use Some::Module(); 
use lib Some::Module::relative_self('../../lib', __FILE__); 
+0

additonally của nó có thể hợp lý để có được __FILE__ trong số người gọi()./Tôi cân nhắc –

+0

nah, đi FindBin – singingfish

+0

Tôi đã xem xét findbin, và nó bao gồm trường hợp sử dụng trung bình, nhưng cách nó hoạt động đối với một số trường hợp khác và nó hoạt động như thế nào trong mã là khủng khiếp. tạo một biến tại use() thời gian là chỉ thực sự kỳ lạ với tôi. –

0

Giải pháp của tôi:

use lib substr(__FILE__, 0, rindex (__FILE__, "/")); 
+1

Có vẻ hơi lộn xộn so với sử dụng regex? Cũng lưu ý rằng '__FILE__' đôi khi có thể chứa tên * tương đối * (ví dụ:'./ myscript') mà có thể (hoặc có thể không) cắn bạn. – zrajm

0

Chỉ cần thêm hai xu của riêng tôi cho bộ sưu tập các câu trả lời này, tôi thường giải quyết vấn đề này bằng cách sử dụng một cái gì đó dọc theo các dòng sau:

use lib do { 
    use Cwd 'realpath'; 
    my ($dir) = __FILE__ =~ m{^(.*)/}; # $dir = path of current file 
    realpath("$dir/../lib");   # path of '../lib' relative to $dir 
}; 

Tôi thích sử dụng khối do vì mọi thứ cần thiết được chứa gọn gàng trong đó. Nếu bạn cần sao chép/dán hoặc cố gắng hiểu mã của mình sau này, bạn không cần phải tìm một khối riêng biệt BEGIN hoặc bất kỳ thứ gì tương tự.

Đoạn mã trên không đúng là giả định rằng / được sử dụng làm bộ phân cách dir/tên tệp.

0
use lib './'; 

đã làm việc cho tôi với Perl v5.14.2 trên hộp linux để bao gồm các tệp trong cùng thư mục với tập lệnh của tôi.

Có lẽ nó sẽ làm việc cho bạn để di chuyển lib và bin thư mục của bạn dưới thư mục làm việc tập lệnh của bạn và cố gắng tham khảo chúng bằng cách sử

use lib './bin/'; 
+1

Tôi không chắc chắn nếu Frew đang tìm kiếm giải pháp này. Sửa tôi nếu tôi sai nhưng anh ấy thực sự muốn có một cách tốt hơn để đưa các thư viện ra ngoài thư mục làm việc. Sự phục hồi mà bạn đang đề xuất có thể không thực hiện được đối với tất cả các dự án – comiventor

Các vấn đề liên quan