Путь джедая: компилируем GNU/Linux пакеты вручную

Зачем в наш век apt-get'ов и прочих rpm'ов собирать ПО для Linux вручную? Причин может быть несколько.

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

Во-вторых, компилируя из исходников знакомишься с культурой GNU, заглядываешь в код продвинутых прогеров и чему-то у них учишься. При этом не обязательно в совершенстве знать C, достаточно азов, но в процессе сборки эти азы здорово совершенствуются.

В-третьих, иногда быстрее найти ПО в исходниках, чем в репозитариях, да и далеко не всё в последних есть. К тому же в пакетах «от производителей» многие программы собраны в обширные коллекции, а нужен всего лишь маленький кусочек.

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

Рассмотрим процесс на примере сборки свежей верcии gcc (компилятора для Linux) и убедимся, что не так это страшно, как кажется.



На кой черт меня понесло собирать компилятор из исходников? Дело в том, что не все новые программы обрабатываются старыми компиляторами. К тому же новые версии gcc делают код более оптимизированным, а значит быстрым, эффективным. Разве плохо, если программы на компьютере будут работать пусть даже на 2-3% быстрее? С миру по нитке — голому рубашка ;).

Итак, что нужно знать о процессе компиляции.

1) ПО для Linux распространяется в виде исходных кодов, т.е. тех самых текстов, которые программисты пишут на разных языках (в основном на C). Исходные коды собираются в архивы, включающие в себя большое количество файлов, а также скрипты для правильной сборки и установки программ.

2) Такие архивы в формате tar.gz или tar.bz2 (тарболы) скачиваются из Интернета и распаковываются в специальную директорию — /usr/src:

wget ftp://gcc.gnu.org/pub/gcc/releases/gcc-4.5.0/gcc-4.5.0.tar.bz2
cp ~/gcc-4.5.0.tar.bz2 /usr/src
cd /usr/src
tar xvf gcc-4.5.0.tar.bz2


3) Для сборки пакетов из исходников нужны компилятор (gcc) и сборщик (make). Они присутствуют в любом дистрибутиве, хотя иногда из соображений безопасности их отключают (чтобы хакеры, в случае удаленного проникновения на машину, не смогли откомпилировать вредоносный код). Мы в качестве примера будем как раз собирать новый компилятор… посредством старого, установленного из пакетов.

4) Самым главным из сборочных скриптов каждого пакета является ./configure. Это исполняемый файл на языке bash, который проверяет: все ли условия для благополучной компиляции данного пакета есть на вашем компьютере (библиотеки, утилиты, характеристики ядра):

cd /usr/src/gcc-4.5.0
./configure


5) Если чего-то не хватает — ./configure выдаст сообщение об ошибке. Вам придется скачивать и компилировать другие пакеты, пока ./configure не отработает без ошибок. Результатом его работы должен стать файл с названием Makefile.

6) Следующая команда, которую нужно запустить —

make


На этом этапе ошибок бывает гораздо меньше, чем на предыдущем. Но все-таки они случаются и приходится изучать зависимости пакетов, что-то подправлять вручную. При наличии достаточного количества «масла в башке», а также доступа в Интернет проблемы, как правило, удается разрулить. Единственный инструмент, который для этого нужен — текстовой редактор.

7) Далее запускается

make install


Эта команда раскладывает откомпилированные программы и прочие файлы по каталогам системы: настройки в /etc, библиотеки в /usr/lib, бинарники в /usr/bin и т.п. На этом этапе ошибок почти не бывает.

Очень часто никаких проблем при сборке не возникает, да и сами команды можно запустить одной строкой:

./configure && make && sudo make install


Естественно, делать это нужно из каталога, где лежат исходники собираемой программы. Кроме того, make install запускается от имени root, т.к. нужно создавать файлы в доступных на запись только корневому пользователю каталогах.

Конечно, компилирование из исходников занимает много времени. Иногда несколько десятков минут, а если собирать что-нибудь типа wine, а тем более ядро, то и несколько часов. И все-таки, это ни с чем не сравнимый кайф, когда из нескольких десятков мегабайт чьих-то заархивированных текстов получаются программы, точно подогнанные именно под данный компьютер. Такие системы работают стабильнее и эффективнее, чем вытянутые из репозитариев.

Итак, рассмотрим весь процесс на примере сборки нового компилятора gcc. Получить его исходники можно по адресу

ftp://gcc.gnu.org/pub/gcc/releases/gcc-4.5.0/gcc-4.5.0.tar.bz2

Батюшки! Да здесь же 64 с лишним мегабайта! Неужели это всё соберется без ошибок? Конечно, с первого раза не соберется, но танцев с бубном не так уж и много для такого объема. Очень вероятно, что ./configure ругнется на отсутствие или устаревшие версии библиотек gmp, mpfr и mpc. Что это за звери? Да хрен его знает. Вроде что-то для работы с примитивами. Не ломая особо голову, скачиваем, распаковываем, устанавливаем (для каждого пакета распаковка в /usr/src, затем ./configure && make && sudo make install).

ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-4.3.2.tar.bz2
ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-2.4.2.tar.bz2
ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-0.8.1.tar.gz

Некоторые пакеты устанавливаются в особую директорию — /usr/local. А другие пакеты не могут их там найти. Здесь могут помочь символические ссылки, а также команда

export LD_LIBRARY_PATH=/lib,/usr/lib,/usr/local/lib


Итак, зависимости распаковали, установили, возвращаемся в каталог с исходниками gcc. Запускаем ./configure и, ощущая нехилый выброс адреналина в кровь, ждем: потребует еще что-то или нет? Надо же, больше ничего не нужно! Запускаем make и опять мандражируем до окончания процесса. Любителем Counter Strike такие ощущения и не снились Каждый раз во время очередной ошибки облом, поиск выхода, какие-то исправления, снова make. Но на этот раз повезло: огромный компилятор скомпилировался (каламбурчик-с) не пикнув. Делаем make install, убеждаемся, что работает (на уровне демонстрации версии):



Может я и поторопился заявить, что всё работает. Сначала нужно бы удалить старый компилятор, но это детали, которые каждый может решить самостоятельно.

Итак, компилятор собран и демонстрирует признаки жизни. Попробуем воспользоваться им, например, собрать самую главную библиотеку большинства дистрибутивов Linux — glibc. Скачиваем последнюю версию, распаковываем, запускаем ./configure… Обана! Вылетает с ошибкой. Причем непонятно, в чем она заключается. Написано, что детально сообщение о ней можно посмотреть в файле config.log. Что-ж, смотрим что в нем, обнаруживаем строку, где сказано, что невозможно запустить некую программу со странным именем as. Немного гугления — и вот уже понятно, что as — это GNU Ассемблер и получить его можно в составе пакета

ftp.gnu.org/gnu/binutils/binutils-2.20.1.tar.bz2

Скачиваем, распаковываем, собираем, устанавливаем.

На этот раз дело пошло повеселее: ./configure… Проскочили без ошибок? Нет Пишет, что сборку нужно вести в каком-то особом каталоге. Небывалое дело… Гуглим, выясняем, что

mkdir /glibc-build
cd /glibc-build 
/glicb-2.11.1/configure


Ну? Опять двадцать пять! Пишет, что нужно указать каталог установки /usr, а не /usr/local (по умолчанию). ОК, нам не жалко. Вспоминаем нужный ключ с помощью

/glicb-2.11.1/configure --help


Ага, вот как надо:

/glicb-2.11.1/configure --prefix=/usr


Пошло дело? Да нет, есть еще проблемка: не найдены исходники ядра. Значит нужно указать в опциях:

/glicb-2.11.1/configure --prefix=/usr CPPFLAGS="-I/usr/src/linux/include"


Уф… ./configure проскочили. Как насчет make? Вот блин… Выдает какую-то ошибку про неверные строки в каких-то ассемблерных файлах.

./sysdeps/i386/fpu/s_frexp.S: Assembler messages:
./sysdeps/i386/fpu/s_frexp.S:66: Error: invalid identifier for ".ifdef"


Копируем сообщение об ошибке в строку Google, немного вкуриваем сообщения разнообразных буржуйских форумов — и вот уже понятно, что не только у нас такое случалось. Нужно применить к библиотеке патч, касающийся модели процессора. Вот текст патча (выкладываю для отечественных пользователей, поскольку на русском нет вообще ничего толкового об этой ошибке):

diff -Naur glibc-2.11.1-orig/nptl/sysdeps/pthread/pt-initfini.c 
glibc-2.11.1/nptl/sysdeps/pthread/pt-initfini.c
--- glibc-2.11.1-orig/nptl/sysdeps/pthread/pt-initfini.c 2009-12-08 20:10:20.000000000 +0000
+++ glibc-2.11.1/nptl/sysdeps/pthread/pt-initfini.c      2010-04-17 02:24:02.000000000 +0100
@@ -45,6 +45,11 @@
/* Embed an #include to pull in the alignment and .end directives. */
asm ("\n#include \"defs.h\"");

+asm ("\n#if defined __i686 && defined __ASSEMBLER__");
+asm ("\n#undef __i686");
+asm ("\n#define __i686 __i686");
+asm ("\n#endif");
+
/* The initial common code ends here. */
asm ("\n/*...@header_ends*/");

diff -Naur glibc-2.11.1-orig/sysdeps/unix/sysv/linux/i386/sysdep.h 
glibc-2.11.1/sysdeps/unix/sysv/linux/i386/sysdep.h
--- glibc-2.11.1-orig/sysdeps/unix/sysv/linux/i386/sysdep.h  2009-12-08 20:10:20.000000000 +0000
+++ glibc-2.11.1/sysdeps/unix/sysv/linux/i386/sysdep.h       2010-04-17 02:24:02.000000000 +0100
@@ -29,6 +29,10 @@
#include <dl-sysdep.h>
#include <tls.h>

+#if defined __i686 && defined __ASSEMBLER__
+#undef __i686
+#define __i686 __i686
+#endif


Признаюсь честно: я не умею уверенно работать с патчами. Зато я умею соображать головой При анализе этого диковатого кода можно догадаться, что в файл nptl/sysdeps/pthread/pt-initfini.c нужно в районе 45-й строки добавить строки

asm ("\n#if defined __i686 && defined __ASSEMBLER__");
asm ("\n#undef __i686");
asm ("\n#define __i686 __i686");
asm ("\n#endif");


а в файле sysdeps/unix/sysv/linux/i386/sysdep.h — строки

+#if defined __i686 && defined __ASSEMBLER__
+#undef __i686
+#define __i686 __i686
+#endif


Что они обозначают — понятия не имею ;) Знаю только, что после внесения правки процесс компиляции совершился без ошибок (как раз пока я писал этот топик).

Осталось выполнить make install, но мы не только выполним, но и перевыполним: создадим модуль для Slax:

mkdir /tmp/glibc
sudo make DESTDIR=/tmp/glibc install
dir2lzm /tmp/glibc $SLAX_HOME/slax/base/glibc.lzm


Ну как квест? Это вам не ботов по бассейну шугать

Если новички не поняли этот топик до конца — ничего страшного, дело наживное. И все-таки при случае попробуйте собрать какой-нибудь несложный пакет. В случае удачи будете чувствовать себя в мире Linux гораздо увереннее.

Комментарии (23)

RSS свернуть / развернуть
+
+1
Вначале для новичков понятно все написано
Потом конечно hardcore action, но бывают вещи и похуже для компиляции, например, сборка из исходников OpenCASCADE и т.п. специализированных больших платформ
avatar

Sergei_T

  • 19 мая 2010, 00:27
+
0
В конце 90-х собирал один пакет из серии — библиотека для решения дифференциальных уравнений + анализ методом конечных элементов + визуализация.
Комп PC 386 вот памяти сколько был не помню. Около 50 зависимостей часть из которых вылезала на этапе сборки + пришлось пару скриптов дл я сборки руками править. Окончательная компиляция занимала около 6-8 часов.
А еще сборка пакета FElt, собирал его на разных платформах (Linux, Solaris, Windows, Cygwin) всек время что-нибудь вылазило с зависимосттями глубиной на 3-4 уровня.
avatar

Engineer

  • 19 мая 2010, 05:58
+
0
Да, подобный софт не так популярен, как обычный, поэтому и исправление ошибок сборки можно ждать долго — проще самому исправить.
avatar

Sergei_T

  • 19 мая 2010, 08:36
+
+1
ВО! Спасибо
Теперь я морально готов поставить openFoam))))
avatar

ksandras

  • 19 мая 2010, 00:28
+
0
Я же писал про него на блоге — у меня собирался
avatar

Sergei_T

  • 19 мая 2010, 00:28
+
0
Да, прям «фильм ужасов» получился: вначале птички, цветочки, а в конце — мясистое мочилово. Аффтар — аццкий сотона
avatar

yababay

  • 19 мая 2010, 00:40
+
0
Вот те и собрал gcc
Ну я в последнее время редко что компилирую. А прирост производительности кстати чтобы был — нужно тебе поиграться с флагами оптимизации
avatar

Sergei_T

  • 19 мая 2010, 00:44
+
0
из личного опыта — в далёкие придалёкие времена когда у меня ещё не было интернета и он был запредельно медленный и дорогой — в общем из того что было был комп был диск убунты 5ки на тот момент + диски Хакер где лежали разные интересные программулины 'unixoиды — НО в исходниках — и configure.sh-ки и make и make install я выучил и осознал в тот момент доскональна — сидя чуть ли не до посинения за компиляцией того или иного программного продукта. Хорошо когда хватает всех нужных пакетов
avatar

FREExLOADER

  • 19 мая 2010, 01:13
+
0
Да, я тоже помню времена — заказывал диски на линуксценте, а потом находил архивы с сорцами и компилил компилил компилил
avatar

Sergei_T

  • 19 мая 2010, 01:57
+
0
хорошо чувствовать начинаешь себя тогда когда все уже в .po файлах и запускается
avatar

FREExLOADER

  • 19 мая 2010, 01:16
+
+1
avatar

Sergei_T

  • 19 мая 2010, 02:23
+
0
Во-во, оно самое
Только в моем случае — Slackware. Это Gentoo для ленивых .
avatar

yababay

  • 19 мая 2010, 09:08
+
0
Вместо Gentoo мне понравился Sabayon — можешь устанавливать все из бинарных пакетов, а можешь и собрать
avatar

Sergei_T

  • 19 мая 2010, 10:14
+
0
Сейчас еще один важный пакет компилю из исходников — свежую версию glib — еще одной важнейшей библиотеки Linux. Столкнулся с проблемой — не хватает заголовочного файла gnu/stubs-32.h. Гуглю. Ответ «пакетчиков»: «Установите пакет glibc-devel». Пакет этот не особо-то и найдешь и что там такое, чего нет в исходниках — непонятно. Короче говоря, черный ящик, почти как Windows.

Ответ гентушников:

touch /usr/include/stubs-32.h


Помогло Почувствуйте разницу, как говорится
avatar

yababay

  • 19 мая 2010, 12:26
+
0
Просто где-то в ./configure есть проверка наличия этого файл
или где-то левый include
avatar

Sergei_T

  • 19 мая 2010, 12:52
+
+1
+#if defined __i686 && defined __ASSEMBLER__
+#undef __i686
+#define __i686 __i686
+#endif
Перевод:
Если уже были предопределены функции(в машинных кодах)
__i686 И __ASSEMBLER__, ТО
Исключить из сборки модуль __i686
И ПОДКЛючить модуль __i686__i686
все.
avatar

Markony

  • 20 мая 2010, 07:32
+
+1
Почему же в машинных кодах? До них еще очень далеко, здесь пока еще препроцессинг.
Если определены одновременно макросы __i686 и __ASSEMBLER__, то значение идентификатора __i686 обнулить (сделать пустым), а потом положить туда вместо какой-то прежней неправильной байды буковки "__i686". Как они будут обрабатываться дальше — тайна сия велика есть (для меня по крайней мере).

Я не силен в препроцессинге C и меня эта конструкция несколько удивляет — идентификатору _i686 присваивается значение _i686. Но это реально работает .
avatar

yababay

  • 20 мая 2010, 09:49
+
+1
Главное правило линуксоида
Если есть два способа, простой и сложный, то выбирай сложный, так как он проще простого способа, который тоже сложный, но ещё и кривой

bash.org.ru/quote/406702
avatar

yababay

  • 20 мая 2010, 09:54
+
0
Hy KAK-TO TAK ...
avatar

Markony

  • 20 мая 2010, 16:19
+
0
идентификатору _i686 присваивается значение _i686_i686
KAK-TO TAK ...
avatar

Markony

  • 20 мая 2010, 16:20
+
0
__i686 __i686
тут   ^ пробел
avatar

yababay

  • 20 мая 2010, 17:45
+
0
Da-a-a-a-a!
avatar

Markony

  • 20 мая 2010, 18:13
+
0
«Конечно, компилирование из исходников занимает много времени. Иногда несколько десятков минут, а если собирать что-нибудь типа wine, а тем более ядро, то и несколько часов. И все-таки, это ни с чем не сравнимый кайф, когда из нескольких десятков мегабайт чьих-то заархивированных текстов получаются программы, точно подогнанные именно под данный компьютер. Такие системы работают стабильнее и эффективнее, чем вытянутые их репозитариев.»
Вправьте кто-нибудь топик!
avatar

ahmetzyanov_d

  • 20 мая 2010, 20:00

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.