- Кросс-компиляция в OS X под Linux используя crosstool-ng
- Disclaimer
- Подготовка
- Настройка crosstool-ng
- Сборка toolchain
- Заключение
- Кросс-компилятор⚓︎
- Применение кросс-компиляторов⚓︎
- Канадский крест⚓︎
- Кросс-компиляция с GCC⚓︎
- Кросс-компиляция под Linux
- Binutils
- GCC
- NewLib
- GDB
- Сборка Toolchain
- Порядок сборки Toolchain
Кросс-компиляция в OS X под Linux используя crosstool-ng
В данной заметке речь пойдёт о замечательном средстве автоматизации сборки кросс-тулчейнов crosstool-ng, практически незаменимого инструмента для любого уважающего себя embedded-разработчика. Если вам приходилось по-серьёзному собирать софт из x86-linux под arm-linux , то вы наверняка слышали о нём.
В данном руководстве рассматривается не столько кросс-компиляция по архитектуре, сколько кросс-компиляция по системе — сборка под Linux в Darwin.
Disclaimer
В интернете есть несколько статей по сборке crosstool-ng под OS X, например на benmont.com и в официальном руководстве. Тем не менее, в некоторых статьях встречается множество ошибок и устаревших сведений, а в других описываются лишь общие черты. Здесь будет описан мой путь, по которому я успешно собрал toolchain в июле 2013.
Подготовка
Эта часть зависит от того, какой пакетный менеджер вы используете в OS X — MacPorts или Homebrew. Я для себя давно выбрал ports-way, так что буду писать исходя из этого.
1. Регистрозависимая файловая система
Тут всё просто, в OS X есть утилита Disk Utility , воспользуемся ей для создания нового раздела. Потребуется 5+ Гб.
2. Инструменты
Предполагается, что у вас установлен MacPorts. Установим следующие пакеты:
ncurses lzma libtool binutils gsed gawk grep gcc48
Проверим, какие версии gcc есть в системе: sudo port select —list gcc . Нам нужна mp-gcc48 — выбираем по-умолчанию командой sudo port select —set gcc mp-gcc48 .
3. Установка crosstool-ng
Собирать сам инструментарий достаточно просто, воспользуемся официальной инструкцией:
hg clone http://crosstool-ng.org/hg/crosstool-ng cd crosstool-ng ./bootstrap
./configure \ --with-objcopy=/opt/local/bin/gobjcopy \ --with-objdump=/opt/local/bin/gobjdump \ --with-readelf=/opt/local/bin/greadelf \ --with-sed=/opt/local/bin/gsed \ --with-libtool=/opt/local/bin/glibtool \ --with-grep=/opt/local/bin/grep \ --with-install=/opt/local/bin/ginstall make sudo make install
Это установит ct-ng в /usr/local/bin . Домашняя директория ct-ng: /usr/local/lib/ct-ng.hg+default-2685dfa9de14 в зависимости от ревизии. В этой директории отредактируем файл scripts/functions , заменив строчку для Darwin строчкой от Linux:
--- scripts/functions.orig 2013-07-09 22:15:12.000000000 +0400 +++ scripts/functions 2013-07-06 04:28:41.000000000 +0400 @@ -460,7 +460,7 @@ mode="$(stat -c '%a' "$(dirname "$")")" ;; Darwin|*BSD) - mode="$(stat -f '%Lp' "$(dirname "$")")" + mode="$(stat -c '%a' "$(dirname "$")")" ;; *) CT_Abort "Unhandled host OS $CT_SYS_OS"
Это потому, что ct-ng случайно хавает версию gstat из GNU-набора, вместо оригинального stat из OS X. Полюбуйтесь красотой и изящностью здешнего кода и закройте файл.
Можете также скопировать скрипт ct-ng.comp для bash-completion , работает хорошо.
Теперь нужно выбрать временную папку, в которой будут коваться наш замечательный cross-toolchain и его sysroot. У меня это /Volumes/Unixen/ct-config , перейдите в вашу папку и начнём настройку.
Настройка crosstool-ng
Прежде чем начать настройку, унаследуем конфигурацию от шаблона. Нас интересует x86_64-unknown-linux-gnu :
cd /Volumes/Unixen/ct-config ct-ng x86_64-unknown-linux-gnu ct-ng menuconfig
После этого вы видите меню, в котором мы будем настраивать наш инструментарий.
1. Paths and misc options
Здесь важно указать опции Local tarballs directory ( /Volumes/Unixen/src ) и Prefix directory ( /Volumes/Unixen/$
2. C compiler
Здесь я отключил поддержку Java и Fortran, потому что не знаю, как поведёт себя GCC при сборке с включёнными фичами. Обязательно отключаем [ ] Link libstdc++ statically into the gcc binary , иначе будет ошибка
collect2: error: ld returned 1 exit status ld: library not found for -lcrt0.o
3. Debug facilities
Здесь придётся отключить поддержку dmalloc и ltrace , так как иначе будут нерешаемые проблемы. В разделе gdb следует отключить [ ] Native gdb и, если нет необходимости, отключить [*] Enable python scripting (проблема с python, но решение будет ниже). Я использую версию gdb version (7.3.1) .
4. Companion libraries
Здесь строго следующие версии библиотек, иначе будут ошибки компиляции и autotools, эти версии подбирал методом тыка, зачастую помогал выбор более свежей.
* GMP version (5.0.2) * MPFR version (3.1.2) * PPL version (0.11.2) * CLooG version (0.15.11) * MPC version (1.0.1)
Сборка toolchain
Практически всё готово. В процессе сборки может возникнуть следующая ошибка (версия ядра указана моя):
[ERROR] /Volumes/Unixen/ct-config/.build/src/linux-3.8.11/arch/x86/tools/relocs.c:8:17: fatal error: elf.h: No such file or directory
Поэтому заранее позаботимся об этом, взяв elf.h из доверенного источника. Если под рукой нет, возьмите мой elf.h. Класть нужно в /usr/include .
Если во время сборки у вас возникнет ошибка в gdb, если вы не отключили [*] Enable python scripting раньше:
configure: error: python is missing or unusable
# if getvar('LINKFORSHARED') is not None: # libs.extend(getvar('LINKFORSHARED').split())
На Macbook Air с i5 сборка идёт порядка 69 минут , причём у вас скорее всего в середине всплывут какие-нибудь ошибки. Так что отойти далеко от компьютера не получится.
Заключение
/Volumes/Unixen $ du -csh ct-config/
Using built-in specs. COLLECT_GCC=x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-gcc COLLECT_LTO_WRAPPER=/Volumes/Unixen/x86_64-unknown-linux-gnu/libexec/gcc/x86_64-unknown-linux-gnu/4.7.3/lto-wrapper Configured with: /Volumes/Unixen/ct-config/.build/src/gcc-4.7.3/configure --build=x86_64-build_apple-darwin12.4.0 --host=x86_64-build_apple-darwin12.4.0 --target=x86_64-unknown-linux-gnu --prefix=/Volumes/Unixen/x86_64-unknown-linux-gnu --with-sysroot=/Volumes/Unixen/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot --enable-languages=c,c++ . Target: x86_64-unknown-linux-gnu Thread model: posix gcc version 4.7.3 (crosstool-NG hg+default-2685dfa9de14)
cd linux-source-3.9 export PATH=$PATH:/Volumes/Unixen/x86_64-unknown-linux-gnu/bin export C_INCLUDE_PATH=/usr/include:/opt/local/include:/Volumes/Unixen/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot/usr/include make ARCH=x86_64 CROSS_COMPILE=x86_64-unknown-linux-gnu- all -j4
Кросс-компилятор⚓︎
Кросс-компилятор (англ. cross compiler ) — компилятор, производящий исполняемый код для платформы, отличной от той, на которой исполняется сам кросс-компилятор. Такой инструмент бывает полезен, когда нужно получить код для платформы, экземпляров которой нет в наличии, или в случаях когда компиляция на целевой платформе невозможна или нецелесообразна (например, это касается мобильных систем или микроконтроллеров с минимальным объёмом памяти). Например, компилятор, который работает на компьютере Windows 7, но и генерирует код, который работает на Android.
Применение кросс-компиляторов⚓︎
- Встроенные компьютеры, на которых ресурсы устройства крайне ограничены.
- Компиляция для нескольких машин. Например, компания может пожелать поддерживать несколько разных версий операционной системы или поддерживать несколько разных операционных систем. Используя кросс-компилятор, можно настроить единую среду сборки для компиляции для каждой из этих целей.
- Компиляции на ферме серверов. Подобно компиляции для нескольких машин, сложная сборка, которая включает в себя множество операций компиляции, может быть выполнена на любой свободной машине.
- Самонастройка на новую платформу. При разработке программного обеспечения для новой платформы или эмулятора будущей платформы используется кросс-компилятор, чтобы скомпилировать необходимые инструменты.
- Компиляция машинного кода для эмуляторов для уже устаревших платформ, таких как Commodore 64 или Apple II.
Канадский крест⚓︎
Канадский крест — это техника построения кросс-компиляторов для других машин. Система конфигурирования и сборки GNU позволяет собирать программы, которые запускаются на системе, отличной от той, на которой собирались необходимые средства. Иными словами, она поддерживает сборку программ с помощью кросс-компилятора.
При использовании канадского креста c GCC могут быть четыре вида:
- Фирменный родной компилятор для машины (1) (например, компилятор из Visual Studio) используется для построения собственного компилятора GCC для машины (2).
- Родной компилятор GCC для машины (2) используется для сборки кросс-компилятора GCC с компьютера А на компьютер Б (3)
- GCC кросс-компилятор с компьютера A на компьютер Б (3) используется для построения компилятора GCC кросс-компилятор из машины в машину C (4)
Конечный кросс-компилятор (4) не сможет работать на машине сборки A; вместо этого он будет работать на машине B, чтобы скомпилировать приложение в исполняемый код, который затем будет скопирован на машину C и выполнен на машине C.
Термин «канадский крест» возник потому, что в то время, когда эти проблемы обсуждались, в Канаде было три национальные политические партии.
Кросс-компиляция с GCC⚓︎
GCC, коллекция свободно распространяемых компиляторов, может быть настроена для кросс-компиляции. Она поддерживает множество платформ и языков.
Для кросс-компиляции с GCC необходимо, чтобы была доступна скомпилированная для целевой платформы версия binutils. Особенно важно наличие GNU Assembler. Поэтому binutils должны быть предварительно скомпилированы с ключом —target=some-target, указанным скрипту конфигурирования (англ.). GCC также должна быть указана опция —target с аналогичным содержанием. После этого, чтобы GCC могла использовать полученные binutils, надо поместить путь к ним в переменную окружения path, например:
PATH=/path/to/binutils/bin:$PATH> make
Кросс-компиляция GCC требует, чтобы часть стандартной библиотеки целевой платформы была доступна на хост-платформе. Программист может решить скомпилировать полную библиотеку C, но этот выбор может быть ненадежным. Альтернативой является использование файла, который представляет собой небольшую библиотеку C, содержащий только самые важные компоненты, необходимые для компиляции исходного кода C.
Кросс-компиляция под Linux
Что же у нас есть для кросс-компиляции? Если не считать коммерческих продуктов и мелких поделок, то для того, чтобы скомпилировать любой проект под любую платформу, понадобится Gnu Compiler Collection, или, кратко, GCC. GCC — это один большой набор исходников, но собирать из него кросс-компилятор на каждую новую целевую платформу придётся отдельно.
Надо сказать, список целевых платформ довольно внушителен.
Вообще, для того, чтобы работать с GGC надо собрать т. н. Toolchain, набор утилит для компиляции. В toolchain входит помимно GCC, ещё Binutils, предназначенные для манипуляций с объектными и бинарными файлами. Для голого железа (если планируется работать не под ОС на целевой платформы, весьма полезной будет также NewLib — сборник стандартных процедур.
Binutils
GCC
В составе GCC большой набор разнообразных инструментов, однако, скорее всего иметь дело придётся с frontend, который так и называется, gcc. Он сам определяет тип исходного файла и вызывает соответствующий компилятор, а также, по необходимости, линковщик или библиотекарь.
NewLib
NewLib — специальная подборка стандартных функций для встраиваемых систем. Она включает в себя libc (функци работы со строками, файлами и т. д.), libm (разнообразные математические функции). Также она обладает широкими возможностями конфигурирования под разнообразные требования.
Надо сказать, NewLib далеко не единственный выбор. В принципе, если не пользоваться библиотечными функциями, можно вообще без библиотек обойтись, но этот путь сложен и тернист — стандарт си не требует наличия их в т. н. standalone environment 1) . Вполне возможно, есть другие подходящие варианты
GDB
GNU Debugger — стандартное средство отладки программ, и, в принципе, необязательно. Возможно, вы предпочтёте графический отладчик или вовсе пользуетесь исключительно printf-style-debug 2) .
Сборка Toolchain
Также стоит определить путь, куда будет всё установлено. В терминах GCC это называется prefix. По умолчанию этот путь — /usr/local . Однако по ряду различных причин иногда стоит специально указать другой. Первая причина — поставить в собственную домашнюю директорию, например, если нет root-полномочий на машине или просто его поставить только для себя (впрочем, лучше так не делать). Другая причина — бывает нужда с специальных вариантах сборки, и тогда это стоит делать, чтобы не спутать такую сборку с обычной. Стоит отметить, что компиляторы под различные платформы не перепутываются, так как имеют различные имена: gcc для ARM, например, будет именоваться arm-elf-gcc 3) или arm-linux-gcc , и именно его придётся указывать при компиляции (либо указывать target, тогда gcc сам вызовет нужный). Если же оставить путь по-умолчанию, сборка попадёт в стандартный путь поиска исполняемых файлов — /usr/local/bin , и может вызываться без специального указания пути или модификации $path .
Для указания prefix у configure есть соответствующая опция: — -prefix=…
Порядок сборки Toolchain
Сборка тулчейна в описанной конфигурации состоит из следующих этапов: