Что же у нас есть для кросс-компиляции? Если не считать коммерческих продуктов и мелких поделок, то для того, чтобы скомпилировать любой проект под любую платформу, понадобится Gnu Compiler Collection, или, кратко, GCC. GCC — это один большой набор исходников, но собирать из него кросс-компилятор на каждую новую целевую платформу придётся отдельно.
Надо сказать, список целевых платформ довольно внушителен.
Вообще, для того, чтобы работать с GGC надо собрать т. н. Toolchain, набор утилит для компиляции. В toolchain входит помимно GCC, ещё Binutils, предназначенные для манипуляций с объектными и бинарными файлами. Для голого железа (если планируется работать не под ОС на целевой платформы, весьма полезной будет также NewLib — сборник стандартных процедур.
В Binutils входят:
В составе GCC большой набор разнообразных инструментов, однако, скорее всего иметь дело придётся с frontend, который так и называется, gcc. Он сам определяет тип исходного файла и вызывает соответствующий компилятор, а также, по необходимости, линковщик или библиотекарь.
NewLib — специальная подборка стандартных функций для встраиваемых систем. Она включает в себя libc (функци работы со строками, файлами и т. д.), libm (разнообразные математические функции). Также она обладает широкими возможностями конфигурирования под разнообразные требования.
Надо сказать, NewLib далеко не единственный выбор. В принципе, если не пользоваться библиотечными функциями, можно вообще без библиотек обойтись, но этот путь сложен и тернист — стандарт си не требует наличия их в т. н. standalone environment1). Вполне возможно, есть другие подходящие варианты
GNU Debugger — стандартное средство отладки программ, и, в принципе, необязательно. Возможно, вы предпочтёте графический отладчик или вовсе пользуетесь исключительно printf-style-debug2).
Также стоит определить путь, куда будет всё установлено. В терминах GCC это называется prefix. По умолчанию этот путь — /usr/local
. Однако по ряду различных причин иногда стоит специально указать другой. Первая причина — поставить в собственную домашнюю директорию, например, если нет root-полномочий на машине или просто его поставить только для себя (впрочем, лучше так не делать). Другая причина — бывает нужда с специальных вариантах сборки, и тогда это стоит делать, чтобы не спутать такую сборку с обычной. Стоит отметить, что компиляторы под различные платформы не перепутываются, так как имеют различные имена: gcc
для ARM, например, будет именоваться arm-elf-gcc
3) или arm-linux-gcc
, и именно его придётся указывать при компиляции (либо указывать target, тогда gcc сам вызовет нужный). Если же оставить путь по-умолчанию, сборка попадёт в стандартный путь поиска исполняемых файлов — /usr/local/bin
, и может вызываться без специального указания пути или модификации $path
.
Для указания prefix у configure есть соответствующая опция: -
-prefix=…
Сборка тулчейна в описанной конфигурации состоит из следующих этапов:
Прежде всего нужно сделать себе „сборочную площадку“ для тулчейна. Пусть это будет директория. ~/toolchain
. Создадим её и перейдём туда:
mkdir ~/toolchain cd ~/toolchain
Для инсталляции требуются свежие исходники.
binutils-n.n.n.tar.gz
(n.n.n — версия, последняя на момент написания — 2.20.1)
gcc-n.n.n.tar.bz2
(последний на момент написания — 4.3.5).
newlib-n.n.n.tar.gz
(последний на момент написания – 1.18.0)
Маленькое замечание: в качестве последней версии GCC указана 4.3.5, несмотря на наличие 4.5.1. Дело в том, что это две параллельных ветки компилятора, однако 4.5.1 при этом мне собрать не удалось — возникала ошибка configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES.
В дальнейшем в качестве примеров я буду приводить данные версии и целевую платформу arm-elf
, так как собирал именно их. Полагаю, описание также подойдёт и к другим версиям и платформам. Сборка проивзводилась на дистрибутиве Ubuntu 10.04 LTS, поэтому замечания, касающиеся дополнительных бинарных пакетов, будут касаться именно его. однако, думаю, нет никаких сложностей найти аналогичные пакеты для любого другого.
Распаковка сходников проста и элементарна для любого знакомого с командной строкой Linux:
tar xaf binutils-2.20.1.tar.gz tar xaf gcc-4.3.5.tar.bz2 tar xaf newlib-1.18.0.tar.gz
Для сборки тулчейна также необходимы дополнительные пакеты:
sudo aptitude install build-essential texinfo libgmp3-dev libmpfr-dev libmpc-dev
Если какого-либо из этих пакетов, то сборка тулчейна прерывается с какой-нибудь ошибкой, причём из-за чего «лыжи не едут», бывает неочевидным. 4)
Для сборки Binutils необходима отдельная пустая директория. И всё следует делать находясь в ней. Стандартную подготовку можно сделать так:
mkdir build-binutils cd build-binutils
Затем необходимо запустить скрипт конфигурации:
../binutils-2.20.1/configure --target=arm-elf --enable-interwork --enable-multilib \ --with-gnu-as --with-gnu-ld --disable-nls
Что значат эти опции:
Надо сказать, я сначала по ошибке скачал версию 2.9.1, и она отказалась собираться — configure выдавал ошибку под предлогом BFD does not support target arm-unknown-elf
.
После этого происходит собственно сборка:
make
Впрочем, для ускорения можно указать опцию make -j n
, где n — число потоков, в которых будет производиться сборка. Это ускорит сборку на многопроцессорных машинах, правда несколько сложнее будет разобрать вывод на экране в случае ошибки сборки.
Затем установка в систему:
sudo make install
(sudo
— команда, запускающая команду с правами root, если в вашей системе другой способ получения прав, используйте его).
Если префикс сохранён по умолчанию, можно убедиться, что команды доступны из консоли — если набрать arm-elf-
и нажать Tab, шелл предложит на выбор команды из пакета — arm-elf-ar, arm-elf-ld и т. д.
Теперь стоит не забыть покинуть директорию сборки
cd ..
Так же, как и в случае с Binutils, процесс сборки GCC стоит проивзводить в отдельной директории
mkdir build-pre-gcc cd build-pre-gcc ../gcc-4.3.5/configure --target=arm-elf --enable-interwork --enable-multilib \ --enable-languages="c" --with-newlib --without-headers --disable-shared --with-gnu-ld \ --with-gnu-as --with-float=soft --disable-nls
Снова стоит разобрать опции конфигурации: 5)
make all-gcc make install-gcc cd ..
Сборка NewLib начинается подобным одбразом:
mkdir build-newlib cd build-newlib
А дальше следует заметить, что у NewLib огромное количество конфигурационных параметров. О них подробно можно почитать в статье «konfiguracija_newlib».
../newlib-1.18.0/configure --target=arm-elf --enable-interwork --enable-multilib \ --with-gnu-as --with-gnu-ld --disable-nls --disable-newlib-supplied-syscalls --enable-newlib-mb \ --enable-newlib-io-c99-formats --enable-newlib-io-long-long --enable-newlib-io-pos-args \ --enable-newlib-multithread
Сборка:
make sudo make install cd ..
mkdir build-gcc cd build-gcc ../gcc-4.3.5/configure --target=arm-elf --enable-interwork --enable-multilib \ --enable-languages="c,c++" --with-newlib --disable-shared --with-gnu-ld \ --with-gnu-as --with-float=soft --disable-nls
make sudo make install cd ..
ARM отличается разнообразием вариантов исполнения, подчас несовместимых с собой — little / big endian, наборами инструкций ARM, Thumb, Thumb2, JAVA и т. д, без или с блоком плавающей арифметики и т. д. Если только вы не собираетесь всегда работать с одним и тем же чипом, вам понадобится держать по крайней мере несколько вариантов библиотек. Так что здесь как нигде полезна будет опция Multilib.
При сборке GCC обязательно укажите -
-enable-multilib
, а также набор необходимых вариантов7).
Multilib конфигурируется в файле gcc-n.n.n/gcc/config/arm/t-arm-elf
из архива исходников. В нём следует раскомментировать соответствующие нужным опциям строки (убрав решётку и пробел в начале).
Архитектура ARMv7 (Cortex, набор инструкций Thumb2):
MULTILIB_OPTIONS += march=armv7 MULTILIB_DIRNAMES += thumb2 MULTILIB_EXCEPTIONS += march=armv7* marm/*march=armv7* MULTILIB_MATCHES += march?armv7=march?armv7-a MULTILIB_MATCHES += march?armv7=march?armv7-r MULTILIB_MATCHES += march?armv7=march?armv7-m MULTILIB_MATCHES += march?armv7=mcpu?cortex-a8 MULTILIB_MATCHES += march?armv7=mcpu?cortex-r4 MULTILIB_MATCHES += march?armv7=mcpu?cortex-m3
Способы передачи чисел с плавающей запятой:
MULTILIB_OPTIONS += mfloat-abi=hard MULTILIB_DIRNAMES += fpu MULTILIB_EXCEPTIONS += *mthumb/*mfloat-abi=hard* MULTILIB_EXCEPTIONS += *mcpu=fa526/*mfloat-abi=hard* MULTILIB_EXCEPTIONS += *mcpu=fa626/*mfloat-abi=hard*
Разный порядок байтов:
MULTILIB_OPTIONS += mlittle-endian/mbig-endian MULTILIB_DIRNAMES += le be MULTILIB_MATCHES += mbig-endian=mbe mlittle-endian=mle
С и без блока плавающей арифметики:
MULTILIB_OPTIONS += mhard-float/msoft-float MULTILIB_DIRNAMES += fpu soft MULTILIB_EXCEPTIONS += *mthumb/*mhard-float*
Поддержка Cortex (armv7) конфликтует с поддержкой hard-float (make
возвращает «configure: error: cannot compute suffix of object files: cannot compile»), видимо требуется добавить некоторые исключения, но понять, какие, мне не удалось. Так что либо FPU, либо Cortex, либо ковырять дальше.
Строки, касающиеся поддержки разных ABI нужны, если их действительно нужно использовать.
Версии, поддерживающие и не поддерживающие перекрёстные вызовы (режимы ARM/Thumb):
MULTILIB_OPTIONS += mno-thumb-interwork/mthumb-interwork MULTILIB_DIRNAMES += normal interwork
Разные способы именования:
MULTILIB_OPTIONS += fno-leading-underscore/fleading-underscore MULTILIB_DIRNAMES += elf under
Строки, касающиеся отдельных чипов, старых архитектур обычно можно не раскомментировать.
Чипы Faraday Tech:
MULTILIB_OPTIONS += mcpu=fa526/mcpu=fa626/mcpu=fa606te/mcpu=fa626te/mcpu=fmp626/mcpu=fa726te MULTILIB_DIRNAMES += fa526 fa626 fa606te fa626te fmp626 fa726te MULTILIB_EXCEPTIONS += *mthumb*/*mcpu=fa526 *mthumb*/*mcpu=fa626
Чипы Cirrus Logic
MULTILIB_OPTIONS += mcpu=ep9312 MULTILIB_DIRNAMES += ep9312 MULTILIB_EXCEPTIONS += *mthumb/*mcpu=ep9312*
ARMv3 и более ранние:
MULTILIB_OPTIONS += mcpu=arm7 MULTILIB_DIRNAMES += nofmult MULTILIB_EXCEPTIONS += *mthumb*/*mcpu=arm7* MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7d MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7di MULTILIB_MATCHES += mcpu?arm7=mcpu?arm70 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm700 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm700i MULTILIB_MATCHES += mcpu?arm7=mcpu?arm710 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm710c MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7100 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7500 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7500fe MULTILIB_MATCHES += mcpu?arm7=mcpu?arm6 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm60 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm600 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm610 MULTILIB_MATCHES += mcpu?arm7=mcpu?arm620
-
-disable-werror
.
configure
можно добавить ключ –disable-libssp
.
make
) сообщение «configure: error: cannot compute suffix of object files: cannot compile» может говорить о том, что используются несовместимые опции, например в конфигурации Multilib (см. выше). Файл config.log при этом приходится искать в поддиректориях (можно использовать find
, поиск в mc
по указанному сообщению).
-
-enable-fixed-point
(и выключается соответстветственно -
-disable-fixed-point
), однако она сделана только для платформы MIPS.
binutils-2.22
Опции:
--target=arm-x-eabi --enable-interwork --enable-multilib \ --with-gnu-as --with-gnu-ld --disable-nls
gcc-4.6.3
Раскомментированы строки в файле gcc/config/t-arm-elf:
MULTILIB_OPTIONS += march=armv7 MULTILIB_DIRNAMES += thumb2 MULTILIB_EXCEPTIONS += march=armv7* marm/*march=armv7* MULTILIB_MATCHES += march?armv7=march?armv7-a MULTILIB_MATCHES += march?armv7=march?armv7-r MULTILIB_MATCHES += march?armv7=march?armv7-m MULTILIB_MATCHES += march?armv7=mcpu?cortex-a8 MULTILIB_MATCHES += march?armv7=mcpu?cortex-r4 MULTILIB_MATCHES += march?armv7=mcpu?cortex-m3 ... MULTILIB_OPTIONS += mlittle-endian/mbig-endian MULTILIB_DIRNAMES += le be MULTILIB_MATCHES += mbig-endian=mbe mlittle-endian=mle
Опции:
--target=arm-x-eabi --enable-interwork --enable-languages="c,c++" \ --with-newlib --without-headers --disable-shared --with-gnu-ld --with-gnu-as \ --disable-nls --disable-libssp --disable-libada --enable-lto --with-system-zlib
newlib-1.20.0
Опции:
--target=arm-x-eabi --enable-interwork --enable-multilib --with-gnu-as \ --with-gnu-ld --disable-nls --disable-newlib-supplied-syscalls \ --enable-newlib-mb --enable-newlib-io-c99-formats --enable-newlib-io-long-long
Правильность компиляции пока не проверил.