пятница, 9 октября 2009 г.

Cross compiling toolchain своими руками

Любопытство, довольно затратная, но интересная штука. Если не отмахиваться от него, то можно давольно далеко зайти только от того, что тебе интересно. Just for fun, как говорят на западе :)

Необходимые пояснения
Когда я только-только начинал думать о кросс-компиляции, мне были непонятны самые элементарные вещи, наподобии того, как происходит эта компиляция, нужен ли специальный компилятор, если gcc знает разные архитектуры, то можно ли и как его научить собирать код под них?? Не помню, нашел ли я где-то прямой ответ, но если взять сухой остаток, то получим следующее:
Для сборки под другую платформу нам необходим компилятор, собранный таким образом, чтобы работать на нашей платферме, а генерить бинарники под целевую (target), что очевидно. Потом, есть архитектура как такавая (x86, ARM, etc..) и есть различные её модификации (или ядра, варианты, типы процессора, не знаю как точно назвать), это i386, i586, etc. Архитектура включает в себя модификации, т.е. компилятор, собранный под x86 теоретически умеет делать бинарник под любой процессор данной архитектуры. Что значит "компилятор, собранный под архитектуру"? Это значит, что тип архитектуры, под которую компилятор будет собирать бинарники, определяется при сборке компилятора. Есть комерческие кросскомпиляторы, которые, по всей видимости, представляют из себя обыкновенный gcc с особыми параметрами сборки и, может, какими специфическими патчами. Собственно вопрос, на который я хочу ответить - "можно ли, вряв исходники обычного компилятора, и того, что ему там ещё надо по зависимостям, собрать мало-мальски нормальный кросс-компилятор с нуля?". Ответ - да, и далее я приведу общую методику сборки, которая, я надеюсь, применима для сборки под любую другую архитектуру. В конце заметки есть ссылка на архив с поправленными/искалеченными spec-ами и дополнительными патчами. Я не буду отдельно расписывать параметры сборки, ибо это всё есть в spec-ах.

Используемые версии
И так, мы будем собирать rpm-based toolchain для ARM на базе ALTLinux. Пакеты, для сборки стянуты из актуальной версии branch 5.0. Вот то, что нам понадобится:
binutils-2.18.50.0.9-alt5.src.rpm
gcc3.4-3.4.5-alt8.src.rpm
glibc-kernheaders-2.6.27-alt3.src.rpm
glibc-2.3.5-alt5.src.rpm
gcc4.3-4.3.2-alt9.src.rpm
glibc-2.9-alt5.src.rpm

Собираем binutils
Тут всё просто, как оказалось в дальнейшем. Надо лишь дополнительноуказать опцию --target при сборке и указать пути. В нашем случае это arm-alt-linux-gnueabi-, если мы хотим получить eabi-компилятор. Везде далее в качестве target используется эта же цель. С путями получилась засада, с одной стороны я хз какие они должны быть, а с другой от версии к версии компилятора расположение файлов "по умолчанию" отличается, что тоже вносит путаницу. Я выбрал общий префикс для всех пакетов /usr/lib/arm, по которому располагается структура катологов компилятора. Похоже, что сами собираемые утилиты уже расчитаны на более тесную и корректную интеграцию с системой без дополнительного префикса, но я этот момент не осилил.

Собираем gcc-3.4
Отрезаем всё, что можно отрезать, и что мешается нам при сборке. Любой ценой собираем минимальный компилятор для С. Без плюсов, без библитек, без потоков. Для всего этого понадбятся glibc, которых у нас сейчас ещё нет. Почему версия 3.4, чуть позже.

Собираем glibc-kernheaders
Тут тоже практически без приключений, просто установка нужных исходников по нужному пути, совсем не большая правка spec-а.

Собираем glibc-2.3.5
Берём наиболее старую версию glibc, доступную в репозитории, исключительно из-за того, что онаотносительно легко собирается с потоками linuxthreads. Для сборки posix-потоков нужны glibc. Сборку надо пройти также любой ценой и любыми патчами/костылями. Более новую версию glibc-2.5.1 с linuxthreads мне собрать не удалось, а более старые не собираются gcc4 и выше, т.о. чтобы собрать glibc-2.3.5 нужен С-компилятор gcc-3.4.

Собираем gcc4.3
В черновую. Но тем не менее, сейчас нам окружение уже позволяет собрать C и C++ компиляторы с поддержкой потоков. При сборке компилятор ешё собирает какие-то свои либы, и возникли проблемы с передачей параметров этим либам. Кастыли в приложеном архиве эту проблему устраняют.

Собираем glibc-2.9
И наконец, делаем рывок, и собираем последнюю версию glibc. При первой сбрке придётся отрезать пару вещей (патчи прилагаются), чтобы эта сборка прошла. Неприятности вызваны тем, что gcc4 собран со старыми glibc, пересоберём его

Повторная сборка gcc4.3 и glibc-2.9
И последний этап - "чистовая" сборка компилятора и glibc. На этом этапе проблем быть практически не должно, а некоторые кастыли, которые мы подставили по glibc на прошлом этапе, сейчас можно убрать.
Да, я не говорю о том, что после очередной сборки пакета мы сначала должны его установить, и лишь после этого продолжать сборку другого пакета.
И так, сухой остаток, мы имеем  arm-binutils-2.18.50.0.9-alt5, arm- glibc-kernheaders-2.6.27-alt3, gcc4.3-4.3.2-alt9, arm-glibc-2.9-alt5, т.е. весьма свеженькие версии в toolchain, которые ещё и могут быть собраны с нашими специфическими опциями. Работа данного toolchain пока проверена только на сборке ядра 2.6.27 и busybox. Сборка этих компонент прошла успешно, вылезел ли что при дальнейшей эксплуатции - неизвестно.

Известные проблемы
При сборке пакетов не работает AutoReq, пришлось отключить. Пути, по которым устанавливается toolchain, хоть и являются болееменее рабочими, но не являются правильными. При сборке glibc нет возможности корректно запустить тесты, но вроде работает без них (знаю что косяк, но осилить не могу).
Спасибо за внимание, надеюсь что мой небольшой опыт сможет кому-нить помочь.
P.S. Да, обещанная ссылка - http://galilley.at.nsu.ru/toolchain-addon.tar.bz2

понедельник, 5 октября 2009 г.

MailMan для малого предприятия

Введение
Как часто вам приходилось рассылать объявления на несколько адресатов? Вести обсуждение проблемы по почте с несколькими людьми одновременно? Искать в архиве писем решение проблемы годичной давности?
Оказывается уже давно есть простые иструменны, эффективно решающие эти проблемы - списки рассылки (http://ru.wikipedia.org/wiki/Рассылка_электронной_почты).
Принцип работы прост - для того чтобы распространить сообщение между подписчиками необходимо отправить письмо на специальный e-mail рассылки. Примером рабочей рассылки может служить http://lists.altlinux.org/ где идёт постоянное обсуждение проблем разработки и использования решений ALT Linux между членами сообщества. Применение такого подхода в рамках малого предприятия позволит структурировать рассылку объявлений, вынести часть дискуссий в рассылку и даёт возможность каждому участнику быть в курсе.
Для полноценного использования списков рассылки требуется, чтобы сервис работал на сервере с доменным именем. Однако если с регистрацией заморачиваться не хочется, а рассылки хочется, то можно немного пораскинуть мозгами, и поднять сервис на локальной машине а пересылку писем вести через сторонний внешний сервер. В качестве сервиса управления рассылками выбран один из наиболее популярных - mailman, и о том, как заставить его корректно работать из локальной сети, и пойдёт речь дальше.

Необходимый инструментарий
В качестве дистрибутива я использую ALT Linux 4.1, где всё необходимое есть в пакетах, и это надо только поставить и настроить. И так, ставим MailMan. Он требует, чтобы на машине работал сервер электронной почты. Ставим postfix, на всякий случай прихватываем модули для авторизации по sasl и отправку через cyrus. Fetchmail для сбора почты снаружи и передаци её postfix-у.
Алгоритм следующий. Поднимаем postfix, учим его отправлять локальные письма напрямую, а все остальные через внешний smtp. Создаём необходимые ящики на любимом сервере, пусть будет example.mail.ru. Адресов понадобится несколько, хотябы 4 на одну рассылку. Объясняем postfix-у как авторизовываться на smtp в зависимости от отправителя. Настраиваем fetchmail на проверку новосозданных ящиков и запускаем демоном. Запускаем MailMan и настраиваем там нашу рассылку.

Настройка postfix
Тут наступил на давольно редкие грабли. Почтовый сервер, на котором я остановился, требовал авторизацию открытым текстом поверх TLS. Погуглив и почитав маны на postfix, понял, что обучить его этому нельзя. Решение следующее - запускаем демоном stunnel:

stunnel -c -r example.mail.ru:465 -d 11125
В /etc/postfix/main.cf добавляем следующее:

relayhost = [127.0.0.1]:11125 #хост для отправки писем наружу
mynetworks = 127.0.0.1 #обслуживаем только локальные запросы
smtp_sender_dependent_authentication = yes #в зависимости от отправителья выбираем аккаунт для smtp
sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relayhost #список акаунтов
smtp_sasl_auth_enable = yes #говорим о необходимости регистрации
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd #перечисляем используемые аккаунты
smtp_sasl_security_options = #очищаем опции защиты
transport_maps = hash:/etc/postfix/transport #перечисляем случаи, когда почта должна доставлятся локально
myorigin = localhost #имя нашего хоста :)
recipient_canonical_maps = hash:/etc/postfix/recipient_canonical #таблица замен

alias_maps = hash:/etc/postfix/aliases, hash:/etc/mailman/aliases #файлы с алиасами

Тут стоит заметить, что если при отправке письма обратный адрес, и аккаунт, с которого произошла отправка, будут не совпадать, то такое письмо рискует попасть в спам. По крайней мере google делает именно так.
Далее полагаем, что мы хотим создать список рассылки mylists.

/etc/postfix/sender_relayhost
mylists@example.mail.ru [127.0.0.1]:11125 #адрес, на который необходимо посылать письма в рассылку
mylists-bounces@example.mail.ru [127.0.0.1]:11125 #отсюда будут приходить письма из рассылки
mylists-request@example.mail.ru [127.0.0.1]:11125 #отсюда будет приходить запрос на регистрацию
mylists-owner@example.mail.ru [127.0.0.1]:11125 #сюда надо писать письма для владельца рассылки
По хорошему, mailman-у надо ещё столько же адресов для связи с администраторами, можераторами и пр, но этот функционал мы не пользуем, и адреса, соответственно, не создаём.

/etc/postfix/sasl_passwd #перечисляем используемые аккаунты с явками и паролями
mylists@example.mail.ru mylists:xxx
mylists-bounces@example.mail.ru mylists:xxx
mylists-request@example.mail.ru mylists:xxx
mylists-owner@example.mail.ru mylists:xxx
/etc/postfix/transport
localhost.localdomain local: #письма с таким доменом отправляем локально
localhost local:

/etc/postfix/recipient_canonical
@yourhost.yourdomain @localhost.localdomain

Эта таблица требуется в том случае, если и машини есть какие-то абстрактные имя и домен, и они пролазят в заголовки писем или мешают корректно работать transport-ам. Хотя наверно это содержимое можно было бы просто перенсти в /etc/postfix/transport

На этом с отправкой писем вроде всё, хотя мелкие детали я мог и упустить. Перед дальнейшим шагом необходимо проверить работоспособность сервера, например mutt-ом. Перед запуском postfix не забываем сделать postmap для всех хешей.

Настройка fetchmail
Здесь всё гораздо проще.

cat ~/.fetchmailrc
set syslog
defaults protocol pop3, timeout 90, nokeep, fetchall, ssl
poll "example.mail.ru" user "mylists" there with password "infibgal" is mylists here;
poll "example.mail.ru" user "mylists-request" there with password "xxx" is mylists-request here;
poll "example.mail.ru" user "mylists-bounces" there with password "xxx" is mylists-bounces here;
poll "example.mail.ru" user "mylists-owner" there with password "xxx" is mylists-owner here;

Локально пользователей mylists* может не быть. Необходимые алиасы настраиваются автоматически mailman-ом при создании рассылки mylists.
Запускаем fetchmail демоном:
#fetchmail -d 90
Запуск можно прописать в загрузочные скрипты.

Настройка mailman
Теперь у нас всё подготовлено для работы mailman-а. Первоначальную настройку можно выполнить через alterator. При этом в качестве адреса веб-сайта обязательно указываем ip нашей машины, или ммылки внутри mailman-а не будут работать. В качестве адресо почтового сервера указываем example.mail.ru. Используемый MTA - postfix.

После этого идём не страничку админимстрирования http://наш.ip.ад.рес/mailman/admin и создаём первый список рассылки mylists. После этого обязательно обновим алиасы postfix-а, запустив newaliaces.
Теоретически, всё должно работать, если я не забыл каких-нить мелочей. Ура!