Как собирать под linux



Создание операционной системы на базе ядра linux. С нуля

Рано или поздно каждый пользователь Линукса задумывается над созданием собственного дистрибутива. Некоторые аргументируют это тем, что можно «все настроить под себя». Другие сетуют на то, что среди уже представленных дистрибутивов в Ветке нет идеального. А у них, якобы, есть суперконцептуальные идеи для собственной системы. Зачем я всю эту психологию затеял? Для того, чтобы сразу перекрыть кислород играющимся с Линуксом новичкам, которым делать нечего. Если уж задумались над созданием ОС, думайте до конца. Итак,

Я хочу создать ОС на базе Linux.
Сразу предупреждаю: был бы XVIII век, всех тех, кто для основы своей будущей системы выбирает другой развитый дистрибутив (и, не дай Бог, популярный. ) ждала бы виселица. Пост именно про создание системы с нуля, а значит, всякие Slax и Linux Mint мы трогать не будем.

Шаг 1. Выбор носителя
Вариантов немного: либо ваша ОС запускается с LiveCD, либо с жесткого диска, либо с флеш-устройства. Сразу оговорюсь: не скажу в посте ни слова про жесткий диск, потому что гораздо удобнее создавать гибкий дистрибутив из серии «все свое ношу с собой», либо залоченный дистрибутив на оптическом диске. Если вы научитесь создавать LiveCD или LiveUSB систему, с установкой на жесткий диск проблем не будет.

На всякий случай, приготовьте чистую флешку, CD-диск, и установите, наконец, Virtualbox.

Шаг 2. Компиляция ядра
По поводу выхода третьего ядра Linux, этот шаг воодушевляет на дальнейшие разработки… Итак, нам нужны исходники ядра. Каждый пользователь знает, что их можно достать на сайте kernel.org. Ни в коем случае, слышите?, никогда не прикручивайте к своей системе постороннее ядро, скомпилированное не вами!

Поскольку лень моя зашкаливала, я создал папку /linuxkernel и распаковал туда архив с исходниками. Залогинившись под рутом, я сделал следующее:

cd /linuxkernel
make menuconfig

В принципе, ядро можно конфигурировать тремя способами: make config (диалоговая конфигурация), make menuconfig (псевдографическая конфигурация через ncurses), а также make xconfig (графическая конфигурация). Суть в том, что make config испортит вам настроение надолго, т.к. он задаст все возможные вопросы по всем аспектам всех тем. Проблема с make xconfig встречается не у всех, но вот у меня встречалась и встречается. Если приспичило сделать через X, разбирайтесь сами. Оптимальный вариант — make menuconfig. Эта штука откроет вам псевдографический интерфейс, через который вы сможете настроить ядро на свой лад. Штука требует библиотеки ncurses, которая легко устанавливается.

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

Однако, направить вас все же придется. Перейдите по адресу File Systems —> и поставьте необходимые звездочки. Буква M означает, что поддержка того или иного драйвера осуществляется с помощью подключения к ядру внешнего модуля (ненавижу их!). Нам понадобится также поддержка isofs, для чтения дисков. File Systems —> CD-ROM/DVD Filesystems —> ISO 9660 CDROM file system support. Можно еще поддержать древнедосовские системы.

Чмошные разработчики Mandriva забыли разрешить File systems —> DOS/FAT/NT Filesystems —> NTFS write support, и на одном из их дистрибутивов я мучился с доступом к древневиндовскому разделу.

Посмотрите Processor type and features —> Processor family, мне порекомендовали выбрать Pentium-MMX.

Еще поройтесь в Device Drivers, полезно. Можете шутки ради понавыбирать там все и скомпилировать ядро весом > 50 Мб.

Далее. Ядро после загрузки себя должно загружать, собственно, систему. Либо из скомпилированных в себе файлов (используются во встраиваемых системах), либо из CPIO архива, сжатого чем-нибудь, либо из Initrd. Здесь вам не DOS, здесь не получится сразу сослаться на какой-нибудь init’овый файл в корневом каталоге диска или флешки. На самом деле получится, не слушайте дядю Анникса! Неправильно это, хоть в Интернете по этому поводу уже нехилая полемика ведется. В своей системе мы будем использовать initrd, т.к. это удобно, и не вызовет нецензурных выражений от сторонних разработчиков, в отличие от CPIO архива.

Ах, да, скомпилируйте ядро командой

Если у вас x86, найдете его по адресу /linuxkernel/arch/x86/boot/bzImage.

Для суровых челябинских программистов можно использовать Кросс-компайлинг…

Теперь нам нужен initrd с установленной там простейшей оболочкой. Мы будем использовать busybox, потому что эта няша может все. Способ мы украдем у Роберто де Лео, создателя Movix (я бы даже уважать его начал, если бы не запредельная любовь к Perl):

dd if=/dev/zero of=/dev/ram0 bs=1k count=5000 — Создаем Ramdisk в оперативной памяти нашего компьютера.
mke2fs -m0 /dev/ram0 5000 — Форматируем Ramdisk в системе Ext2
mkdir /distro — Создаем папку
mount /dev/ram0 /distro — Монтируем в папку /distro

Все, теперь у нас есть Ramdisk, емкостью в 5 Мб. Можно и больше, только не нужно. В отличие от Томаса Матеджисека, я не собираюсь пичкать initrd модулями в Squashfs, сжатыми LZMA. Все, что необходимо, будет скомпилировано вместе с ядром. Да, это не очень логично и правильно, но мороки в сто раз меньше. А специально для тех, кто осуждает такой подход, можно разрешить опцию модульности в ядре: Enable loadable module support.

В нашем Ramdisk’е, смонтированном в /distro, есть такая папка, lost+found. Это потому, что мы отформатировали его в ext2. Ни в коем случае нельзя ее удалять, хоть она здесь вряд ли поможет, образ-то фиксированный. Нам бы busybox сначала поставить…

Установка Busybox
Вот почему у таких классных проектов такие отстойные сайты? Хотя… это уже не суть важно, если исходники скачаны и успешно распакованы в папку /busybox.

Сконфигурировать busybox можно так же:

cd /busybox
make menuconfig

Если вы еще не поняли, что это, объясню. Busybox заменяет тонны UNIX приложений, хранящихся в папках /bin, /sbin, /usr/bin, /usr/sbin. Вместо этого, создается только одно приложение: /bin/busybox, а на него создается куча ссылок в указанных выше папках. Установим busybox следующей командой:

make CONFIG_PREFIX=/distro install

Еще Busybox создаст файлы /sbin/init и зачем-то /linuxrc, чтобы ваша система корректно запустилась. Но не все необходимые папки были созданы. Так что завершаем все руками и создаем:

/distro/etc
/distro/lib
/distro/dev
/distro/mnt
distro/proc
/distro/root
/distro/tmp
/distro/root

Если что забыл — вспомните, т.к. директории эти забыть сложно.

Все бы хорошо, вот только busybox для работы требует библиотеки, которые нужно скопировать в наш дистрибутив. Очень легко узнать, какие:

Программа покажет нам библиотеки, требуемые для нашей оболочки. Сразу говорю: linux gate создается ядром и скопирован быть не может.

При копировании библиотек можно отсекать отладочную информацию (так Роберто советует):

objcopy —strip-debug откуда куда

Делаем из Линукса Линукс

Надо создать несколько системных текстовых файлов:

Нам нужен /etc/inittab. Удивлю вас: в начале жизни система даже не знает, что такое Root. У нас даже пользователь безымянный, но вот файл общесистемных низкоуровневых фич (ОНФ) должен присутствовать. Пилотное содержание файла следующее:

# Запустить оболочку в консоли.
::respawn:-/bin/sh

# Перезагрузка по нажатии на Ctrl+Alt+Del.
::ctrlaltdel:/sbin/reboot

# Команды, выполняемые перед выключением и перезагрузкой.
::shutdown:/sbin/swapoff -a >/dev/null 2>&1
::shutdown:/bin/umount -a -r >/dev/null 2>&1

Следующий файл — /etc/fstab. Это таблица, в которой описано, что и куда монтировать при загрузке. Вещь бесполезная! Нам нужно обязательно смонтировать proc, иначе вообще ничего работать не будет, так что в файле пишем:

none /proc proc defaults 0 0

Для mount нужен также файл /etc/mtab. Создайте его и оставьте пустым.

Но mount сделает все необходимое только тогда, когда мы явно его об этом попросим. А просить мы будем в том самом первозагрузочном файле /etc/rc.d/rc.S (rc.d — папка). Вежливо попросим:

/bin/mount -av -t nonfs

Еще нам необходим файл профиля (b)(a)sh, тут вообще раздолье для фантазии. Создаем файл /etc/profile и заполняем следующим:

PATH=»$PATH:/bin:/sbin:/usr/bin:/usr/sbin:»
LESS=-MM
TERM=linux
HOME=/root
PS1=’> ‘
PS2=’> ‘
ignoreeof=10
export PATH DISPLAY LESS TERM PS1 PS2 HOME ignoreeof

Понадобится также файл /etc/shell, в котором указано, что есть оболочка:

Вот собственно и все. Можно записывать наш Ramdisk в файл.

mkdir /os — папка для «готового».
umount /dev/ram0 — размонтируем кусочек оперативной памяти.
dd if=/dev/ram0 of=/os/initrd bs=1k count=5000 — создаем файл.
gzip /os/initrd — сжимаем файл initrd

Читайте также:  Sb live 4830 драйвер

Создание загрузочной флешки

«Финишная прямая» нашей маленькой разработки. Берем флешку, вставляем, форматируем в vfat (можно и в ext, но не забывайте, что еще не все пользователи Windows застрелились).

На флешке создаем папку boot, в ней папки initrd и kernel.

Из папки /os копируем сжатый Ramdisk в папку boot/initrd на флешке, называем «main.gz». Из папки с исходниками ядра копируем bzImage в папку boot/kernel на флешке, называем «main.lk». Достаем файлы загрузчика Syslinux (в Интернете, либо из другого дистрибутива: тут не принципиально), а именно syslinux.bin, syslinux.boot, syslinux.cfg. Копируем их в корневой каталог нашей флешки. В файле syslinux.cfg пишем что-то подобное:

default mm
prompt 1
timeout 100
label mm
kernel /boot/kernel/main.lk
append initrd=/boot/initrd/main.gz load_ramdisk=1 ramdisk_size=5000 rw root=/dev/ram0
label mc
kernel /boot/kernel/main.lk
append initrd=/boot/initrd/custom.gz load_ramdisk=1 ramdisk_size=5000 rw root=/dev/ram0
label cm
kernel /boot/kernel/custom.lk
append initrd=/boot/initrd/main.gz load_ramdisk=1 ramdisk_size=5000 rw root=/dev/ram0
label cc
kernel /boot/kernel/custom.lk
append initrd=/boot/initrd/custom.gz load_ramdisk=1 ramdisk_size=5000 rw root=/dev/ram0
label hd
localboot 0x80

Тем самым мы поддержали кастомные initrd и ядро, которые, эксперимента ради, можно подключить к нашему дистрибутиву.

Узнаем, каким девайсом в системе является наша флешка (можно запустить mount без параметров и посмотреть). Это либо /dev/sdb1, либо /dev/sdc1, либо /dev/sdd1. Стоит отмонтировать флешку перед началом установки.

Устанавливаем syslinux (если пакета в системе нет, apt-get install syslinux):

syslinux -d путь_к_устройству

В корневом каталоге флешки должен появиться файл ldlinux.sys. Если он есть, значит syslinux.bin, syslinux.boot больше не нужны.

Как настроить BIOS на загрузку из флешки, я вам рассказывать не буду — это легко. Скажу только, что очень удобно создать папку /boot/initrd/init, в которую можно будет смонтировать /boot/initrd/main, для последующей работы с ним. Только не забудьте разжимать и сжимать его gzip’ом.

Как-бы я только что рассказал вам, как создать с нуля систему на Linux. Легко, не правда ли? Далее вы можете редактировать скрипт /sbin/init, ведь у вас еще много работы! Вы должны будете написать скрипт для монтирования флешки, который делает chroot в корневой каталог. В противном случае, вы вынуждены будете работать с ReadOnly разделом, величиной в 5 Мб. Но это уже совсем другая история.

Томас Матеджисек — создатель Slax и Linux Live Scripts.
Роберто де Лео — создатель Movix.

Источник

Как создавать, собирать, устанавливать и использовать пакеты с программами и библиотеками для UNIX-подобных систем

Речь пойдёт о программах и библиотеках для UNIX-подобных систем, распространяемых в виде исходного кода (в том числе в виде тарболлов), написанных обычно на C и C++ (хотя этот же порядок работы может применяться к софту на любом языке). Многие вещи в этой статье написаны применительно конкретно к GNU/Linux, хотя многое из статьи может быть обобщено и на другие UNIX-подобные ОС.

Под словом «пакет» я понимаю в этой статье пакет с исходными текстами, причём не пакет конкретного дистрибутива GNU/Linux, а просто пакет, исходящий от оригинальных авторов софта (UPD от 2017-02-09: кроме тех случаев, где из контекста ясно, что слово «пакет» употреблено в другом смысле).

В этой статье я разберу следующие вопросы:

  • Вот скачал программу или библиотеку. Как её собрать и установить? Как воспользоваться библиотекой?
  • Что такое префикс (prefix) установки? В чём разница между сборкой и установкой? Куда обычно устанавливают программы?

Я разберу только совсем базовые вещи. Те, которые типичные участники сообщества свободного ПО, программирующие на C и C++ под UNIX-подобные системы, обычно уже знают. Как создавать тарболлы (на примере «голого» make) и как устанавливать чужие тарболлы. Advanced советы по созданию «хороших» пакетов я не дам. «Продвинутые» вещи читайте в документации систем сборки, в замечательной статье «Upstream guide» от Debian (в её конце есть ещё куча ссылок о создании «хороших» пакетов). Многое в этой статье можно было сделать по-другому, моя цель: дать хотя бы один способ, не пытаться объять необъятное.

Предупрежу: начало будет совсем простым, но ближе к концу будет всё поинтереснее.

И ещё одно предупреждение. Я написал эту статью наскоро для одного человека. А после написания подумал, мол, раз уж написал, выложу уж на Хабр, чтоб не пропала. Поэтому в статье есть недочёты типа нечёткого структурирования статьи, фраз типа «не осуществляет сама инклудивание» и пр. Я это исправлять не буду. Может когда-нибудь в следующей жизни, когда руки дойдут. Выбор был между тем, чтобы публиковать так или не публиковать вовсе.

Итак, начнём мы с того, что создадим пакет с программой Hello, world. Для начала определимся с системой сборки.

Собственно, сама сборка пакета обычно осуществляется с помощью программы make (хотя это не единственный путь). Конфиг для make обычно лежит в файле под названием Makefile.

Есть несколько вариантов: просто использовать make либо использовать совместно с make некую высокоуровневую систему сборки (обычно autotools или cmake), которая будет, собственно, генерировать конфиги для make.

Мы в нашем примере будет использовать только make для простоты. Итак, создаём hello.c:

Внимание! Работает на GNU/Linux. Работа под macOS не гарантируется! Этот Makefile не является портируемым вообще на все UNIX-подобные системы! Подробнее будет дальше.

здесь означает символ табуляции.

Это далеко не единственный способ написать этот Makefile. Вообще, цель всей моей статьи — дать некую базу. Что ещё можно в этом Makefile изменить, вы можете потом узнать из других источников.

Также в этой статье я предполагаю, что вы знаете уж совсем базовые вещи про make. Я имею в виду, что вы знаете, что Makefile — это описание дерева зависимостей, и что он нужен, чтобы собрать ровно те файлы, которые нуждаются в сборке. В этой статье я расскажу про использование make при создании пакетов, про «виртуальные» цели make такие как install и all. Ещё я предполагаю, что вы уже знаете совсем базовые вещи про то, как запускать компилятор из командной строки, т. е. вы знаете, что такое cc -o hello hello.c .

Итак, теперь давайте разбирать наш Makefile.

Для начала скажу следующее. Допустим, пользователь скачал пакет. Ему нужно сперва собрать его, т. е. получить бинарники в каталоге с самим пакетом (либо в случае out of tree build получить их в неком другом каталоге, что не меняет сути), а затем установить, т. е. скопировать полученные бинарники в место их окончательного хранения в системе.

То есть смотрите. Вы залогинены под юзером user. Ваш домашний каталог /home/user. Вы скачали пакет, распаковали его, скажем в /home/user/Desktop/foo. Далее вы его собрали. Собрали в этой же папке, /home/user/Desktop/foo. Либо, если речь идёт об out of tree build, вы создали ещё одну папку /home/user/Desktop/foo-build и собрали в ней. Теперь, после сборки вы решаете установить её в /usr/local. Вот тут уже вам нужны права root. Вы при помощи sudo устанавливаете эту программу в /usr/local.

Пара слов о размещении каталогов в системе. Разберу лишь некоторые каталоги. Более подробную информацию можно найти в Filesystem Hierarchy Standard (поддержан многими дистрибутивами GNU/Linux) и по команде «man 7 hier» в GNU/Linux и, возможно, других ОС. Во всяком случае я расскажу, как они были устроены, скажем, лет пять назад (т. е. где-то в 2012-м году), всякие новые веяния типа недавнего нововведения в Fedora «давайте-ка мы всё переместим в /usr» я рассматривать не буду.

  • /bin — это бинарники (т. е. испоняемые файлы), важные для работы системы на ранних стадиях загрузки.
  • /sbin — это то же самое с тем отличием, что эти бинарники обычно может запускать только root.
  • /lib — бинарные файлы библиотек, нужные для программ из /bin и /sbin
  • /usr — «вторая иерархия файлов», т. е. это как бы «ещё один /»
  • /usr/bin — то же, что /bin, но на этот раз это бинарники, некритичные для загрузки
  • /usr/sbin — то же, что /sbin, но опять-таки, некритичные для загрузки
  • /usr/lib — бинарные файлы библиотек, которые не нужны для программ из /bin и /sbin
  • /usr/include — хедеры библиотек
  • /usr/local — «третья иерархия файлов», она опять содержит /usr/local/bin, /usr/local/sbin, /usr/local/lib и /usr/local/include, на этот раз эти каталоги предназначены для «локального администратора». Что это значит? Это значит, что (в случае дистрибутивов GNU/Linux с пакетным менеджером) каталоги, о которых речь шла до этого, находятся под контролем пакетного менеджера. А вот каталоги внутри /usr/local находятся в распоряжении «локального администратора», т. е. вас. Если вы хотите поставить что-то из сорцов, в обход менеджера пакетов, то можно поставить туда.
Читайте также:  Как вы выбирали linux

Теперь по поводу prefix. Когда вы устанавливаете какой-нибудь пакет, вы должны указать ему так называемый prefix, т. е. каталог, в который всё будет установлено. В этом каталоге будет создан подкаталог bin, в него будет установлены бинарники, будет создан подкаталог lib, туда будут установлены бинарные файлы библиотек, и т. д.

То есть, например, вы устанавливаете пакет, указывая ему prefix /usr/local. Тогда бинарники пойдут в /usr/local/bin, бинарные файлы библиотек — в /usr/local/lib и так далее.

Теперь вернусь к разбору Makefile. PREFIX — это и есть тот prefix, про который я сейчас говорил. В качестве дефолтного префикса (пользователь сможет его переопределить) у нас указан /usr/local — хороший дефолтный выбор. Обычно его всегда указывают в качестве дефолтного префикса при создании пакетов (к сожалению, некоторые пакеты этого всё же не делают, дальше будет подробнее). Далее идёт CC. Это стандартное название для переменной make, в которую кладут компилятор, в данном случае cc. cc — это в свою очередь обычно используемая команда для запуска компилятора по умолчанию в данной системе. Это может быть gcc или clang. На некоторых системах команда cc может отсутствовать. CFLAGS — стандартное название для переменной с флагами компиляции.

Если просто набрать make, то будет выполнена та цель, которая идёт в Makefile первой. Обычная практика в том, чтобы называть её all. И такая цель обычно собирает весь проект, но ничего не устанавливает. Эта цель обычно «виртуальная», т. е. у нас нет файла под названием all. Т. к. наша задача собрать лишь один бинарник hello, то мы просто делаем all зависящим от hello. Далее идёт описание цели сборки hello. Его можно было в принципе разбить на два этапа: сборка hello.o из hello.c и сборка hello из hello.o. Я так делать не стал для простоты.

Далее идёт install, установка. Это тоже виртуальная цель. Она зависит от all. Это сделано на случай, если пользователь сразу наберёт «make install», без «make». В этой цели мы сперва создаём папку, куда будем устанавливать, т. е. как и следовало ожидать, $(PREFIX)/bin, а затем устанавливаем в неё утилитой install.

Что делает install? Это почти то же, что и cp. Точные отличия я и сам не знаю. Для установки программ нужно использовать install, а не cp.

Бинарник устанавливается в $(PREFIX)/bin, потому что именно так и нужно делать. Бинарники идут в подкаталог bin в prefix, бинарные файлы библиотек — в lib в PREFIX и т. д.

Здесь я предполагаю, что у вас на системе установлен так называемый BSD install. В GNU/Linux’е он есть. В некоторых системах его может не быть. Может быть какой-нибудь другой install, который в этой ситуации не сработает. Именно это я имел в виду, когда сказал, что работа в разных ОС не гарантируется.

Здесь я не рассматривал DESTDIR, который, между прочим, крайне рекомендуется использовать в Makefile. Я даже не рассматривал цель clean.

Окей, давайте теперь создадим окончательный тарболл, так называют файл с расширением .tar.gz, .tar.xz и так далее. Поместите файлы hello.c и Makefile в папку hello-1.0 (принято указывать номер версии при создании тарболла). Затем установите в качестве текущего каталога тот, который содержит hello-1.0 и наберите, например:

Это создаст архив, внутри которого есть каталог hello-1.0, который содержит hello.c и Makefile. Таков способ распространения пакетов.

C++-вариант пакета. Исходник будет тем же, его нужно будет назвать hello.cpp. Makefile будет таким:

Обратите внимание, что стандартное название переменной для флагов к компилятору C++ — это CXXFLAGS, а не CPPFLAGS. CPPFLAGS же — это название переменной для флагов к препроцессору C.

Теперь разберём, как устанавливать пакеты из сорцов (любые, программы и библиотеки). Независимо от системы сборки. Этот алгоритм будет пригоден в том числе для тарболла, который мы создали только что. Допустим, что пакет, который нужно собрать, тоже называется hello.

Первый шаг: скачать и зайти в папку с сорцами. Тут два варианта: скачиваем из системы контроля версий (я разберу для примера git) или скачиваем тарболл.

Первый вариант. git. Делаем clone:

Это создаст папку hello. Без номера версии, т. к. мы скачали из системы контроля версий. Делаем cd в созданную папку, т. е. cd hello .

Второй вариант. Тарболл. Скачиваем тарболл. Потом набираем команду, скажем, tar -xf hello-1.0.tar.xz . Это создаст папку, например, hello-1.0 . Обычно, если создатель пакета сделал всё правильно, имя папки будет содержать номер версии. Потом делаем cd в полученную папку, например, cd hello-1.0 .

Теперь нужно собрать. Будем считать для простоты, что мы не будем делать out of tree build (если автор пакета требует out of tree build, там обычно будут написаны инструкции, как это сделать). А значит, собирать мы будем в этой же папке, где сорцы. Т. е. в этой папке, в которую мы сейчас сделали cd.

Дальнейшие действия зависят от системы сборки, выбранной в проекте. Но независимо от системы сборки мы в процессе сборки должны будем указать prefix. Причём обычно его нужно будет указать именно на этапе сборки, а не на этапе установки, т. к. часто prefix захардкоживается внутрь бинарника. А это значит, что после установки программы в определённое место её нельзя просто так взять и передвинуть.

Я дам здесь примерные инструкции, работающие в большинстве случаев. Точные инструкции вы увидите у автора проекта, там могут быть разные нюансы.

Обязательно указывайте prefix при сборке (что бы там не писал в инструкции автор). Если вы не укажите, то будет выбран дефолтный. Обычно это /usr/local, и это достаточно хороший выбор. А если нет? Что если автор пакета указал какой-то другой дефолтный префикс? Вы установите непонятно куда. В частности libqglviewer использует в качестве дефолтного префикса /usr, что совершенно неправильно (я отправил автору баг репорт). Итак, совершенно всегда указывайте префикс. Читайте инструкции, которые автор указывает на своём сайте и прикидывайте, куда впихнуть prefix.

Итак, какие могут быть системы сборки. Во-первых, может быть просто make. Такой вариант с голым make встречается редко. Один из немногих пакетов с «голым» make — bzip ( www.bzip.org ). В случае с нашим hello-1.0.tar.xz, который мы создали, у нас именно такой вариант.

Итак, собирать в случае голого make нужно так:

(Конкретно в случае с bzip на этапе сборки указывать PREFIX не надо. Но теоретически можно представить себе пакет, который захардкоживает PREFIX внутрь бинарника. Поэтому в общем случае PREFIX нужен.)

Следующий вариант — это autotools. В этом случае собираем так:

Следующий вариант — cmake. Собираем так (обратите внимание на точку в конце команды cmake):

Откуда точка в конце? Дело в том, что cmake’у нужно передавать путь к сорцам. А поскольку у нас не out of tree build, мы собираем здесь же. Сорцы находятся там же, где находимся мы. Поэтому точка, т. е. текущий каталог.

В случае с autotools и cmake команда, генерирующая Makefile (т. е. ./configure или cmake) записывает prefix в конфиги к make, поэтому в команде make (и в команде make install, про которую речь пойдёт далее) указывать prefix уже не нужно.

Итак, собрали одним из этих способов. Что дальше? Теперь нужно установить.

В случае голого make это делается так:

Нужно будет указать тот же prefix, который вы указывали при сборке.

Читайте также:  Как открыть буфер копирования windows 10

В случае autotools и cmake так:

В случае, если для записи в prefix вам нужен sudo, то вот эту команду для установки нужно будет набирать с sudo. Вообще, сборка всегда осуществляется с обычными правами, а вот установка осуществляется с теми правами, которые нужны, чтобы записать в prefix.

Окей, теперь посмотрим, что мы натворили. Допустим, что ставили мы не что-нибудь, а тот hello-1.0.tar.xz, который создавали до этого. Допустим также, что prefix, который мы указали, был /foo. Тогда в нашей системе появятся папки /foo, /foo/bin (если их не было до этого) и файл /foo/bin/hello. Что произошло? Указанная в командной строке при сборке переменная PREFIX=/foo переопределила заданную в Makefile PREFIX=/usr/local. В результате указанные в Makefile команды mkdir -p и install стали такими:

В результате бинарник положился в /foo/bin.

Теперь хочу ещё немного поговорить про префиксы. Какие префиксы вообще есть?

Префикс /. Вряд ли когда-нибудь вам придётся его выбирать. Он используется для программ, критичных для ранних стадий загрузки ОС (т. е. критичные элементы для загрузки находятся в /bin, /lib и т. д.) (впрочем, даже если вам нужно установить программу в /, её сперва устанавливают в /usr, т. е. собирают и устанавливают с префиксом /usr, а потом перемещают необходимое в / [т. е. перемещают из /usr/bin в /bin, скажем], во всяком случае именно так поступают авторы Linux From Scratch 7.10 с пакетом, скажем, bash).

Префикс /usr. Стандартный префикс, используемый обычно для программ, установленных через менеджер пакетов. То есть если вы установили программу через менеджер пакетов, она ведёт себя так, словно она собрана и установлена на вашей системе с префиксом /usr. Самому устанавливать пакеты с префиксом /usr нельзя.

Префикс /usr/local. Отличный префикс для установки туда программ самостоятельно. Хорош тем, что /usr/local/bin есть в дефолтном PATH (во всяком случае в дебиане). То есть сразу после установки программы вы сможете просто запускать программу по названию. Потому что бинарник лежит в /usr/local/bin, а /usr/local/bin есть в PATH. Плох тем, что там все программы лежат смешанно. Вот допустим, вы установили библиотеку foo, а потом библиотеку bar. Обе в этот prefix. Тогда дерево может выглядеть так (в совсем упрощённом виде):

Видите? Всё смешано. Нет единой папки, которая бы содержала «всё, связанное с foo» и другой папки, которая бы содержала «всё, связанное с bar». (Хотя это ваше дело, считать, что это действительно плохо или нет). Понятное дело, что такая же проблема присутствует при любой установке разных пакетов в один префикс. То есть префикс /usr страдает от того же: пакеты «размазаны» по системе (здесь уже речь идёт о пакетах, поставленных через менеджер пакетов, т. е. тех, которые, собственно, составляют систему). Собственно, это и есть одно из бросающихся отличий большинства UNIX-подобных систем от Windows. В Windows каждая программа находится в своей папке в Program Files. В большинстве UNIX-подобных систем она «размазана» по системе. (UPD от 2017-02-09: в Windows программы на самом деле тоже «размазаны», скажем, по реестру, просто это не так бросается в глаза.) Существуют дистибутивы GNU/Linux, «решающие» эту проблему, например, GoboLinux. Там каждый пакет в своём каталоге, как в Windows.

Префиксы вида /opt/XXX. Папку /opt предполагается использовать следующим образом: в ней нужно создавать подкаталоги, называть их названиями пакетов и использовать эти подкаталоги как префиксы. При таком подходе указанная выше проблема /usr/local (если считать её проблемой) исчезает. Каждый пакет будет установлен в свой каталог. Приведённый выше пример с foo и bar будет выглядеть так (я бы посоветовал в названии подкаталогов в /opt указывать ещё и номер версии):

Недостаток у такого решения тоже есть. Вам придётся самому добавлять все эти бесчисленные каталоги /opt/foo-1.0/bin (для каждого пакета) в PATH.

Префиксы, соответствующие домашним каталогам. Т. е., скажем, /home/user. Советую в случае, когда хочется поставить «только для себя», т. е. только для одного юзера. Или когда нет прав root. Возможно, ваши конфиги, поставляемые с ОС уже настроены таким образом, чтобы помещать

/bin в PATH при условии, что такой каталог есть. Так что PATH будет настроен как надо.

Каждый префикс может содержать в себе свои bin, sbin, lib, include и т. д.

Итак, что из этого выбрать? Если нужно поставить на всей системе, то я бы посоветовал /opt/XXX. Я сам так обычно ставлю.

Теперь о сборке, установке библиотеки и её использовании. Собирается и ставится библиотека так же, как и любой другой пакет, я это уже рассказывал выше. Так что перейдём сразу к использованию. Вот мы установили библиотеку в некий префикс, допустим, /foo. Теперь в /foo/include появились хедеры этой библиотеки, а в /foo/lib — бинарные файлы библиотеки (.so — динамическая библиотека, либо .a — статическая, либо и то, и то).

Допустим, нужно собрать некий файл a.c с этой библиотекой. Как это сделать?

Во-первых, вверху файла нужно написать #include, соответствующий подключаему хедеру. Ну а собирать нужно так:

Давайте разбираться. Для начала скажу, что I (большая английская и) и l (маленькая английская эль) — это две разные буквы. Не перепутайте их в приведённых командах.

Первая команда производит компиляцию, то есть создаёт a.o на основе a.c. Вторая — линковку, то есть окончательный бинарник на основании a.o.

В первой команде мы указали -I/foo/include. Это указание той папки, где нужно искать хедеры. Путь из этой опции соединится с файлом, указанным в #include. То есть если в командной строке указано -I/foo/include, а в файле написано #include , то получится /foo/include/foo.h, он-то и будет заинклуден.

Здесь опция -I/foo/include не осуществляет сама инклудивание. Она лишь указывает папку, где нужно искать, поэтому нужен ещё и #include. То есть нужен и -I/foo/include, и #include, одного из них недостаточно.

Линковка. -L/foo/lib — это указание папки, где нужно искать бинарные файлы библиотеки, т. е. файлы .so и .a. -lfoo — это указание на то, что нужно, собственно, прилинковать эту библиотеку к результирующему бинарнику. Имя библиотеки, указанное в опции -lfoo, соединится с папкой, указанной в -L/foo/lib и получится /foo/lib/libfoo (в начало названия файла вставляется слово «lib»), затем сюда прибавится .so (или .a) и опционально номер версии и получится /foo/lib/libfoo.so или, скажем, /foo/lib/libfoo.so.1. Это и будет тем именем .so-файла, который будет искаться.

Так же, как и при компиляции (a.o из a.c), нужны обе опции -L/foo/lib и -lfoo. -L/foo/lib указывает, где искать. А -lfoo даёт окончательную команду на прилинковку.

Вместо -lfoo можно прямо написать целиком путь до файла библиотеки, который нужно слинковать, например, /foo/lib/libfoo.so.1. Тогда опция -L/foo/lib не нужна. Получится так:

Библиотеку (будь то полный путь к библиотеке или опция вида -lfoo) нужно указывать после «своих» объектных файлов, в данном случае a.o. (Может, и не нужно, но на всякий случай лучше так делать.)

Можно соединить две наши команды в одну, тогда будет что-то такое:

В случае, если библиотека установлена с префиксом /usr (то есть просто установлена через менеджер пакетов), то опции -I и -L не нужны, считайте, что -I/usr/include и -L/usr/lib у вас как бы уже есть. То же, возможно, относится к /usr/local.

Если существует некая библиотека под названием foo, то она обычно запаковывается для дебиан в пакеты с названиями libfoo (или libfoo1, libfoo2) и libfoo-dev. libfoo содержит файлы .so, а libfoo-dev — хедеры. То есть хитрые разработчики дебиан умеют из одного пакета сделать несколько. На сборочных машинах дебиана пакет собирается и расфасовывается в несколько пакетов.

Если вы установите у себя на машине libfoo и libfoo-dev, то результат будет как если бы вы сами собрали пакет foo из исходных кодов с префиксом /usr. У вас на системе будут, скажем, файлы:

Напомню, что список файлов в данном пакете можно посмотреть по команде, скажем, dpkg -L libfoo . Ну а найти пакет по файлу с помощью dpkg -S /usr/include/foo.h .

Источник

Adblock
detector