- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF133:ARM
Материал из Linuxformat.
- Linux и ARM
Содержание |
ARM: Пишем программы
- Статья из предыдущего номера лишь раздразнила ваш аппетит? Приготовьтесь к настоящему делу: сегодня Андрей Боровский будет создавать ARM-приложения на обычном компьютере.
Разработка для мобильных устройств перспективнее, чем для ПК, и вот почему. Важную роль в развитии ПО для настольных компьютеров сыграл рост производительности их процессоров, и хотя закон Мура по-прежнему справедлив, наращивание числа ядер не приводит к такому же росту производительности, как увеличение тактовой частоты. ПК находятся в стадии экстенсивного роста, тогда как мобильные устройства еще не прошли фазу интенсивного, при котором подъем тактовой частоты, объемов оперативной памяти, разрешающей способности экрана не просто ускоряет работу, но и открывает перед разработчиком новые возможности. Кроме того, начинка мобильных устройств все еще не унифицирована, и орды программ, написанных для старых гаджетов, не могут быть автоматически перенесены на новые. Все это создает прекрасную творческую атмосферу, в которой талантливый программист может всесторонне проявить себя.
Средства разработки для мобильных устройств столь же разнообразны, как и сами устройства – начиная с систем программирования на «голом железе» и заканчивая пакетами разработки для специфических закрытых сред. Мы же рассмотрим инструменты программирования для «полноценных Linux-систем» (не обязательно мобильных), на базе процессора ARM.
Scratchbox
Попросту говоря, Scratchbox представляет собой «песочницу», в которой можно выполнять различные действия (в том числе в режиме эмуляции root), не затрагивая работу остальной системы. Что отличает Scratchbox от других «песочниц», так это среда разработчика, настроенная на кросс-компиляцию. Помимо x86, Scratchbox поддерживает ARM, а также, в экспериментальном режиме, PowerPC и некоторые другие архитектуры. Scratchbox включает насколько наборов разработчика [development kits, devkits], которые содержат все необходимое для сборки приложений той или иной платформы, так что программы, собранные в Scratchbox, могут сразу устанавливаться на соответствующие целевые устройства. Но это не все. Благодаря интеграции с Qemu, программы, собранные, например, для ARM, можно запускать для отладки и тестирования непосредственно на вашей локальной машине с процессором x86. При этом гостевая программа выполняется не в окне Qemu, а в хост-системе (разумеется, с ограничениями, наложенными «песочницей» Scratchbox). Scratchbox используется как стандартное средство разработки для платформ ARM Linux Internet Platform и Maemo.
Для знакомства со Scratchbox проще всего воспользоваться дистрибутивом, который распространяется вместе с Maemo SDK (и хотя сама Maemo, судя по всему, будет поглощена MeeGo, принципы кросс-платформенной разработки от этого вряд ли изменятся). Компания Nokia сделала все возможное для упрощения установки и настройки Scratchbox и Qemu, и даже распространяла готовые настроенные образы виртуальных машин. В результате мы получали эмулятор внутри эмулятора, который, благодаря производительности современных ПК, мог работать быстрее, чем целевое устройство. Виртуальная машина Qemu-ARM, выполняющаяся внутри виртуальной машины VMware, работающей в Windows... Глядя на такое, невольно задаешь себе вопрос, а не является ли вся наша Вселенная виртуальной машиной внутри какой-нибудь другой виртуальной машины? Если это так, то будем надеяться, что наша машина запрограммирована лучше, чем Qemu, и мы не вылетим на самом интересном месте из-за ошибки сегментации.
Пробуем в деле
Как бы там ни было, мы установим Maemo Scratchbox на живом компьютере, тем более что это не труднее, чем запустить виртуальную машину. Единственная сложность, с которой вы можете столкнуться, заключается в том, что эмулятор и инструментарий, поставляемый Nokia, рассчитаны на 32‑битные системы (установка на x64 в принципе возможна, но сопряжена с некоторыми трудностями). Подробная инструкция по установке Maemo SDK, в том числе и Scratchbox, доступна по адресу http://wiki.maemo.org/Documentation/Maemo5_Final_Installation. Сам Scratchbox устанавливается с помощью скрипта maemo-scratchbox-install_5.0.sh (доступ к нему можно получить, начав со страницы http://maemo.org/development/sdks/). Он устанавливает только среду Scratchbox, но не компоненты devkits, которые требуются для сборки приложений для ARM. Для их добавления нам понадобится скрипт maemo-sdk-install_5.0.sh, который можно загрузить с той же страницы. В процессе установки оба скрипта скачивают требуемые компоненты из Сети, так что позаботьтесь о доступе к Интернету. Скрипт maemo-scratchbox-install_5.0.sh следует выполнять в режиме root, тогда как скрипт maemo-sdk-install_5.0.sh – в режиме обычного пользователя. Для любителей графических интерфейсов есть также единый графический инсталлятор.
Помимо Maemo SDK, на ваш компьютер будут установлены несколько средств разработки для процессоров ARM и x86. Выберите пункт «Runtime Environment + All Dev Packages» в меню установки, в результате чего будут установлены все компоненты, необходимые для разработки ARM.
Далее будем считать, что Scratchbox установлен в директорию /scratchbox. После завершения установки скомандуйте:
sudo /scratchbox/sbin/sbox_adduser ваше_имя_пользователя
Выйдите из системы и войдите вновь, чтобы изменения вступили в силу. Сервер Scratchbox запускается командой
sudo /scratchbox/sbin/sbox_ctl start
Далее, скомандуйте
/scratchbox/login
И – ура! Мы попали в среду Scratchbox. Приглашение командой строки (рис. 1) содержит имя целевой архитектуры, для которой настроен Scratchbox. Чтобы выбрать другую целевую архитектуру и набор разработчика, нужно запустить утилиту sb-menu (рис. 2), что и советует сделать Scratchbox.
Помимо возможности выбора целевой архитектуры и наборов разработчика, утилита позволяет указать CPU Transparency – метод эмуляции целевого процессора. Мы выбираем qemu-arm-sb. Теперь программы, собранные для ARM, можно запускать из командной строки Scratchbox. Если вы забудете выставить метод эмуляции процессора, попытка запустить собранную программу в вашей системе приведет к выводу сообщения ‘SBOX_CPUTRANSPARENCY_METHOD not set’.
Давайте осмотримся по сторонам. К нашим услугам компилятор GCC, который собирает программы для ARM (при условии, что в окне sb-menu была выбрана именно эта платформа), отладчик Gdb, набор программ для работы с Perl, пакеты Automake/Autoconf, текстовый редактор Vi (если вы раньше пренебрегали изучением его команд, у вас появилась еще одна причина для того, чтобы, наконец, их выучить) и множество мелких вспомогательных программ. Помимо прочего, нам доступна и утилита apt-get, так что перечень установленных приложений можно расширить.
Если мы теперь скомпилируем и запустим программу helloworld.c (можно, я обойдусь без листинга?), то увидим то, что и ожидали. Даже не верится, что мы собрали программу для инородного процессора. Чтобы убедиться, что эмуляция ARM действительно работает, воспользуемся командой file. Ее вывод должен выглядеть примерно так:
a.out: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/ Linux 2.6.14, dynamically linked (uses shared libs), not stripped
Теперь можно вздохнуть с облегчением. Скомпилировав программу helloworld.c с ключом -S, мы получим код программы на ассемблере для ARM (рис. 3).
Среда Scratchbox позволяет нашим программам, собранным для ARM, получать доступ ко многим устройствам системы – например, к звуковым /scratchbox/dev/dsp и /scrachbox/dev/mixer. Если по умолчанию пользователь Scratchbox не имеет доступа к файлам этих устройств, его нужно открыть с помощью команд изменения прав доступа в хост-системе (fakeroot внутри самого Scratchbox нам тут не поможет).
Набор доступных библиотек зависит от выбранных devkit’ов. К нашим услугам наборы debian-etch, debian-lenny, debian-sarge, apt-https, doctools, git, perl, qemu и svn. Как вы уже поняли, пакеты можно комбинировать (это делается в программе sb-menu), в результате чего в систему устанавливаются соответствующие библиотеки и программы. Я использовал набор debian-lenny+qemu. В этом варианте, помимо стандартной библиотеки времени выполнения, можно использовать ncurses и X11.
Scratchbox позволяет тестировать и отлаживать графические приложения (и было бы странно, если бы не позволял, учитывая, что консоль, мягко говоря, не очень популярна на мобильных устройствах). Чтобы работать с Scratchbox и Maemo SDK безо всяких проблем, мы установим X-сервер Xephyr (он наверняка есть в репозиториях вашего дистрибутива). Xephyr можно запустить командой
Xephyr :2 -host-cursor -screen 800x480x16 -dpi 96 -ac -kb &
Командовать следует за пределами Scratchbox. Мы запустили Xephyr на втором дисплее. Перейдем теперь в Scratchbox и присвоим переменной окружения DISPLAY значение :2.0:
export DISPLAY=:2.0
Теперь из командной строки Scratchbox можно запускать графические программы (рис. 4).
Scratchbox сам по себе
Если вы не хотите пользоваться системой Scratchbox в составе Maemo SDK, можете установить ее самостоятельно. С сайта проекта (http://www.scratchbox.org) можно загрузить исходные тексты Scratchbox и наборов разработчика и готовые пакеты Debian.
Сложности способны возникнуть при настройке Scratchbox. Пакет scratchbox имееся в двух вариантах: старый scratchbox 1.x и новый scratchbox 2, который разрабатывается при поддержке Nokia. Мы рассмотрим настройку scratchbox 2. Перед этим, помимо самого пакета, нужно установить Qemu и систему сборки для ARM. В качестве последней мы используем инструментарий CodeSourcery для процессоров ARM, о котором будет сказано ниже.
Прежде всего, нужно вызвать утилиту sb2-init:
sb2-init -c /usr/bin/qemu-arm armv7 /usr/local/arm-2008q3/bin/arm-none-linux-gnueabi-gcc
Здесь armv7 – целевая архитектура процессора. Утилиту sb2‑init следует вызывать из директории, которая будет корневым каталогом «песочницы» Scratchbox. Для изменения параметров уже настроенной системы можно воспользоваться утилитой sb2‑config. Например, вызов
sb2-config -d armvt
заменяет целевую архитектуру. Теперь командуем
sb2 -R
и оказываемся в «песочнице» Scratchbox. В данном случае sb2 работает в режиме оболочки. Далее все происходит так, как в обычной Linux-системе. Программу sb2 можно вызывать и в режиме командной строки, например:
sb2 ./configure --prefix=/usr/local/arm-2008q3/sb2 make
и так далее.
Отладка приложений может выполняться на хост-компьютере с использованием специальной версии отладчика Gdb, адаптированной для работы с Qemu. Как и в случае Maemo SDK, отладка выполняется в удаленном режиме. Сначала с помощью команды sb2‑qemu-gdbserver-prepare мы запускаем сервер отладки совместно с эмулятором, затем – клиент отладчика, адаптированный к работе с ARM, в нашем случае – тот, который входит в поставку CodeSourcery.
Сложности кросс-платформенной сборки
Для переноса программы с одной платформы на другую недостаточно сгенерировать машинный код целевого процессора. Программа должна быть скомпонована с библиотеками, которые обслуживают ее работу в целевой системе (а они зависят не только от архитектуры системы, но и от версии используемой ОС). Например, библиотека glibc, которую использует приложение, может оказаться несовместима с версией ядра.
Наборы Scratchbox Devkits содержат, помимо прочего, версии библиотек, скомпилированных на целевых платформах для целевых систем, так что при сборке на ПК программа сразу компонуется «правильно». Несколько готовых наборов входят в поставку Scratchbox, а на сайте проекта (http://www.scratchbox.org) можно найти инструкцию по созданию новых наборов. Фрагмент файловой системы, содержащий минимальный набор файлов среды времени выполнения, необходимых для запуска программы, часто именуется sysroot. Так же называется переменная, содержащая путь к корню целевой файловой системы и еще некоторые вещи, но когда программа установки спрашивает вас, нужно ли установить sysroot, знайте: вам всего лишь предлагают установить среду времени выполнения.
Где же наши файлы?
Scratchbox – многопользовательская система. Если корневая директория Scratchbox имеет имя /scratchbox, то настройки пользователя user_name хранятся в директории /scratchbox/users/user_name, а его домашней директорией в среде Scratchbox будет /scratchbox/users/user_name/home/user_name.
Отладка в Scratchbox
Работая в Scratchbox с программами, предназначенными для ARM, нетрудно забыть о том, что на самом деле у нас процессор x86. Однако, когда мы приступаем к отладке приложения, ограничения эмуляции напоминают нам об этом: мы не можем отлаживать программу, предназначенную для ARM, из командной строки. Нам придется сначала запустить сервер Qemu в режиме отладки (напомню, что в Qemu встроен отладчик), а затем подключиться к этому серверу с помощью программы Gdb, как к удаленной машине. Допустим, у нас есть программа hello, скомпилированная для платформы ARM с ключом -g (то есть с отладочной информацией). В этом случае сервер запускается из командной строки Scratchbox:
qemu-arm-sb -g 1212 hello
Здесь 1212 – номер порта, по которому клиент отладки соединяется с сервером, а hello – имя исполнимого файла отлаживаемой программы. Теперь в окне терминала Scratchbox мы запускаем программу gdb (или gdbtui).
В командной строке отладчика вводим следующие команды:
(gdb) file hello (gdb) target remote :1212
Поскольку сервер отладки выполняется на той же машине, что и клиент, мы указываем только порт, но не адрес. В результате программа загружена и готова к дальнейшей отладке, которая аналогична процессу отладки локального файла (рис. 5).
GNU ARM
Проект GNU ARM (http://www.gnuarm.com) предоставляет нам стандартный набор инструментов GNU для разработки программ под ARM-процессор (его можно использовать и в составе пакета разработчика для Scratchbox). Если вы не хотите тратить время на установку Scratchbox, GNU ARM – ваш выбор. Для установки GNU ARM достаточно распаковать архив двоичных файлов, причем доступных не только для Linux x86, но и под Cygwin и Mac OS. В результате сборки программы в GNU ARM вы получите статически скомпонованный 32‑битный файл в формате ELF, так что его можно выполнить на любой системе Linux для ARM. Если к инструментам GNU ARM мы добавим в набор отладчик Gdb и эмулятор Qemu, то получим аналог Scratchbox для работы из-под Windows или Mac, хотя использовать Scratchbox все же удобнее: многие утилиты, предназначенные специально для Linux, не смогут работать в чужих системах.
В качестве стандартной библиотеки времени выполнения в GNU ARM используется Newlib, разрабатываемая Red Hat. Статическое связывание программы с библиотекой времени выполнения является одним из требований стандарта EABI (Embedded Application Binary Interface), двоичного интерфейса для встроенных систем, на котором основан GNU ARM. Следование стандарту обеспечивает двоичную совместимость между программными компонентами, собранными с использованием различных систем разработки. Особенности стандарта ориентированы на приложения, работающие на «голом железе», то есть без всякой операционной системы. Так, EABI поощряет (а иногда и делает обязательным) статическое связывание приложения с библиотеками и допускает наличие в коде привилегированных инструкций, которыми обычно пользуется только ядро ОС. По этой причине приложения EABI не всегда могут работать в Linux, хотя новейшие ARM-дистрибутивы от Debian сами основаны на EABI.
Sourcery G++
Пакет Sourcery G++ (http://www.codesourcery.com) представляет собой средство кросс-платформенной сборки приложений на основе инструментария GNU, интегрированной среды Eclipse и нескольких инструментов, добавленных разработчиками пакета. Оно существует в вариантах для Linux и Windows (последний, естественно, на основе MinGW). В отличие от всего рассмотренного выше, Sourcery G++ не бесплатен; тем не менее, можно взять бесплатную пробную версию и сравнить возможности Sourcery G++ с некоммерческими конкурентами. Среди многочисленных платформ, которые поддерживает Sourcery G++, есть и ARM GNU/Linux (полноценный Linux на процессоре ARM). Эту версию Sourcery G++ можно использовать, в том числе, и для сборки ядра Linux. Версия для платформы ARM EABI позволяет собирать программы для работы на «голом железе». Эта версия содержит свой собственный эмулятор ARM, который можно использовать и для отладки.
В качестве сервера отладчика в Sourcery G++ используется программа gdbserver, которая должна быть установлена на целевой платформе. Взаимодействие между локальным отладчиком GDB и сервером отладки происходит так же, как было описано выше для Scratchbox. С помощью своего собственного скрипта отладки можно научить Sourcery G++ использовать сервер отладки из Qemu, или сервер OpenOCD для встраиваемых устройств. Собственно, сами разработчики Sourcery G++ не скрывают, что основная их заслуга – сборка и наладка пакетов, доступных всем в виде исходников. Ричард Столлмен должен одобрять такую модель!
Самое интересное в пакете для нас, пожалуй, это новые версии ориентированных на ARM инструментов GNU (для сравнения, GNU ARM «замер» на уровне 2006 года). Поскольку это инструменты GNU, вы можете копировать и использовать их в любых проектах, не вступая в конфликт со своей совестью (если она вообще что-то говорит вам по поводу копирования программ). К этому стоит добавить библиотеку glibc, собранную с использованием заголовочных файлов из более новых версий ядер.
SDK, созданные производителями мобильных устройств, обычно скрывают от пользователя детали работы платформы. Тем не менее, знание этих деталей не только развивает мысль, но и (возможно) позволит вам достичь уровня легендарного программиста Мела.
Ценителям красивого ассемблера
Как известно, настоящие программисты пишут программы ради красоты. Самые же настоящие – ради той красоты, которую можно увидеть только в дизассемблере (http://rixstep.com/2/2/20071015,01.shtml – классический пример). Посмотрите на простую реализацию функции sign() на языке C:
int sign(int x) { if (x > 0) return 1; if (x < 0) return -1; return 0; }
Сколько переходов в ассемблерном эквиваленте этой функции? Если вы компилируете функцию с помощью GCC для ARM с включенным флагом -O3, ответ будет «ни одного»:
cmp r0, #0 mov r0, #1 movgt pc, lr mvn r0, #0 movge r0, #0 mov pc, lr
Первая строчка кода сравнивает содержимое регистра r0 (передающего аргумент функции) с нулем. Заметьте суффиксы (в системе команд ARM – скорее префиксы) условного выполнения при командах mov, манипуляции с регистрами PC (адрес следующей выполняемой инструкции) и LR (адрес возврата) для выхода из функции. Однако вариант
int sign(int x) { return (x > 0) - (x < 0); }
произведет код на одну инструкцию короче (впрочем, насчет выигрыша по времени я не уверен).