Как я могу распространять свое приложение Perl в виде одного файла?

У меня есть Perl-скрипт (foo.pl), который загружает Foo.pm из того же каталога, используя механизм require:

require "./Foo.pm";
...
my $foo = new Foo::Bar;

Foo.pm придерживается стандартного формата модуля:

package Foo::Bar;
...
1;

Вместо того, чтобы распространять мое приложение в виде двух файлов (foo.pl и Foo.pm), я бы хотел распространять только один файл. В частности, я хотел бы сделать Foo.pm частью сценария foo.pl.

Как мне этого добиться?

Тривиальный подход простого слияния двух файлов (cat foo.pl Foo.pm > foo2.pl) не работает.


person knorv    schedule 12.09.2009    source источник


Ответы (5)


Ваш код не работал (хотя было бы полезно указать сообщения об ошибках, которые вы получили), потому что вы пытались использовать Foo::Bar до того, как он был определен. Попробуй это:

use strict;
use warnings;
my $foo = Foo::Bar->new();
# more code...

# end code

# begin definitions
BEGIN {
    package Foo::Bar;
    use strict;
    use warnings;
    # definitions...
    1;

    package Foo::Baz;
    # more stuff, if you need to define another class
}

Дополнения:

  • строгий контроль везде.
  • конструктор вызывается явно, а не с помощью метода косвенного объекта: in-perl">В чем разница между new Some::Class и Some::Class-›new() в Perl?
person Ether    schedule 12.09.2009

Если вы хотите упаковать свой сценарий Perl в двоичный файл со всеми включенными модулями, от которых он зависит, вы можете использовать упаковщик PAR:

pp -o binary_name foo.pl
person Drew Stephens    schedule 12.09.2009

Файл может содержать несколько пакетов. Сначала поместите свой класс, а затем основной скрипт:

package Foo::Bar;

sub new { 
  my $class = shift;
  return bless {}, $class;
}

#...

package main;

my $foo = Foo::Bar->new();
print ref $foo;  # Foo::Bar
person Michael Carman    schedule 12.09.2009
comment
Оператор package не создает новую область видимости, поэтому вы можете использовать { package Foo::Bar; REST_OF_THE_CODE }, чтобы предотвратить утечку данных между двумя пакетами. - person Chas. Owens; 13.09.2009

Общая схема заключалась бы в том, чтобы заменить ваше «требовать ...» содержимым того, что вам нужно. Это еще не все (может потребоваться BEGIN { }), и я не совсем уверен, что это значит. Конечно, вы хотели бы автоматизировать это.

Вот альтернатива: сгенерируйте один исполняемый файл, в котором модули, от которых вы зависите, упакованы внутри него, используя PAR/pp

person Jonathan Graehl    schedule 12.09.2009
comment
Привет, вранг-вранг! Спасибо за советы. К сожалению, создание исполняемого файла невозможно, поскольку один и тот же сценарий будет использоваться на нескольких платформах. - person knorv; 12.09.2009
comment
knorv: Если вы не включаете какие-либо модули с компонентом XS/C/скомпилированным, PAR может создавать файлы .par, которые являются кросс-платформенными. Это НЕ двоичный исполняемый файл, как в случае с pp -o foo.exe foo.pl. - person tsee; 13.09.2009

У вас уже есть несколько хороших ответов. Кроме того, можно сделать модуль, который можно запускать непосредственно как скрипт.

package Foo;

__PACKAGE__->run(@ARGV) unless caller();

sub run {
    # Do stuff here if you are running the Foo.pm as
    # a script rather than using it as a module.
}

Дополнительные сведения см. в статье Брайана Д. Фоя Как скрипт становится модулем.

person FMc    schedule 12.09.2009