Собираем софт для 32х-битных машин в 64х-битной системе
kayo — Пнд, 31/10/2011 - 00:34
Сказать по правде, не часто возникает необходимость собирать что-либо для x86_32, поскольку почти всё моё рабочее оборудование имеет архитектуру x86_64, а что касается пакетов для дистрибутивов, то их сборка обычно происходит на специально предназначенных для этого сервисах Launchpad.Net, Build.OpenSUSE.Org и им подобных. Однако бывают случаи, когда нам нужно просто скомпилировать программу, не создавая пакет, либо собрать пакет средствами этих сервисов по каким-либо причинам не представляется возможным.
Присказка об OpenEmbedded и BitBake
Когда впервые возникла потребность в сборке под 32-битную систему, у меня была как раз вторая ситуация. Есть такой проект, как OpenEmbedded, это по сути «большая энциклопедия рецептов» для полностью автоматизированной сборки всего, что только можно собрать, под любое железо. Проект использует систему сборки BitBake, которая путём анализа так называемых «рецептов» делает всё, что требуется, чтобы достичь цель: выкачивает необходимые исходники, корректным образом конфигурирует всё под задачу, собирает и вуаля. Однако на практике это оказывается куда суровее, чем в теории:
- Необходим интернет, чтобы стягивать исходники.
- Даже если у нас уже получены все необходимые исходники, все вместе они могут занимать гигабайты места на диске.
- Сборка обычно, дело весьма не быстрое, даже при параллелизации процесса занимает несколько часов, а то и суток.
- Как вы понимаете, в процессе сборки занимается ещё больше места на диске, в основном потому, что файловые системы не очень компактно хранят огромные количества мелких файлов.
Всё из выше сказанного делает практически невозможным создание пакетов, которые будут собираться с нуля на специализированных сервисах с использованием OpenEmbedded. И, наверно, единственный путь — собрать пакеты под все требуемые архитектуры самостоятельно и вместо пакета исходных текстов создать бинарный пакет.
Сказка о Chroot, Debootstrap и Linux32
Собственно так и было решено поступить. Системы с amd64 у меня всегда под боком, однако для сборки нам также непременно понадобится i386 окружение. Конечно, ничто не мешает установить все необходимые 32-битные пакеты в 64-битную систему, однако мне не хотелось засорять корневую фс неведомым хламом, который при случае не просто будет вычистить, поэтому решено было использовать отдельное chroot окружение. Нам потребуется утилита debootstrap, она поможет создать начальный экземпляр корневой файловой системы с нужным дистрибутивом и архитектурой. Всё довольно тривиально, и разобраться во всех тонкостях работы данной утилиты, думаю не составит особого труда. В моём случае потребовалось следующее:
sudo apt-get install debootstrap sudo mkdir /usr/local/ubuntu-i386 sudo debootstrap --arch i386 oneiric /usr/local/ubuntu-i386 http://archive.ubuntu.com/ubuntu
Если всё прошло гладко, то можно приступить к chroot-ингу в наше новое окружение. То что мы должны сделать: примонтировать всё что нужно в наше окружение, а затем погрузиться в него, после завершения работы должны не забыть отмонтировать всё, что примонтировали. В общем действий не мало, поэтому я написал простенький скрипт dive.sh и положил его в каталог /usr/local/ubuntu-i386:
#!/bin/sh path="$PWD" [ -z "$_" ] && path="$path/somehere" || path="$path/$_" # корень окружения home="$(echo "$path" | sed -r -e 's/\/{2,}/\//g' -e 's/\/(\.\/)+/\//g' -e 's/\/[^\/]*$//')" # что будем монтировать mnts="proc sys dev dev/pts home" # что будем отмонтировать umnt="home dev/pts dev sys proc" # монтируем for n in $mnts; do mount -o bind /$n $home/$n done # погружаемся chroot $home # немножко релаксируем, пока все ресурсы не освободились sleep 1 # отмонтируем for n in $umnt; do umount $home/$n done
Теперь если выполнить скрипт от рута, мы попадём в новое окружение, однако нам скорее всего не понравиться то, что мы там увидим, поэтому наведём порядок. Первое, что нам скорее всего захочется сделать, это настроить локали:
# Ставим нужный пакет apt-get install locale # Генерируем нужные локали locale-gen en_US.UTF-8 ru_RU.UTF-8
Теперь может потребоваться создать пользователей, я добавил себя, чтобы работать со своими файлами в реальном домашнем каталоге, который мы пробиндили выше:
# Добавляем пользователя с такими же uid и gid, как и в родительской системе # Группа с именем пользователя создаётся автоматически adduser kayo --uid 1000 -gid 1000 # Пробуем стать только что созданным пользователем su - kayo # Смотрим, что у нас в домашнем каталоге, должно быть много хорошо знакомых файлов ^_^ # Заодно проверяем, чтобы у файлов был правильный владелец и группа ls -al # Выходим exit
Теперь можно ставить всё что угодно на наше усмотрение, я в первую очередь поставил build-essential и bitbake:
apt-get install build-essential bitbake
При этом, потребовалось добавить подгруппу universe после main в /etc/apt/sources.list, потому что bitbake нет в main-е. BitBake поругался на то, что у меня оболочка не Bash, поэтому установил её и сделал по умолчанию:
apt-get install bash dpkg-reconfigure dash # Выбираем bash
Проделав это, вы уже будете многим довольны, однако это ещё далеко не всё. Например, если попробуете выполнить uname -a, то получите сведения о том, что вы находитесь вовсе не в i386 системе, а в x86_64, многие системы сборки получают информацию о системе хоста от этой утилиты, поэтому необходимо с ней что-то делать. Первая мысль была написать фэйк этой утилиты, однако погуглив немного, наткнулся на уже готовое решение, которое называется linux32:
# Ставим apt-get install linux32 # Пробуем обмануть себя linux32 # Проверяем, что получилось uname -a # Должны увидеть уже не x86_64
Данная утилита использует механизм LD_PRELOAD, добавляя разделяемую библиотеку, с фэйками функций, выдающих информацию об архитектуре, во всём остальном функциональность ни коим образом не страдает. Теперь можем добавить эту команду после chroot в наш скрипт.
Но и это ещё не всё, запустив BitBake, я получил множество сообщений об ошибках, оказалось, что программа использует разделяемую память shm, а соответствующее устройство не примонтировано, поэтому в список монтирования и отмонтирования добавим следующее: run, run/shm, и на всякий случай run/lock.
Для удобства я также сделал возможность с запуска скрипта с ключом user, чтобы, падая в окружение, сразу становиться обычным пользователем, и вот что в итоге у меня получилось:
#!/bin/sh path="$PWD" [ -z "$_" ] && path="$path/somehere" || path="$path/$_" home="$(echo "$path" | sed -r -e 's/\/{2,}/\//g' -e 's/\/(\.\/)+/\//g' -e 's/\/[^\/]*$//')" mnts="proc sys run run/shm run/lock dev dev/pts home" umnt="home dev/pts dev run/lock run/shm run sys proc" for n in $mnts; do mount -o bind /$n $home/$n done if [ "$1" = "user" ]; then opts="su - kayo" fi chroot $home linux32 $opts sleep 1 for n in $umnt; do umount $home/$n done
Вот и всё, удачного погружения.

Отправить комментарий