Устанавливаем Staticperl. Часть 3.

В предыдущих статьях было рассказано, что представляет из себя staticperl, как его установить. В этой статье пойдет речь об его использовании.

Запуск из консоли

Прежде чем рассказать о том, как собирать бинарные файл, хочу рассказать о том, что еще можете сделать с новособранным Perl.

Во первых, все программы, или скрипты, поставляемые из устанавливаемых модулей располагаются в директории $STATICPERL/bin, где $STATICPERL это разыменованная переменная с тем же именем, которая указывает на директорию, куда устанавили собранный Perl. Также эту переменную мы указали в файле ~/.staticperlrc.

В нашем случае, она должна быть примерно такой:

shell> . ~/.staticperlrc
shell> echo $STATICPERL
/home/gw/.staticperl-5.20.1

А вот структура директорий внутри ее:

shell> ls $STATICPERL
bin  cache  cpan  lib  patched  perl  src

Запуск perl, который был собран с помощью staticperl можно производить несколькими способами. Во-первых, через сам скрипт:

shell> ~/staticperl perl -v
This is perl 5, version 20, subversion 1 (v5.20.1) built for i686-linux-64int

Copyright 1987-2014, Larry Wall
...

Во-вторых, по прямому пути:

shell> ~/.staticperl-5.20.1/bin/perl -le 'print hello'
hello

Я же предпочитаю заменять вызов perl, который идет по умолчанию в системе, на тот, что я использую вместе с staticperl.

shell> . ~/.staticperlrc
shell> export PATH=$STATICPERL/bin:$PATH
shell> perl -v | grep This
This is perl 5, version 20, subversion 1 (v5.20.1) built for i686-linux-64int

Этот способ также позволяет напрямую запускать другие полезные команды, такие как perldoc. Вывод последней команды будет всегда ссылаться на документы той версии Perl, которую мы собрали.

Собираем Hello World в исполняемый файл

Создадим в отдельной директории обычный Perl скрипт следующего содержания:

Hello World (hello-world.pl) download
#!/usr/bin/perl -w

use strict;

print "Hello World!\n";

Теперь нам надо сделать так, чтобы получился бинарный файл со статической линковкой. Напишем скрипт сборки программы. Не смотря на то, что это можно выполнять прямо из консоли, преимущество файла в том, что его можно будет использовать позднее в других проектах.

make.sh for Hello World (hello-world-make.sh) download
#!/bin/sh

# your application name
APP_NAME="hello-world"

# perl script to boot
BOOT_SCRIPT="hello-world.pl"

# staticperl sh-script
SP=$HOME/staticperl


# build command
$SP mkapp $APP_NAME --boot $BOOT_SCRIPT $@

Как видно, мы запускаем непосредственно скрипт, передаем ему команду mkapp, со значением имени приложения hello-world и опцию –boot запуска стартового скрипта с именем hello-world.pl. Переменная $@ указывает на все аргументы переданные bash скрипту, что позволит легко добавлять новые опции при сборке.

Попробуем запустить сборку программы:

shell> sh hello-world-make.sh
processing bundle files (try more -v power if you get bored waiting here)...
generating bundle.h... 
generating bundle.c... 7292 octets (3073 data octets).

generating bundle.ccopts... -g -DPERL_DISABLE_PMC -DPERL_ARENA_SIZE=16376 -DNO_PERL_MALLOC_ENV -D_GNU_SOURCE -DNDEBUG -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g -DPERL_DISABLE_PMC -DPERL_ARENA_SIZE=16376 -DNO_PERL_MALLOC_ENV -D_GNU_SOURCE -DNDEBUG -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -I/home/gw/.staticperl-5.20.1/perl/lib/CORE

generating bundle.ldopts...  -Wl,--gc-sections -Wl,--allow-multiple-definition -L/usr/local/lib /home/gw/.staticperl-5.20.1/perl/lib/auto/PerlIO/scalar/scalar.a /home/gw/.staticperl-5.20.1/perl/lib/CORE/libperl.a -lm -lcrypt

build hello-world...
 

Попробуем запустить:

shell> ./hello-world
Can't locate strict.pm in @INC (you may need to install the strict module) (@INC contains: CODE(0x8b89894)) at !boot line 3.
BEGIN failed--compilation aborted at !boot line 3.
Compilation failed in require.

Как видно, не хватает файла strict.pm. Давайте, добавим его в командную строку и запустим заново собранный бинарник:

shell> sh hello-world-make.sh -Mstrict.pm
...
shell> ./hello-world
Hello World!

Посмотрим, что представляет из себя файл:

shell> file hello-world
hello-world: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xff11560676320866b68497edecdd2b9d8027f19a, not stripped

Файл собран для 32-битной системы GNU/Linux, динамически слинкован и не избавлен от лишних символов (strip). Исправим файл сборки на следующий:

make2.sh for Hello World (hello-world-make2.sh) download
#!/bin/sh

# your application name
APP_NAME="hello-world"

# perl script to boot
BOOT_SCRIPT="hello-world.pl"

# staticperl sh-script
SP=$HOME/staticperl


# build command
$SP mkapp $APP_NAME --boot $BOOT_SCRIPT \
-Mstrict \
--static
$@

Итак, как видно, добавили опцию для включения модуля -Mstrict, а также указали опцию для статической сборки –static. Посмотрим, что получится:

shell> sh hello-world-make2.sh
...
shell> ./hello-world
Hello World!
shell> file hello-world
hello-world: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=0x3ab67186cce5acd6c6672741ed2249c7c466d1aa, not stripped

Как видно, теперь файл собрался без зависимостей. Вот так, просто и легко мы научились собирать простые Perl-скрипты в один бинарный файл.

Опции сборки

Рассмотрим некоторые опции, которые могут быть полезны:

  • –strip - указывает режим урезания данных
  • –usepacklists - включать в сборку модули из файла .packlist
  • –allow-dynamic и –static - опции компиляции
  • –add - включить Perl файл

strip

Указывает режим урезания строк в файлах. Проще говоря, при включенном режиме все лишние символы удаляются, а код превращается в одну строку. За счет этого снижается объем файлов, а значит и размер вашего бинарного файла. Значение может быть none, ppi, pod.

Наибольший выйгрыш в размере дает режим ppi.

Примечание. Некоторые модули могут перестать корректно работать, если использовать –strip ppi.

usepacklists

После установки модуля может появляться файл .packlist, например:

shell> cat /home/gw/.staticperl-5.20.1/lib/auto/Clone/.packlist
/home/gw/.staticperl-5.20.1/perl/lib/Clone.pm
/home/gw/.staticperl-5.20.1/perl/lib/auto/Clone/Clone.a
/home/gw/.staticperl-5.20.1/perl/lib/auto/Clone/autosplit.ix
/home/gw/.staticperl-5.20.1/perl/lib/auto/Clone/extralibs.ld

Если данная опция включена, то при указании включения модуля вам не придется указывать все его дочерние модули, т.о., вместо

-MURI -MURI::Escape -MURI::URL ...

достаточно указать:

-MURI
--usepacklists

allow-dynamic и static

Определяет тип линковки для конечного файла. Также может быть полезна опция для линковки отдельных компонентов –staticlib.

add

Включает в сборку отдельный файл, который может расположен вне директории $STATICPERL/lib. Например,

--add '/path/to/Local/Module.pm Local/Module.pm' 

Тогда, в своем приложении для его использования достаточно написать use Local::Module;.

Настоящие проекты и staticperl

В более крупных приложениях на Perl, используется большое количество разнообразных модулей. В данной статье я не стану вдаваться в детали, вместо этого предлагаю прочитать внимательно документацию по staticperl на CPAN.

Вы можете попробовать собрать ради интереса свои приложения, либо воспользоваться некоторыми из моих: Perl PasteBin, Perl Web Run Daemon.