Содержание статьи
Не так давно участники проекта Elementary Project представили на суд общественности новую технологию упаковки Linux-приложений под названием AppImage, которая позволяет запускать программы из одного файла на любом современном дистрибутиве без необходимости в их установке. Так ли хороша эта технология, как говорят о ней создатели, и нужна ли она Linux, мы постараемся выяснить на следующих страницах.
Введение
На самом деле в Elementary Project (в рамках которого, кстати, готовят свой вариант Ubuntu, www.elementary-project.com) изобрели вещь, известную в кругах пользователей Windows под именем «переносные приложения» (Portable Apps), суть которых сводится к следованию трем простым правилам: не требовать установки на диск (скачал, запустил, работаешь), представлять собой один исполняемый файл (а не установочный архив) и не оставлять после себя следов (держать конфиги и все остальное внутри себя). Проще говоря: «Одна программа — один файл».
Преимущества таких программ виндузятники (а макосовцы — так и подавно) уже успели оценить. Их можно таскать с собой на флешке, выкладывать в Dropbox, хранить на рабочем столе вместо ярлыков, удалять одним нажатием клавиши. Они не требуют установки и не засоряют систему. Хороши со всех сторон, как ни посмотри. Но могут ли линуксоиды получить все это? Проведем эксперимент.
Тест
Для продвижения идеи AppImage-приложений был создан сайт Portable Linux Apps (www.portablelinuxapps.org), содержащий более сотни портабельных приложений.
Попробуем скачать одно из них и запустить в первом попавшемся дистрибутиве (Kubuntu 10.04 x64). Кликаем по ссылке Opera 10.70 и через минуту получаем на жесткий диск одноименный файл весом 15 Мб, причем без расширения (позже выяснилось, что AppImage-приложения должны носить вполне осмысленное имя с расширением .appimage, но баг на их сайте все испортил).
Натравливаем на него команду file и видим «ELF 32-bit LSB executable, Intel 80386 …» — обычный исполняемый файл. Ставим бит исполнения (chmod +x Opera 10.70), запускаем… упс, библиотека libfuse.so.2 не найдена. Приложение не запускается на одном из самых популярных дистрибутивов со всеми стандартными пакетами.
ОК, делаем вид, что ничего не произошло. Для верности запускаем ldd, видим небольшое количество библиотек-зависимостей, среди которых стандартные библиотеки пакета libc — та самая libfuse и libglib-2.0.
С первой все ясно — это часть пакета fuse, используемого для создания файловых систем в пространстве пользователя (позже мы узнаем, зачем она нужна), но что же такое вторая? Это библиотека для работы с данными и их хранения, часть графического тулкита GTK (на котором основан Gnome), но может использоваться и консольным софтом, таким как mc. Она действительно есть по умолчанию в большинстве дистрибутивов, но вполне может и отсутствовать.
В Kubuntu libglib-2.0 имеется, поэтому остается только доустановить libfuse. Набираем «sudo apt-get install libfuse2» и… «Уже установлена самая новая версия libfuse2». Оказывается, либа уже в системе (действительно, она используется в драйвере NTFS-3g, который есть в любом Ubuntu), но почему ее не может найти наша программа?
Ответ на этот вопрос прост: на 64-битном ядре libfuse невозможно собрать в режиме совместимости с 32-битным софтом, коим является наша портабельная Opera 10.70. Вывод: пользуйтесь 32-битным линуксом.
Отлично, берем 32-битный Ubuntu 10.04 и ставим его в виртуалку. Скачиваем все тот же файл «Opera 10.70», делаем исполняемым, запускаем. На этот раз все прошло отлично, программа запустилась почти без задержек и продолжала нормально функционировать на протяжении двух часов. Однако после закрытия приложения на диске был найден каталог «.opera», содержащий конфигурацию браузера, что свидетельствует о достаточно серьезной недоработке технологии (какой прок от такого браузера, если я не могу утащить его вместе со своими настройками и паролями на флешке или через Dropbox).
Короче, первый раунд AppImage с треском проигрывает, так как и работает далеко не везде (64-битные машины сейчас повсеместны), и всем требованиям портабельности не соответствует. На очереди вскрытие.
Что внутри?
Попробовав портативные приложения в деле, постараемся разобраться, как они работают и чем отличаются от обычных дистрибутивных пакетов вроде Deb и RPM. Сами создатели AppImage не особо заботятся о документировании своей технологии, говоря только о том, что приложения упакованы в обычный ISO-образ, который включает в себя программу и все ее зависимости, поэтому дальнейшие изыскания придется проводить самостоятельно.
Упакованная по правилам AppImage программа действительно представляет собой ISO-образ. Это легко проверить, если набрать команду mount сразу после запуска приложения и посмотреть на последнюю строчку. В начало образа (а точнее, прямо перед ним) записана небольшая программа (назовем ее загрузчиком), которая монтирует образ к временному каталогу (с помощью того самого fuse) и запускает содержащийся внутри скрипт AppRun, который запускает саму программу. Именно благодаря загрузчику AppImage-приложение можно запустить сразу после скачивания, необходимости в распаковке нет.
Во всем остальном это самый обычный ISO-образ, который можно смонтировать, чтобы изучить содержимое:
$ mkdir /tmp/appimage
$ sudo mount -o loop Opera 10.70 /tmp/appimage
$ cd /tmp/appimage && ls
Что мы видим внутри? Во-первых, корневой скрипт AppRun, который запускается загрузчиком сразу после монтирования ISO-образа. Его задача — подготовить приложение к работе и передать ему управление.
Содержимое Apprun
HERE=$(dirname $(readlink -f "${0}"))
export OPERA_DIR="${HERE}"/share/opera
exec "${HERE}"/lib/opera/opera "$@"
Эти три строки присваивают переменной окружения OPERA_DIR значение «/текущийкаталог/share/opera» и запускают программу из каталога «/текущийкаталог/lib/opera». Очевидно, OPERA_DIR указывает на каталог с ресурсами приложения, поэтому браузер использует его вместо стандартного «/usr/share/opera». Скорее всего, в случае многих других приложений скрипту AppRun пришлось бы использовать более хитрые приемы, чтобы переопределить дефолтовый каталог и обмануть приложение (например, символические ссылки), но здесь все просто. Следующий стандартный компонент AppImage — это файл opera-browser.desktop, содержащий метаданные приложения, такие как имя, путь к иконке (в данном случае — opera-browser.png), категории, к которым относится приложение, комментарии, типы ассоциированных с приложением файлов и т.д. (все в соответствии со стандартами freedesktop). Сама иконка программы дополнительно продублирована в скрытом файле .DirIcon. Остальное содержимое образа — компоненты самого приложения.
В данном случае это файлы LICENSE, install, opera-widget-manager и каталоги share и lib, представляющие собой локальную версию каталогов /usr/share и /usr/lib. Первый содержит все необходимые приложению ресурсы, документацию, man-страницы, второй — библиотеки зависимостей и сам исполняемый файл. У Opera зависимостей мало (разработчики компилируют ее статически, включая в бинарник даже библиотеку Xlib для работы с X Window), поэтому каталог lib почти пуст, только парочка библиотек самой программы и два плагина для Gstreamer. В целом, изнутри все выглядит довольно логично и просто, поэтому можно предположить, что и создавать такие образы будет легко.
AppImage своими руками
Путем вскрытия существующего AppImage-приложения мы узнали, какие компоненты оно может содержать. Обязательными из них являются всего три:
- Каталоговая структура самого приложения (бинарник, ресурсы, библиотеки-зависимости)
- Скрипт запуска приложения AppRun
- Файл .desktop, содержащий метаданные
Есть два способа создания этих компонентов: самостоятельная сборка приложения, написание AppRun и .desktop-файлов (последний обычно идет в комплекте с исходниками) или же вытягивание всего этого из уже существующих и заведомо работоспособных deb-пакетов. Не думаю, что первый способ придется кому-то по вкусу, поэтому сразу перейдем ко второму. Тем более, что он считается официальным и достаточно подробно описан на сайте Elementary Project (www.elementary-project.com/wiki/index.php?title=Creating_AppImages).
Подыскиваем подходящий пакет и распаковываем его с помощью следующей команды:
$ ar xv пакет.deb
Видим три файла: control.tar.gz, data.tar.gz и debian-binary. Первый и последний нам неинтересны, поэтому их можно смело удалять.
Второй файл содержит всю необходимую каталоговую структуру приложения как раз в нужном нам виде. Распаковываем его:
$ tar xzf data.tar.gz
И переименовываем получившийся каталог так, чтобы его новое имя заканчивалось на .appdir:
$ mv data пакет.appdir
Копируем файл имя_приложения.desktop из каталога пакет.appdir/usr/share/applications в корень каталога пакет.appdir. Помещаем туда же скрипт AppRun, загруженный с сайта Elementary Project:
$ cd пакет.appdir
$ wget www.elementary-project.com/downloads/AppRun
$ chmod +x AppRun
Запускаем скрипт AppRun, чтобы проверить приложение на работоспособность. Если заработало, значит, теперь у нас есть так называемый AppDir (Application Directory) — приложение, полностью заключенное в один каталог. Осталось только упаковать его в ISOобраз и добавить в начало загрузчик. Это можно сделать с помощью графического приложения AppImageAssistant (www.elementaryproject.com/downloads/apps/AppImageAssistant). Просто запускаем приложение, нажимаем кнопку «Forward», выбираем каталог пакет.appdir и вновь нажимаем «Forward». Все, AppImage готов.
Однако так просто все выглядит только на бумаге (точнее, на сайте Elementary Project). На самом деле процесс несколько сложнее. Дело в том, что .desktop-файл, представляющий собой обязательный компонент AppDir, можно найти далеко не в каждом пакете.
Изначально он был придуман для того, чтобы облегчить поиск и классификацию приложений в средах рабочего стола, поэтому в консольных приложениях его обычно нет, как нет и в старых, но хороших графических программах. Стандартный скрипт AppRun, доступный на сайте Elementary Project, также далек от идеала и не может обеспечить корректный запуск любого приложения. Все, что он делает — это выискивает в .desktop-файле путь к исполняемому файлу приложения, добавляет к путям поиска библиотек и команд локальные каталоги AppDir (например, пакет .appdir/usr/lib и пакет. appdir/usr/bin) и запускает исполняемый файл. Естественно, если обычное приложение хранит свои ресурсы где-нибудь в /usr/share, то при упаковке в AppImage они окажутся вне образа, и оно не сможет получить к ним доступ. Мы уже говорили о том, что в случае с браузером Opera эта проблема решается просто через присваивание имени нужного каталога переменной OPERA_DIR, в других случаях придется прибегать к более изощренным приемам.
История вопроса
Портабельные приложения были придуманы давно, но из-за простоты и очевидности идеи очень трудно понять, кто это сделал впервые.
Ведь даже в DOS, где о каких-то идеях и концепциях дизайна ОС говорить просто смешно, каждая вторая программа вполне могла носить статус Portable. Если же говорить о более экзотических ОС, то тут сразу вспоминается операционка компьютеров NEXTSTEP и ее более современный и разрекламированный потомок под названием Mac OS X. В этих ОС любое приложение представляет собой файл с расширением .app (на самом деле это каталог, который обрабатывается как отдельный файл), содержащий все компоненты приложения.
Еще раньше похожий подход применялся в операционной системе RISC OS, многие идеи которой позднее перекочевали в файловый менеджер ROX (об этом читай во врезке «AppImage и RISC OS»).
В UNIX-системах же подобные идеи обособления приложений в отдельные файлы и каталоги всегда считались ересью и проваливались в самом начале своего пути. Испокон веков UNIX исповедует собственную философию размещения файлов внутри файловой системы. Бинарные файлы — в одном каталоге, документы — в другом, библиотеки — в третьем. На момент появления UNIX эта идея была замечательной и делала разработчиков и пользователей счастливыми. Для просмотра доступных команд можно было вывести листинг каталога /bin, а для указания местоположения всех библиотек при сборке софта указать каталог /lib. Проблема этой идеи лишь в том, что она не рассчитана на установку дополнительного софта. Когда UNIX и философия открытых исходников стали популярны, количество стороннего ПО возросло в сотни раз, и с ним необходимо было что-то делать (не использовать же метод «make install» всю оставшуюся жизнь). И вот, чтящие традиции юниксоиды вместо того, чтобы действительно решать проблему, пошли по проторенной дорожке и создали пакетные менеджеры, которые встраивают новый софт в уже известную каталоговую структуру, предложенную еще 40 лет назад, а все те, кто двинулся иными путями, были объявлены иноверцами.
Со скрипом и множеством проблем, но такой прием все же прошел, и теперь мы имеем пакетные менеджеры, которые правильно распознают зависимости, легко устанавливают софт из удаленных репозиториев и могут обновить хоть всю ОС за раз. Однако до сих пор остаются нерешенными проблемы dll hell (одна программа требует одну версию либы, другая — другую, третья — третью, пакетный менеджер в шоке), огромного бардака в каталоге /usr (к какому пакету относится этот файл?), невозможности установки нескольких версий одной программы (подходы типа «apt-get install firefox3 firefox4» не в счет) и банальной потери базы пакетов (стерли ее — и пакетный менеджер беспомощен). В некоторых ситуациях этот классический подход к установке ПО оказывается выигрышным. Например, в серверных вариантах ОС он дает UNIX большое преимущество, однако для простого пользователя оказывается жутко неудобным и создает гораздо больше проблем, чем предлагает решений. Именно поэтому в последнее время идее портабельных приложений в Linux уделяют особое внимание. Одним из первых был проект Zero Install (zero-install.sourceforge.net), в свое время претендовавший на роль универсального менеджера пакетов всех времен и народов. Затем был Klick (klik.atekon.de) с лозунгом «Простейший путь загрузки и запуска приложений без установки». Теперь AppImage.
Выводы
AppImage-приложения не такие уж и портабельные, как заявляют их создатели, к тому же их просто делать только на бумаге. Скорее всего, они не займут достойное место в истории Linux, зато в очередной раз доказывают правильность утверждения о том, что домашний Linux должен отличаться от Linux'а серверного.
AppImage и RISC OS
В 1988 году компания Acorn Computers выпустила операционную систему RISC OS 2.00, предназначенную для компьютеров собственного производства. Кроме идеи файлов как логического центра графического интерфейса, операционка предлагала еще одну интересную концепцию под названием AppDir: любое приложение представляло собой специальный каталог, имя которого начиналось с восклицательного знака. При виде такого каталога файловый менеджер автоматически принимал его за исполняемый файл, а при клике — запускал файл !Run, расположенный внутри. Позже эту идею сперли создатели NEXTSTEP, но гораздо более интересным для нас является тот факт, что она же была реализована в файловом менеджере ROX-Filer (имя которого так и расшифровывается — RISC OS on X).
Создатели ROX лишь немного изменили первоначальную идею, заменив имя файла !Run на AppRun, файла !Sprites — на .DirIcon, выкинули из названия восклицательный знак и добавили вместо него расширение .appdir. Все это без изменений перекочевало в AppImage и обзавелось обязательным .desktop-файлом.
Толстый эльф
Год назад Ryan C. Gordon объявил о создании нового формата исполняемых файлов FatELF, который позволяет выполнять один и тот же бинарный файл на разных архитектурах. Например, без изменений запускать программу на процессорах архитектуры ARM и x86. В совокупности с идеей портабельных приложений FatELF позволил бы создать по-настоящему универсальные программы, которые работают везде и всегда.