Кросс-компиляция под Linux

Введение

Что же у нас есть для кросс-компиляции? Если не считать коммерческих продуктов и мелких поделок, то для того, чтобы скомпилировать любой проект под любую платформу, понадобится Gnu Compiler Collection, или, кратко, GCC. GCC — это один большой набор исходников, но собирать из него кросс-компилятор на каждую новую целевую платформу придётся отдельно.

Надо сказать, список целевых платформ довольно внушителен.

Вообще, для того, чтобы работать с GGC надо собрать т. н. Toolchain, набор утилит для компиляции. В toolchain входит помимно GCC, ещё Binutils, предназначенные для манипуляций с объектными и бинарными файлами. Для голого железа (если планируется работать не под ОС на целевой платформы, весьма полезной будет также NewLib — сборник стандартных процедур.

Binutils

В Binutils входят:

addr2line
Утилита определения места в исходнике по адресу.
ar
Утилита работы с объектными архивами.
c++filt
Дешифратор имён перегруженных функций и методов для языков C++ и Java.
dlltool
Генератор файлов для сборки и использования DLL.
gprof
Профилировщик.
libtool
Библиотекарь — утилита для работы с динамическими и статическими библиотеками.
nlmconv
Конвертер объектных файлов в NLM.
nm
Генератор списка символов.
objcopy
Копировщик и преобразователь объектных файлов.
objdump
Утилита вывода информации по объектным файлам.
ranlib
Утилита индексирования объектных архивов.
readelf
Утилита вывода информации по ELF-файлам.
size
Измеритель размера секций и программ в целом.
strings
Извлекатель символьных строк из объектных файлов.
strip
Утилита для отфильтровывания символических имён, отладочной информации из бинарных файлов.
windmc
Компилятор файлов сообщений для Windows.
windres
Компилятор ресурсов Windows.

GCC

В составе GCC большой набор разнообразных инструментов, однако, скорее всего иметь дело придётся с frontend, который так и называется, gcc. Он сам определяет тип исходного файла и вызывает соответствующий компилятор, а также, по необходимости, линковщик или библиотекарь.

NewLib

NewLib — специальная подборка стандартных функций для встраиваемых систем. Она включает в себя libc (функци работы со строками, файлами и т. д.), libm (разнообразные математические функции). Также она обладает широкими возможностями конфигурирования под разнообразные требования.

Надо сказать, NewLib далеко не единственный выбор. В принципе, если не пользоваться библиотечными функциями, можно вообще без библиотек обойтись, но этот путь сложен и тернист — стандарт си не требует наличия их в т. н. standalone environment1). Вполне возможно, есть другие подходящие варианты

GDB

GNU Debugger — стандартное средство отладки программ, и, в принципе, необязательно. Возможно, вы предпочтёте графический отладчик или вовсе пользуетесь исключительно printf-style-debug2).

Сборка Toolchain

Также стоит определить путь, куда будет всё установлено. В терминах GCC это называется prefix. По умолчанию этот путь — /usr/local. Однако по ряду различных причин иногда стоит специально указать другой. Первая причина — поставить в собственную домашнюю директорию, например, если нет root-полномочий на машине или просто его поставить только для себя (впрочем, лучше так не делать). Другая причина — бывает нужда с специальных вариантах сборки, и тогда это стоит делать, чтобы не спутать такую сборку с обычной. Стоит отметить, что компиляторы под различные платформы не перепутываются, так как имеют различные имена: gcc для ARM, например, будет именоваться arm-elf-gcc3) или arm-linux-gcc, и именно его придётся указывать при компиляции (либо указывать target, тогда gcc сам вызовет нужный). Если же оставить путь по-умолчанию, сборка попадёт в стандартный путь поиска исполняемых файлов — /usr/local/bin, и может вызываться без специального указания пути или модификации $path.

Для указания prefix у configure есть соответствующая опция: --prefix=…

Порядок сборки Toolchain

Сборка тулчейна в описанной конфигурации состоит из следующих этапов:

  1. подготовка пространства для сборки, скачивание и распаковка исходников и т. п.;
  2. сборка и установка Binutils;
  3. сборка и установка предварительного варианта GCC для сборки NewLib;
  4. сборка и установка NewLib;
  5. сборка и установка окончательного варианта GCC (с поддержкой NewLib).

Необходимые приготовления

Прежде всего нужно сделать себе „сборочную площадку“ для тулчейна. Пусть это будет директория. ~/toolchain. Создадим её и перейдём туда:

mkdir ~/toolchain
cd ~/toolchain

Для инсталляции требуются свежие исходники.

  • Binutils берётся с http://ftp.gnu.org/gnu/binutils/, файл типа binutils-n.n.n.tar.gz (n.n.n — версия, последняя на момент написания — 2.20.1)
  • GCC качается с сайта http://gcc.gnu.org/mirrors.html, нужен файл типа gcc-n.n.n.tar.bz2 (последний на момент написания — 4.3.5).
  • Newlib качается с сайта ftp://sources.redhat.com/pub/newlib/index.html, нужен файл типа 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

Для сборки тулчейна также необходимы дополнительные пакеты:

build-essential
Набор средств для сборки пакетов Debian, нужен, так как включает в себя всё необходимое для компиляции.
texinfo
Cредства подготовки документации в формате texinfo. Вроде бы, опциональный пакет, судя по тому, что выдаётся только предупреждение о его желательности, но компиляция binutils прерывается.
sudo aptitude install build-essential texinfo libgmp3-dev libmpfr-dev libmpc-dev

Если какого-либо из этих пакетов, то сборка тулчейна прерывается с какой-нибудь ошибкой, причём из-за чего «лыжи не едут», бывает неочевидным. 4)

Binutils

Для сборки 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

Что значат эти опции:

–target=arm-elf
Наша целевая платформа
–enable-interwork
Специфичная для ARM опция, обеспецивающая взаимодействие режимов ARM и THUMB.
–enable-multilib
Также специфичная для ARM опция, необходимая для работы в нескольких режимах (LE, BE).
–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 ..

Предварительная сборка GCC

Так же, как и в случае с 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)

–enable-multilib
Всё то же, однако утверждают, что эта опция включена по умолчанию6), так что её указывать не нужно, более того, обработка этой опции сломана в некоторых версиях GCC (4.5.1 например).
–enable-languages="c"
Для сборки NewLib ничего не нужно, кроме компилятора си.
–with-newlib
Хитрая опция совместимости с NewLib. Что она делает, читайте в документации к GCC, но делает она совсем немного.
–without-headers
Отключает установку стандартных хедеров, для сборки NewLib они не требуются.
–disable-shared
Отключает поддержку динамических библиотек, на встраиваемой системе оно и не нужно.
–with-float=soft
Способ работы с числами с плавающей запятой — если нет FPU, ставится эта опция.
make all-gcc
make install-gcc
cd ..

Сборка NewLib

Сборка 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 ..

Окончательная сборка GCC

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

Multilib

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

Возможные проблемы и решения

  • Если сборка binutils или gcc обрывается странными ошибками компиляции, может помочь опция --disable-werror.
  • С libssp иногда не собирается gcc. К configure можно добавить ключ –disable-libssp.

Полезные советы

  • Про сборке (make) сообщение «configure: error: cannot compute suffix of object files: cannot compile» может говорить о том, что используются несовместимые опции, например в конфигурации Multilib (см. выше). Файл config.log при этом приходится искать в поддиректориях (можно использовать find, поиск в mc по указанному сообщению).
  • В GCC есть поддержка дробной арифметики с фиксированной запятой согласно TR 18037: Embedded C, которая включается опцией конфигурации --enable-fixed-point (и выключается соответстветственно --disable-fixed-point), однако она сделана только для платформы MIPS.

Рабочие конфигурации

ARM-EABI

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

Правильность компиляции пока не проверил.

Ссылки

1) Так в стандарте называют платформу без полноценной операционной системы, в противовес hosted.
2) Отладка в стиле printf — когда в программу вставляется куча вывода функцией printf для контроля данных и последовательности исполнения
3) в новых весиях GCC это будет arm-none-eabi, а arm-elf-* даже не скомпилируется
7) Пока не написал. Обратитесь к оригинальному руководству или слёзно умоляйте автора:-]
cifra/kross-kompiljacija.txt · Последние изменения: 2012/04/16 17:10 — vovanium
За исключением случаев, когда указано иное, содержимое этой вики предоставляется на условиях следующей лицензии: CC Attribution 3.0 Unported