Танцы с бубном и напильником. Все, что ты хотел знать о сборке из исходниковЕвгений Зобнин (zobnin@gmail.com) Рано или поздно все мы сталкиваемся с необходимостью сборки софта из исходников. Причин тому огромное множество, а проблем, сопровождающих этот процесс, еще больше. Что выбрать – архив tar.gz или CVS-срез? Как накладывать патчи? Что делать, если в исходниках нет скрипта configure? Как побороть ошибки компиляции? Как создать дистрибутивный пакет и заставить программу работать? Ответы на эти и многие другие вопросы ты найдешь в этой статье. Статья разделена на несколько мета-разделов, пошагово описывающих процесс сборки приложения и установки его в систему. Ты можешь проглотить ее сразу или использовать как справочник: разделы не зависят один от другого.
Получение исходных текстовПолучить исходные тексты приложения можно несколькими способами. Самый простой и наименее трудозатратный - скачать архив tar.gz или tar.bz2 (или даже tar.lzma) с официального сайта разработчиков. В этом случае достаточно распаковать полученный файл с помощью одной из приведенных ниже команд и перейти к следующему разделу статьи.
или
Примечание: если в твоей *nix-системе утилита tar не поддерживает флаг '-j', то задействуй конструкцию: «bunzip2 < имя.архива.tar.bz2 | tar xvf -». Использование репозитория VCS (системы контроля версий, к коим можно отнести CVS, Subversion, Git, Hg и множество других продуктов) в качестве источника «свежатинки» несет в себе массу полезнейших побочных эффектов. Тут и возможность всегда быть «на острие атаки», когда ты собираешь программу, последнее изменение в которую внесли 15 минут назад, и быстрое обновление (VCS выкачивают только изменившиеся файлы во время обновления), и чувство причастности к чему-то важному, в конце концов. Но есть и отрицательный момент - нестабильность хранящегося в VCS кода, которым, правда, можно пренебречь: в больших и серьезных проектах экспериментальные и особо неустойчивые нововведения обычно производят в отдельных ветках, а уже после вносят в основной код. Учитывая , что в последнее время развелось множество различных систем контроля версий, беру на себя обязанность описать процесс получения исходных текстов из репозитория каждой из них: CVS - уже мало где используется, но имеет место быть:
Subversion - используется в проектах, размещенных на sf.net и code.google.com:
Git - особо любима Linux-разработчиками, используется на kernel.org и github.com:
Mercurial - code.google.com и множество других, более мелких, хостингов:
Применение патчейИсходные тексты – это еще не все. Иногда возникает необходимость в наложении хитрых патчей на приложения с целью расширить их функционал или исправить баг (выпуск неофициальных патчей, временно устраняющих сложно уловимые баги в коде - частая практика в среде Open Source). Что делать? Все просто. Первое: следует убедиться, что патч создан для той версии программы, исходниками которой ты завладел - небольшие расхождения в версиях допустимы, но не рекомендуемы. Второе: просмотреть патч, возможно в нем содержится бэкдор. Третье: проверить, гладко ли накладывается патч, и накладывается ли он вообще:
Если все ОК, можно запустить процедуру модификации:
Патчи могут распространяться в сжатом виде (с расширением .gz или .bz2). В этом случае процедура наложения будет выглядеть так:
или
Не бойся экспериментировать, потому что изменения, созданные патчем, всегда можно отменить, запустив команду patch с флагом '-R'. Подготовка к сборкеПеред тем как приступить к сборке приложения, хорошо бы убедиться в том, что все необходимые инструменты установлены и готовы к использованию. Во-первых, тебе понадобится собственно сам компилятор, содержащийся в пакетах gcc-* или тому подобных. Во-вторых, компоновщик и архиватор библиотек из пакета binutils. В-третьих, заголовочные файлы стандартной библиотеки языка Си - пакет libc-dev, и, конечно же, утилита make. Во многих дистрибутивах все это можно получить через установку специального мета-пакета. Пример для Ubuntu:
Файл README, содержащийся в корне архива, обязателен к прочтению. Как правило, в нем описаны все необходимые приложению зависимости, а также рекомендации по сборке и ответы на вопросы. INSTALL тоже можно проглядеть, но обычно он является стандартной копией одноименного файла, поставляемого с набором утилит autotools, и не представляет интереса. Конфигурирование и сборкаВ открытых проектах используются специальные системы сборки, задача которых заключается в определении типа операционной системы, установке специальных флагов компилятора и линковщика, поиске необходимых приложению библиотек и заголовочных флагов и последующей сборке и установке приложения. Традиционно в качестве такой системы использовался покрытый сединой Makefile, в котором были описаны правила компиляции и установки приложения. Однако простота его синтаксиса вынуждала программистов выполнять двойную работу (написание самого приложения, плюс написание большого Makefile, который учитывал все особенности низлежащей ОС, самостоятельно находил библиотеки и т.д.) Поэтому в рамках проекта GNU был разработан набор утилит autotools, которые автоматизировали 95% этой работы и генерировали готовый к использованию Makefile. Позднее autotools, написанные на sh и perl, разрослись и стали настолько неудобны, что были разработаны альтернативные системы сборки, наиболее популярны из которых scons и cmake. К чему это я? К тому, что от используемой системы сборки напрямую зависит то, какие команды придется выполнять пользователю, чтобы, имея исходные тексты приложения, получить его бинарник. Например, в системах, основанных на Makefile (которые легко идентифицировать по наличию одноименного файла в корне архива с исходниками), для сборки используется привычная команда make, а конфигурация (пути установки, набор включаемых в приложение компонентов, флаги компилятора и т.д.) обычно указывается прямо в самом Makefile (хотя может находиться и в отдельном файле). Популярная система сборки autotools, идентифицируемая по наличию скрипта configure, более дружелюбна к пользователю и позволяет указывать все опции компиляции через аргументы командной строки:
Где '--prefix' означает путь установки приложения, флаги '--with-что-то-там' и '--without-что-то-там' позволяют включить или отключить добавляемые в приложение компоненты, а флаги типа '--enable-вот-это' используются для указания на использование специального кода. Скрипт оценит пригодность операционной системы для сборки и установки приложения и сгенерирует стандартный (но очень большой) Makefile, а для компиляции приложения останется набрать заветную команду make. Если же ни Makefile, ни configure в архиве не наблюдается - значит, программа использует одну из альтернативных систем сборки: scons (файл SConstruct в корне) или cmake (CMakeLists.txt). В первом случае необходимо установить сам scons:
И запустить процесс компиляции:
Опции обычно описаны в файле README и передаются утилите scons в качестве аргументов. Сборка с помощью cmake напоминает использование autotools с той лишь разницей, что вместо запуска ./configure необходимо набирать команду cmake. Вся последовательность команд выглядит примерно так (cmake требует указания каталога сборки, поэтому мы указываем точку):
Опции передаются на манер scons и также обычно описаны в README или INSTALL. Проблемы компиляцииПроблемы со сборкой приложения могут возникнуть как на этапе конфигурирования системы сборки, так и на этапе непосредственной компиляции приложения. Большинство из них связано с поиском тех или иных библиотек, заголовочных файлов и других компонентов, от которых зависит работоспособность приложения. Их легко идентифицировать по более чем многословным сообщениям системы сборки:
В этом случае достаточно установить требуемый пакет (и его заголовочные файлы, которые содержатся в пакетах *-dev) с помощью пакетного менеджера и вновь запустить процесс конфигурирования. В некоторых случаях сборщик может искать не сам пакет, а только его заголовочные файлы, выводя на экран сообщения вроде:
Тогда придется обратиться к поиску google, чтобы найти название пакета, содержащего необходимый заголовочный файл. Но это еще не все, и ты можешь сильно удивиться, обнаружив, что после установки пакета конфигуратор продолжает ругаться на его отсутствие. Причин тому может быть три: недоустановленные dev-пакеты, устаревшие версии пакетов в дистрибутиве, неправильные пути поиска библиотек и заголовочных файлов. Но если первая проблема решается легко, то с двумя другими есть сложности. Ты можешь попытаться обновить необходимый пакет с помощью пакетного менеджера, но это не сработает, если дистрибутив уже устарел, и в качестве обновлений к нему выходят только багфиксы, или если приложение требует новейшую версию библиотеки, которую еще не успели упаковать в пакет. Придется собирать из исходников уже саму зависимость, а также зависимость зависимости и т.д. Проблема с неправильными путями поиска обычно связана:
Решение: указать пути поиска через переменные компилятора и линковщика перед запуском сборщика:
Встречаются и совсем хардкорные случаи, когда зависимость нужной версии установлена вместе со всеми заголовочными файлами в каталоги, расположенные по правильным путям, а конфигуратор все равно отказывается их находить. Придется лезть в сам скрипт configure и комментировать все места, где производится поиск зависимости. Обычно после такого вмешательства конфигуратор сборщика отрабатывает без ошибок, и программа благополучно собирается. Достаточно часто можно наткнуться на приложения, которые не могут быть собраны новым компилятором (как это до недавнего времени было с эмулятором qemu). Поэтому, если ты встретил упоминание о чем-то подобном в README, просто установи рекомендованную автором версию компилятора и укажи путь к нему через переменную CC перед запуском сборщика:
Проблемы компиляции в BSDВ довесок ко всему перечисленному пользователи FreeBSD получают массу других проблем, корни которых растут из специфики самой операционной системы. Ведь, несмотря на наличие системы портов, которая как раз и создана для того, чтобы автоматизировать процесс сборки стороннего софта, необходимость «ручного вмешательства» возникает достаточно часто. Порты некоторых программ совсем не обновляются, другие помечены флагом BROKEN, а новый софт может пройти очень долгий путь перед включением в официальное дерево. Вот и приходится выкачивать исходники и самостоятельно компилировать программу, спотыкаясь по пути о множество повсюду разбросанных камней. Часто новички входят в ступор просто от того, что пытаются использовать привычную команду make для сборки приложения и получают гору ошибок о неправильном синтаксисе мэйкфайла. Связано это с тем, что BSD-системы используют собственную версию make, не унаследовавшую весь ворох нововведений, сделанных в GNU Make. Поэтому следует устанавливать gmake через систему портов и собирать приложение с его помощью (gmake && gmake install). 1. Ругань компилятора на необъявленные функции. В заголовочных файлах (*.h) ядра и библиотеки языка Си между Linux и FreeBSD есть отличие, – некоторые функции/системные вызовы могут быть объявлены в разных местах. Зачастую следует лишь набрать «man имя_функции» в терминале FreeBSD и посмотреть, к какому заголовочному файлу она относится. Если хидер не включен в файл, обруганный компилятором, значит, проблема решится за счет добавления строки «#include <заголовочный файл.h>» в исходник. Если же искомая функция вообще отсутствует в системе, то остается найти ее код на просторах интернета и скопировать прямо в исходник. 2. Ругань на отсутствующие макроопределения (по соглашению их имена пишутся заглавными буквами). Корень проблемы, опять же, в различии заголовочных файлов, Linux-варианты которых содержат множество подручных макроопределений, а их может и не быть в заголовочных файлах FreeBSD. Решение: найти код макроопределения в интернете или Linux-хидерах и вставить его прямо в исходник приложения. 3. Ругань на функции, которые являются системными вызовами (проверяется с помощью обращения ко второй секции man-страниц в Linux). В большинстве случаев это тупик. Если сам разработчик не позаботился об опции, отвечающей за их отключение, единственный путь - переписывание исходника, что сложно и недостойно. УстановкаПосле сборки приложение необходимо установить. В подавляющем большинстве случаев эта операция выполняется с помощью простой команды «make install» (или «scons install»), которая копирует компоненты приложения на свои места и устанавливает права доступа. Вот только удалить приложение после зачастую можно только с помощью ручного затирания его файлов (может помочь также команда «make uninstall», выполненная из корня исходников, но она наличествует далеко не всегда). Поэтому лучше прибегнуть к специализированным средствам для создания настоящего дистрибутивного пакета. Наиболее простое и эффективное из них - утилита checkinstall (http://checkinstall.izto.org), предназначенная для создания пакетов в момент установки программы из исходников. Ее уникальность в удивительной простоте использования. Все, что нужно сделать для создания пакета и установки его в систему - набрать одну из приведенных ниже команд вместо «make install»:
После того как установка приложения будет завершена, выполни команду strip для бинарников и библиотек приложения с целью уменьшить их объем. Уже установленные приложения можно «стрипнуть» с помощью двух команд:
Проблемы запускаС гордостью за выполненную работу ты набираешь в терминале заветную команду и – бац! – программа завершается, не успев начать выполняться. Wtf? По всей видимости, где-то в процессе инициализации программа встретила ошибку и завершилась. Хорошо было бы увидеть хоть какое-то диагностическое сообщение, но далеко не все программисты столь заботливы. Что делать? Первое: перечитать README. Возможно, в некоторых системах или при стечении определенных обстоятельств софтина не работает, о чем автор уже знает. Второе: проверить, какие компоненты программа установила в систему, и доступны ли они ей. Например, она может использовать один из подкаталогов каталога /var для хранения своих временных файлов, а он почему-то не был создан или получил неправильные права доступа. Третье: запустить программу с флагом '--help' и проверить, поддерживает ли она дебаг-режим с выводом диагностических сообщений на экран. Если это так - включить его. Наверняка на экране появится сообщение об ошибке и, возможно, даже описание способов устранения. Четвертое: если это сервер, который ведет логи - проверить их на наличие диагностических сообщений. Если же ничего не помогло, задействуй тяжелую артиллерию. В любой *nix-системе есть трассировщик системных вызовов, предназначенный для отслеживания всех сисколлов, произведенных приложением, и проверки их возвращаемого значения. В Linux он зовется strace, а во FreeBSD - truss (хотя через систему портов доступен и strace). Просто запусти программу под его управлением, и ты увидишь все ее обращения к операционной системе в режиме реального времени:
Вывод лучше смотреть с конца, постепенно пролистывая все вызовы close в поисках последовательности вызовов open. Затем необходимо проверить, какие из последних вызовов open вернули отрицательный статус (-1), и просмотреть, к чему происходило обращение. В 95% случаев ошибка связана с отсутствием (или недоступности вследствие неправильных прав доступа) какого-либо файла или каталога. Трассировщик покажет все обращения к файлам, и найти недоступного будет не сложно. Флаги оптимизацииИгры с флагами оптимизации - одна из основных причин краха или неправильной работы самостоятельно собранных приложений. Следует понимать, что любая оптимизация выше уровня '-O1' (или просто '-O') потенциально опасна. Флаг '-O2', хоть и не страшен для большинства приложений, запросто убивает низкоуровневый код с ассемблерными вставками, а '-O3', активирующий агрессивный режим, идущий против стандартов, легко отправляет в корку каждое второе приложение. Об остальных флагах и говорить не стоит, они предназначены для весьма узкого круга приложений, поэтому мы бы порекомендовали остановиться на следующих опциях оптимизации и беречь свои нервы и нервы других. INFOСистема портов Gentoo, ArchLinux или FreeBSD - отличный источник информации о том, как правильно собрать программу с учетом всех зависимостей. Если для запуска собранного бинарника требуется подключить динамические библиотеки, расположенные в нестандартных каталогах, используй ldconfig(8). Пример для OpenBSD: «ldconfig /usr/local/lib /usr/X11R6/lib». WARNING BSD-версия команды patch не поддерживает флаг Осторожнее с расширениями tgz и tbz! Такие архивы могут содержать не исходный текст программы, а бинарный пакет для установки в BSD-системы. |