Spec-Zone.ru › Perl 5.36

perlmod

СОДЕРЖАНИЕ

  • ИМЯ
  • ОПИСАНИЕ
    • Этот документ ли?
    • Пакеты
    • Таблицы символов
    • BEGIN, UNITCHECK, CHECK, INIT и END
    • Классы Perl
    • Модули Perl
    • Делаем ваш модуль безопасным для потоков
  • СМОТРИТЕ ТАКЖЕ

ИМЯ

perlmod - Модули Perl (пакеты и таблицы символов)

ОПИСАНИЕ

Этот документ ли?

Существуют другие документы, которые могут содержать искомую вами информацию:

Этот документ

Пакеты Perl, пространства имен и некоторые сведения о классах.

perlnewmod

Руководство по созданию нового модуля.

perlmodstyle

Рекомендации по созданию нового модуля.

Пакеты

В отличие от Perl 4, в котором все переменные были динамическими и использовали одно глобальное пространство имен, что вызывало проблемы с обслуживанием, Perl 5 предоставляет два механизма для защиты кода от перезаписи его переменных другим кодом: лексически ограниченные переменные, созданные с помощью my или state, и именованные глобальные переменные, которые экспонируются с помощью vars pragmy или our ключевого слова. Любая глобальная переменная считается частью пространства имен и может быть обращена через "полную квалифицированную форму". Напротив, любая лексически ограниченная переменная считается частью этого лексического контекста и не имеет "полной квалифицированной формы".

В Perl пространства имен называются "пакетами", и объявление package сообщает компилятору, какое пространство имен префикс к our переменным и неквалифицированным динамическим именам. Это защищает от случайной перезаписи и предоставляет интерфейс для преднамеренной перезаписи глобальных динамических переменных, объявленных и используемых в других областях или пакетах, когда это необходимо.

Область действия объявления package простирается от самого объявления до конца вложенного блока, eval, или файла, что произойдет раньше (такая же область действия, как у операторов my(), our(), state() и local(), а также влияние экспериментального «aliased references», которое может измениться), или до следующего объявления package. Неквалифицированные динамические идентификаторы будут в этом пространстве имен, за исключением тех немногих идентификаторов, которые, будучи неквалифицированными, по умолчанию относятся к главному пакету вместо текущего, как описано ниже. Оператор package воздействует только на динамические глобальные символы, включая имена подпрограмм и переменные, к которым применено local(), но не на лексические переменные, созданные с помощью my(), our() или state().

Как правило, оператор package является первым объявлением в файле, включённом в программу одним из операторов do, require или use. Вы можете переключаться между пакетами в нескольких местах: package не имеет эффекта, кроме указания таблицы символов, которую компилятор будет использовать для динамических символов на оставшуюся часть этого блока или до следующего оператора package. Вы можете ссылаться на переменные и дескрипторы файлов в других пакетах, добавив к идентификатору имя пакета и двойное двоеточие: $Package::Variable. Если имя пакета пустое, предполагается пакет main. То есть, $::sail эквивалентно $main::sail.

Старым разделителем пакетов была одиночная кавычка, но двойное двоеточие теперь предпочтительнее, отчасти потому, что оно более удобочитаемо для человека, и отчасти потому, что оно более удобочитаемо для макросов emacs. Также это даёт ощущение знакомого C++ программистам — в отличие от использования одиночной кавычки в качестве разделителя, которое было сделано, чтобы сделать Ada программистам более понятно. Поскольку устаревшая синтаксис все еще поддерживается для обратной совместимости, если вы попытаетесь использовать строку, такую как "This is $owner's house", вы получите доступ к $owner::s; то есть, переменной $s в пакете owner, что, вероятно, не то, что вы имели в виду. Используйте фигурные скобки, чтобы избежать неоднозначности, как в "This is ${owner}'s house".

Пакеты могут сами содержать разделители пакетов, как в $OUTER::INNER::var. Однако это ничего не говорит о порядке поиска имен. Нет относительных пакетов: все символы либо локальны для текущего пакета, либо должны быть полностью квалифицированы от внешнего имени пакета до внутреннего. Например, нигде в пакете OUTER $INNER::var не ссылается на $OUTER::INNER::var. INNER относится к совершенно отдельному глобальному пакету. Привычка рассматривать имена пакетов как иерархию очень сильна, но язык никак не навязывает её.

Только идентификаторы, начинающиеся с букв (или подчеркивания), хранятся в таблице символов пакета. Все остальные символы хранятся в пакете main, включая все переменные с пунктуацией, такие как $_. Кроме того, при использовании без квалификатора идентификаторы STDIN, STDOUT, STDERR, ARGV, ARGVOUT, ENV, INC и SIG принудительно находятся в пакете main, даже когда они используются не по своему предназначению. Если у вас есть пакет, названный m, s или y, то вы не сможете использовать квалифицированную форму идентификатора, потому что она будет интерпретирована как совпадение шаблона, подстановка или транслитерация.

Переменные, начинающиеся с символа подчеркивания, раньше принудительно помещались в пакет main, но мы решили, что для авторов пакетов полезнее иметь возможность использовать ведущий символ подчеркивания для обозначения закрытых переменных и имён методов. Однако переменные и функции, имеющие одно имя с префиксом подчеркивания, такие как $_ и sub _, по-прежнему помещаются в пакет main. См. также "Синтаксис имён переменных" в perlvar.

eval строки компилируются в том пакете, в котором был скомпилирован eval(). (Присваивания $SIG{}, однако, предполагают, что указанный обработчик сигнала находится в пакете main. Укажите имя обработчика сигнала, если вы хотите иметь обработчик сигнала в пакете.) Для примера рассмотрите perldb.pl в библиотеке Perl. Он первоначально переключается в пакет DB, чтобы отладчик не вмешивался в переменные программы, которую вы пытаетесь отладить. Однако в различных точках он временно возвращается в пакет main для вычисления различных выражений в контексте пакета main (или откуда вы пришли). См. perldebug.

Специальный символ __PACKAGE__ содержит текущий пакет, но (легко) не может использоваться для построения имён переменных. После того как my($foo) скрыл переменную пакета $foo, к ней по-прежнему можно получить доступ без знания текущего пакета как ${__PACKAGE__.'::foo'}.

См. perlsub по другим проблемам области видимости, связанным с my() и local(), и perlref по замыканиям.

Таблицы символов

Таблица символов пакета хранится в хэше с добавленным двойным двоеточием. Имя основной таблицы символов — %main::, или %:: для краткости. Аналогично, имя таблицы символов для вложенного пакета, упомянутого ранее, имеет имя %OUTER::INNER::.

Значение в каждом элементе хэша — то, на что вы ссылаетесь, используя обозначение *name typeglob.

local *main::foo    = *main::bar;

Например, вы можете использовать это, чтобы вывести все переменные в пакете. Стандартная, но устаревшая библиотека dumpvar.pl и модуль CPAN Devel::Symdump используют это.

Результаты создания новых записей таблицы символов непосредственно или изменения записей, которые ещё не являются typeglob, не определены и могут изменяться между выпусками perl.

Присваивание typeglob выполняет операцию алиасирования, то есть

*dick = *richard;

приводит к тому, что переменные, подпрограммы, форматы и дескрипторы файлов и каталогов, доступные через идентификатор richard, также становятся доступными через идентификатор dick. Если вы хотите алиасить только определённую переменную или подпрограмму, присвойте ссылку вместо этого:

*dick = \$richard;

Что делает $richard и $dick одной переменной, но оставляет @richard и @dick отдельными массивами. Сложно, не так ли?

Есть одно тонкое различие между следующими операциями:

*foo = *bar;
*foo = \$bar;

*foo = *bar делает сами typeglob синонимами, в то время как *foo = \$bar делает части SCALAR двух разных typeglob одинаковыми по значению. Это означает, что следующий код:

$bar = 1;
*foo = \$bar;       # Make $foo an alias for $bar

{
    local $bar = 2; # Restrict changes to block
    print $foo;     # Prints '1'!
}

выведет '1', потому что $foo содержит ссылку на исходный $bar. Тот, что был спрятан local() и который будет восстановлен по завершении блока. Поскольку переменные обращаются через typeglob, вы можете использовать *foo = *bar для создания алиаса, который может быть локальным. (Но имейте в виду, что это означает, что у вас не может быть отдельных @foo и @bar, и т. д.)

Важность всего этого заключается в том, что модуль Exporter использует алиасирование typeglob в качестве механизма импорта/экспорта. Возможность локального ограничить переменную, экспортированную из модуля, зависит от того, как она была экспортирована:

@EXPORT = qw($FOO); # Usual form, can't be localized
@EXPORT = qw(*FOO); # Can be localized

Вы можете обойти первый случай, используя полное имя ($Package::FOO) там, где вам нужна локальная переменная, или переопределяя её, написав *FOO = *Package::FOO в вашем скрипте.

Механизм *x = \$y может быть использован для передачи и возврата ссылок в подпрограммы или из них, если вы не хотите копировать всё. Он работает только при присваивании динамическим переменным, а не лексическим.

%some_hash = ();                    # can't be my()
*some_hash = fn( \%another_hash );
sub fn {
    local *hashsym = shift;
    # now use %hashsym normally, and you
    # will affect the caller's %another_hash
    my %nhash = (); # do what you want
    return \%nhash;
}

При возвращении ссылка перезапишет слот хэша в таблице символов, указанной typeglob *some_hash. Это несколько хитроумный способ передавать ссылки дёшево, когда вам не нужно помнить о явном разыменовании переменных.

Ещё одно применение таблиц символов — для создания "константных" скаляров.

*PI = \3.14159265358979;

Теперь вы не можете изменить $PI, что, вероятно, хорошо. Это не то же самое, что константная подпрограмма, которая подвержена оптимизации на этапе компиляции. Константная подпрограмма — это подпрограмма, прототипированная для работы без аргументов и возвращающая константное выражение. См. perlsub для получения более подробной информации об этом. Пragma use constant является удобным сокращением для этого.

Вы можете сказать *foo{PACKAGE} и *foo{NAME}, чтобы узнать имя и пакет, откуда происходит запись таблицы символов *foo. Это может быть полезно в подпрограмме, которой передаются typeglob в качестве аргументов:

sub identify_typeglob {
    my $glob = shift;
    print 'You gave me ', *{$glob}{PACKAGE},
        '::', *{$glob}{NAME}, "\n";
}
identify_typeglob *foo;
identify_typeglob *bar::baz;

Это выведет

You gave me main::foo
You gave me bar::baz

Обозначение *foo{THING} также может использоваться для получения ссылок на отдельные элементы *foo. См. perlref.

Определения подпрограмм (и объявления, кстати) необязательно должны находиться в пакете, в котором они занимают таблицу символов. Вы можете определить подпрограмму вне своего пакета, явно указав имя подпрограммы:

package main;
sub Some_package::foo { ... }   # &foo defined in Some_package

Это просто сокращение для присваивания typeglob во время компиляции:

BEGIN { *Some_package::foo = sub { ... } }

и не то же самое, что:

{
    package Some_package;
    sub foo { ... }
}

В двух первых версиях тело подпрограммы находится лексически в главном пакете, а не в Some_package. Поэтому что-то вроде этого:

package main;

$Some_package::name = "fred";
$main::name = "barney";

sub Some_package::foo {
    print "in ", __PACKAGE__, ": \$name is '$name'\n";
}

Some_package::foo();

выводит:

in main: $name is 'barney'

а не:

in Some_package: $name is 'fred'

Это также имеет последствия для использования квалификатора SUPER:: (см. perlobj).

BEGIN, UNITCHECK, CHECK, INIT и END

Пять специально названных блоков кода выполняются в начале и в конце выполняемой программы Perl. Это блоки BEGIN, UNITCHECK, CHECK, INIT, и END.

Эти блоки кода можно префиксровать с sub, чтобы придать вид подпрограммы (хотя это не считается хорошим стилем). Следует отметить, что эти блоки кода фактически не существуют как именованные подпрограммы (несмотря на их внешний вид). Признаком этого является то, что в программе может быть более одного из этих блоков кода, и все они будут выполнены в соответствующий момент. Поэтому вы не можете выполнить ни один из этих блоков кода по имени.

Блок кода BEGIN выполняется как можно скорее, то есть в момент его полного определения, даже прежде чем остальная часть содержащего файла (или строки) будет обработана. В файле (или строке, обработанной с помощью eval) может быть несколько блоков BEGIN; они будут выполняться в порядке определения. Поскольку блок кода BEGIN выполняется немедленно, он может подключать определения подпрограмм и т. д. из других файлов вовремя, чтобы они были видимы остальной частью времени компиляции и выполнения. Как только блок BEGIN выполнен, он немедленно удаляется, а любой используемый им код возвращается в пул памяти Perl.

Блок кода END выполняется как можно позже, то есть после того, как Perl завершит выполнение программы и непосредственно перед выходом интерпретатора, даже если выход происходит в результате функции die(). (Но не если он трансформируется в другую программу с помощью exec, или если его «сдувает» сигнал — вы должны поймать это сами (если можете)). В файле может быть несколько блоков END — они будут выполняться в обратном порядке определения; то есть: последний вошёл, первый вышел (LIFO). Блоки END не выполняются, когда вы запускаете perl с переключателем -c, или если компиляция завершается ошибкой.

Обратите внимание, что блоки кода END не выполняются в конце строки eval(): если какие-либо блоки кода END созданы в строке eval(), они будут выполнены так же, как и любой другой блок кода END этого пакета в порядке LIFO непосредственно перед выходом интерпретатора.

Внутри блока кода END, $? содержит значение, которое программа передаст exit(). Вы можете изменить $?, чтобы изменить значение выхода программы. Будьте осторожны, случайно не изменяя $? (например, запустив что-то через system).

Внутри блока END, значение ${^GLOBAL_PHASE} будет "END".

Аналогичны блоку END блоки defer, хотя они работают в пределах срока действия отдельных областей видимости блоков, а не всей программы в целом. Они описаны в "defer" в perlsyn.

UNITCHECK, CHECK и INIT блоки кода полезны для захвата перехода между фазой компиляции и фазой выполнения основной программы.

Блоки UNITCHECK выполняются сразу после того, как модуль, определивший их, был скомпилирован. Основной файл программы и каждый загружаемый им модуль являются единицами компиляции, как и строки evals, код, скомпилированный во время выполнения с помощью конструкции (?{ }) в регулярном выражении, вызовы к do FILE, require FILE, и код после переключателя -e на командной строке.

Блоки BEGIN и UNITCHECK напрямую не связаны с фазой работы интерпретатора. Они могут создаваться и выполняться в любой фазе.

Блоки CHECK выполняются сразу после завершения начальной фазы компиляции Perl и перед началом выполнения, в порядке LIFO. Блоки CHECK используются в наборе инструментов компилятора Perl для сохранения скомпилированного состояния программы.

Внутри блока CHECK, значение ${^GLOBAL_PHASE} будет "CHECK".

Блоки INIT выполняются непосредственно перед началом выполнения среды выполнения Perl в порядке «первый пришёл, первый ушёл» (FIFO).

Внутри блока INIT, значение ${^GLOBAL_PHASE} будет "INIT".

Блоки CHECK и INIT в коде, скомпилированном с помощью require, строки do, или строки eval не будут выполнены, если они встречаются после завершения основной фазы компиляции; это может быть проблемой в mod_perl и других устойчивых средах, которые используют эти функции для загрузки кода во время выполнения.

При использовании переключателей -n и -p в Perl, BEGIN и END работают так же, как и в awk, как вырожденный случай. Оба блока BEGIN и CHECK выполняются, когда вы используете переключатель -c для проверки синтаксиса только при компиляции, хотя ваш основной код не выполняется.

Программа begincheck в конечном итоге всё проясняет:

#!/usr/bin/perl

# begincheck

print         "10. Ordinary code runs at runtime.\n";

END { print   "16.   So this is the end of the tale.\n" }
INIT { print  " 7. INIT blocks run FIFO just before runtime.\n" }
UNITCHECK {
  print       " 4.   And therefore before any CHECK blocks.\n"
}
CHECK { print " 6.   So this is the sixth line.\n" }

print         "11.   It runs in order, of course.\n";

BEGIN { print " 1. BEGIN blocks run FIFO during compilation.\n" }
END { print   "15.   Read perlmod for the rest of the story.\n" }
CHECK { print " 5. CHECK blocks run LIFO after all compilation.\n" }
INIT { print  " 8.   Run this again, using Perl's -c switch.\n" }

print         "12.   This is anti-obfuscated code.\n";

END { print   "14. END blocks run LIFO at quitting time.\n" }
BEGIN { print " 2.   So this line comes out second.\n" }
UNITCHECK {
 print " 3. UNITCHECK blocks run LIFO after each file is compiled.\n"
}
INIT { print  " 9.   You'll see the difference right away.\n" }

print         "13.   It only _looks_ like it should be confusing.\n";

__END__

Классы Perl

В Perl нет специального синтаксиса для классов, но пакет может действовать как класс, если он предоставляет подпрограммы, которые действуют как методы. Такой пакет также может унаследовать некоторые из своих методов от другого класса (пакета), перечислив имя(а) другого пакета в своём глобальном массиве @ISA (который должен быть глобальным для пакета, а не лексическим).

Для получения дополнительной информации см. perlootut и perlobj.

Модули Perl

Модуль — это просто набор связанных функций в файле библиотеки, то есть пакет Perl с тем же именем, что и файл. Он специально разработан для повторного использования другими модулями или программами. Он может делать это, предоставляя механизм для экспорта некоторых своих символов в таблицу символов любого пакета, который его использует, или он может функционировать как определение класса и делать свою семантику доступной неявно через вызовы методов к классу и его объектам без явного экспорта чего-либо. Или он может делать и то, и другое.

Например, чтобы начать традиционный, не ОО-модуль под названием Some::Module, создайте файл под названием Some/Module.pm и начните с этого шаблона:

package Some::Module;  # assumes Some/Module.pm

use v5.36;

# Get the import method from Exporter to export functions and
# variables
use Exporter 5.57 'import';

# set the version for version checking
our $VERSION     = '1.00';

# Functions and variables which are exported by default
our @EXPORT      = qw(func1 func2);

# Functions and variables which can be optionally exported
our @EXPORT_OK   = qw($Var1 %Hashit func3);

# exported package globals go here
our $Var1    = '';
our %Hashit  = ();

# non-exported package globals go here
# (they are still accessible as $Some::Module::stuff)
our @more    = ();
our $stuff   = '';

# file-private lexicals go here, before any functions which use them
my $priv_var    = '';
my %secret_hash = ();

# here's a file-private function as a closure,
# callable as $priv_func->();
my $priv_func = sub {
    ...
};

# make all your functions, whether exported or not;
# remember to put something interesting in the {} stubs
sub func1      { ... }
sub func2      { ... }

# this one isn't always exported, but could be called directly
# as Some::Module::func3()
sub func3      { ... }

END { ... }       # module clean-up code here (global destructor)

1;  # don't forget to return a true value from the file

Затем переходите к объявлению и использованию ваших переменных в функциях без каких-либо квалификаторов. Подробности о механике и вопросах стиля при создании модулей см. в Exporter и perlmodlib.

Модули Perl включаются в вашу программу, используя

use Module;

или

use Module LIST;

Это точно эквивалентно

BEGIN { require 'Module.pm'; 'Module'->import; }

или

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

В качестве специального случая

use Module ();

точно эквивалентно

BEGIN { require 'Module.pm'; }

Все файлы модулей Perl имеют расширение .pm. Оператор use предполагает это, так что вам не нужно писать "Module.pm" в кавычках. Это также помогает отличать новые модули от старых файлов .pl и .ph. Имена модулей также пишутся с большой буквы, если они не работают как прагмы; прагмы фактически являются директивами компилятора и иногда называются «прагматическими модулями» (или даже «прагматами», если вы классик).

Два утверждения:

require SomeModule;
require "SomeModule.pm";

отличаются друг от друга двумя способами. В первом случае все двойные двоеточия в имени модуля, такие как Some::Module, переводятся в разделитель каталогов вашей системы, обычно "/". Во втором случае нет, и он должен быть указан буквально. Другое различие заключается в том, что первое require указывает компилятору, что использование косвенной нотации объекта, связанной с «SomeModule», как в $ob = purge SomeModule, является вызовом метода, а не вызовом функции. (Да, это действительно может иметь значение.)

Поскольку утверждение use подразумевает блок BEGIN, импорт семантики происходит сразу после компиляции утверждения use, до компиляции остальной части файла. Именно так он работает как механизм прагмы, и именно так модули могут объявлять подпрограммы, которые затем отображаются как списки или унарные операторы для остальной части текущего файла. Это не сработает, если вы используете require вместо use. С require вы можете столкнуться с этой проблемой:

require Cwd;                # make Cwd:: accessible
$here = Cwd::getcwd();

use Cwd;                    # import names from Cwd::
$here = getcwd();

require Cwd;                # make Cwd:: accessible
$here = getcwd();           # oops! no main::getcwd()

В общем случае, use Module () рекомендуется вместо require Module, так как он определяет доступность модуля на этапе компиляции, а не в середине выполнения вашей программы. Исключением является случай, когда два модуля пытаются use друг друга, а каждый также вызывает функцию из другого модуля. В этом случае проще использовать require вместо этого.

Пакеты Perl могут быть вложены внутри других имён пакетов, так что у нас могут быть имена пакетов, содержащие ::. Но если бы мы использовали это имя пакета напрямую как имя файла, это привело бы к громоздким или невозможным именам файлов на некоторых системах. Поэтому, если имя модуля, скажем, Text::Soundex, то его определение фактически находится в файле библиотеки Text/Soundex.pm.

Модули Perl всегда имеют файл .pm, но с модулем также могут быть связаны динамически подключаемые исполняемые файлы (часто заканчивающиеся на .so) или определения автоматически загружаемых подпрограмм (часто заканчивающиеся на .al). Если это так, то они будут полностью прозрачны для пользователя модуля. Ответственность файла .pm заключается в загрузке (или организации автоматической загрузки) любой дополнительной функциональности. Например, хотя модуль POSIX случается делать и то, и другое, динамическая загрузка, и автоматическую загрузку, пользователь может сказать просто use POSIX чтобы получить всё это.

Обеспечение потокобезопасности вашего модуля

Perl поддерживает тип потоков, называемые интерпретаторскими потоками (ithreads). Эти потоки могут использоваться явно и неявно.

Ithreads работают путём клонирования дерева данных, так что данные не разделяются между различными потоками. Эти потоки могут использоваться с помощью модуля threads или путём выполнения fork() в win32 (поддержка фиктивного fork()). При клонировании потока весь Perl-данные клонируются, однако не-Perl-данные не могут быть клонированы автоматически. Perl начиная с версии 5.8.0 поддерживает специальную подпрограмму CLONE. В CLONE вы можете сделать всё необходимое, например, обработать клонирование не-Perl-данных, если это необходимо. CLONE будет вызван один раз как метод класса для каждого пакета, в котором он определён (или унаследован). Он будет вызван в контексте нового потока, так что все изменения производятся в новой области. В настоящее время CLONE вызывается без параметров, кроме имени пакета вызывающего, но код не должен предполагать, что это останется неизменным, так как в будущем, вероятно, будут переданы дополнительные параметры, чтобы предоставить больше информации о состоянии клонирования.

Если вы хотите клонировать все объекты, вам нужно отслеживать их по пакетам. Это просто делается с помощью хэша и Scalar::Util::weaken().

Perl после версии 5.8.7 поддерживает специальную подпрограмму CLONE_SKIP. Как CLONE, CLONE_SKIP вызывается один раз на каждый пакет; однако, он вызывается непосредственно перед началом клонирования и в контексте родительского потока. Если он возвращает значение true, то объекты данного класса не будут клонироваться; или, скорее, они будут скопированы как неблагословенные, undef значения. Например, если в родительском потоке есть две ссылки на один благословенный хэш, то в дочернем потоке будет две ссылки на одно неопределённое скалярное значение вместо него. Это обеспечивает простой механизм для обеспечения потокобезопасности модуля; просто добавьте sub CLONE_SKIP { 1 } в начало класса, и DESTROY() теперь будет вызываться только один раз на каждый объект. Конечно, если дочернему потоку нужно использовать объекты, то требуется более сложный подход.

Как CLONE, CLONE_SKIP в настоящее время вызывается без параметров, кроме имени пакета-вызывающего объекта, хотя это может измениться. Аналогично, для возможности будущего расширения, возвращаемое значение должно быть одним 0 или 1 значением.

ДРУГИЕ ССЫЛКИ

См. perlmodlib для общих вопросов стиля, связанных с созданием Perl-модулей и классов, а также описаний стандартной библиотеки и CPAN, Exporter для понимания работы механизма импорта/экспорта Perl, perlootut и perlobj для углублённой информации по созданию классов, perlobj для документации по объектам, perlsub для объяснения функций и области видимости, а также perlxstut и perlguts для получения дополнительной информации по написанию расширяющих модулей.

© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/perlmod

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API