Давайте посмотрим, как можно урезать Inferno до минимума, необходимого для работы вашего приложения. Для этого надо разобраться, что происходит при запуске
emu — как загружается OS Inferno.Загрузка OS Inferno
Бинарник
emu уже содержит в себе ядро OS, все драйвера, и виртуальную машину Dis. Когда он запускается, ему необходимо параметром -r передать корневой каталог OS Inferno (сам emu при этом не обязан находится внутри этого каталога, так что можно использовать один emu с несколькими разными инсталляциями OS Inferno — отличающимися установленными приложениями и библиотеками).Загрузившись,
emu просто запускает /dis/emuinit.dis (все пути указаны относительно корневого каталога OS Inferno), который должен проинициализировать систему и запустить либо переданное параметром emu приложение либо шелл. (То же самое делает ядро Linux, когда, загрузившись само, просто передаёт управление на /sbin/init.) Если изучить исходники emuinit выясняется, что «проинициализировать систему» — это очень громко сказано, в Inferno всё делается очень просто, даже по сравнению с максимально упрощённой инициализацией Linux.Это всё. :) Таким образом, для получения standalone инсталляции OS Inferno с вашим приложением необходимо и достаточно следующих файлов и каталогов:
- Сам
emu, находящийся в любом каталоге. - Подкаталог
dis/с файломemuinit.dis. - Необходимые
emuinit.disбиблиотеки (в подкаталоге ).dis/lib/ - Файл(ы) и каталог(и), необходимые вашему приложению.
- Библиотеки, необходимые вашему приложению (в том же
).dis/lib/
Пример: Hello World
Начнём с простого приложения, без каких либо зависимостей. Вот такого:
implement HelloWorld; include "sys.m"; include "draw.m"; HelloWorld: module { init: fn(nil: ref Draw->Context, nil: list of string); }; init(nil: ref Draw->Context, nil: list of string) { sys := load Sys Sys->PATH; sys->print("Hello World!\n"); }
Сохраните его в
helloworld.b, запустите limbo helloworld.b и вы получите helloworld.dis:; ls -l --rw-r--r-- U 0 powerman users 265 Oct 25 02:54 helloworld.b --rw-r--r-- U 0 powerman users 147 Oct 25 02:54 helloworld.dis
Теперь давайте определим зависимости:
; disdep helloworld.dis ; disdep /dis/emuinit.dis /dis/lib/arg.dis /dis/sh.dis /dis/lib/bufio.dis /dis/lib/env.dis /dis/lib/readdir.dis /dis/lib/filepat.dis /dis/lib/string.dis
У
helloworld.dis зависимостей нет, хотя он и использует модуль Sys. Дело в том, что некоторые основные модули написаны на C и встроены прямо в emu, в том числе Sys. У emuinit.dis зависимостей много, но прямых из них только две — arg и sh. Остальное нужно для sh. А сам sh нужен только в том случае, если мы не указали параметром emu приложение, которое нужно сразу запустить. Поэтому мы можем ограничиться одной библиотекой arg. Поехали:$ mkdir inferno-standalone $ mkdir inferno-standalone/dis $ mkdir inferno-standalone/dis/lib $ cd inferno-standalone/ $ SRC=/usr/local/inferno/ $ cp $SRC/Linux/386/bin/emu ./ $ cp $SRC/dis/emuinit.dis dis/ $ cp $SRC/dis/lib/arg.dis dis/lib/ $ cp $SRC/usr/powerman/helloworld.dis ./ $ ./emu -r. helloworld.dis Hello World! $
Итак, у нас есть standalone инсталляция helloworld, готовая к работе на любой системе с Linux (для других OS нужно просто взять emu скомпилированный для этих OS). Давайте посмотрим, сколько она «весит». (Кстати,
emu под Linux по умолчанию не strip-нут, так что его можно заметно уменьшить.)$ strip emu $ find -type f -printf "%8s %p\n" 1562504 ./emu 147 ./helloworld.dis 652 ./dis/lib/arg.dis 1518 ./dis/emuinit.dis
Пример: калькулятор
Теперь давайте возьмём нормальное приложение. Например, калькулятор, входящий в стандартные утилиты Inferno. Он достаточно навороченный, кстати.
; disdep /dis/calc.dis /dis/lib/arg.dis /dis/lib/bufio.dis /dis/lib/daytime.dis /dis/lib/string.dis /dis/lib/rand.dis $ cp $SRC/dis/calc.dis ./ $ cp $SRC/dis/lib/{bufio,daytime,string,rand}.dis dis/lib/ $ find -type f -printf "%8s %p\n" 32567 ./calc.dis 1562504 ./emu 147 ./helloworld.dis 4630 ./dis/lib/bufio.dis 652 ./dis/lib/arg.dis 209 ./dis/lib/rand.dis 4051 ./dis/lib/string.dis 4701 ./dis/lib/daytime.dis 1518 ./dis/emuinit.dis $ ./emu -r. calc.dis 1+2 3 exit $ ./emu -r. calc.dis 1+2 3 $
Погодите, а как же зависимости самого emu?
Да, есть такой момент. Чтобы запустить emu на другой машине там должны быть все необходимые emu библиотеки. К счастью, библиотек всего две. К сожалению, обе относятся к X — это libX11 и libXext.
В принципе, эти библиотеки отлично ставятся без необходимости тащить полностью Xorg. Вот что пришлось бы установить на сервере с Gentoo Linux:
# emerge -pv x11-libs/libX11 x11-libs/libXext These are the packages that would be merged, in order: Calculating dependencies... done! [ebuild N ] x11-misc/util-macros-1.1.5 47 kB [ebuild N ] x11-proto/xproto-7.0.10 140 kB [ebuild N ] x11-proto/inputproto-1.4.2.1 47 kB [ebuild N ] x11-proto/kbproto-1.0.3 57 kB [ebuild N ] x11-proto/xf86bigfontproto-1.1.2 37 kB [ebuild N ] x11-libs/xtrans-1.0.3 USE="-debug" 101 kB [ebuild N ] x11-proto/bigreqsproto-1.0.2 36 kB [ebuild N ] x11-proto/xcmiscproto-1.1.2 36 kB [ebuild N ] x11-proto/xextproto-7.0.2 67 kB [ebuild N ] x11-libs/libXau-1.0.3 USE="-debug" 225 kB [ebuild N ] x11-libs/libXdmcp-1.0.2 USE="-debug" 216 kB [ebuild N ] x11-libs/libX11-1.1.4 USE="-debug -ipv6 -xcb" 1,540 kB [ebuild N ] x11-libs/libXext-1.0.3 USE="-debug" 256 kB Total: 13 packages (13 new), Size of downloads: 2,799 kB
Но для работы на сервере сетевого приложения (у которого GUI нет) эти библиотеки абсолютно не нужны. Ведь даже отлаживать это приложение в графическом отладчике я могу на своей рабочей станции, просто подмонтировав каталог
/prog/ с сервера, где запущено приложение. Для решения этой проблемы можно использовать специальную версию emu — emu-g, которая собирается и работает без libX11 и libXext.emu-g
Чтобы собрать
emu-g нужно запуститьmk CONF=emu-g install
После этого вы сможете запускать
emu-g вместо emu (кстати, emu-g весит после strip-ания всего 700KB):$ emu-g ; pwd /usr/powerman ; wm/wm wm: cannot load $Draw: module not built-in ;
P.S. Каталог inferno-strandalone в .tgz у меня занял 666KB. :-)
Update: добавлена информация об emu-g.