суббота, 9 января 2016 г.

Собираем кросс-компилятор gcc для sparc

Бывает, что перед разработчиком встаёт задача собрать проект, запускающийся на одной платформе, но при этом для разработки проекта используется другая. Для этих целей применяется кросс-компилятор - специальная сборка компилятора, работающая на host-платформе, и генерирующая код для target-платформы. Здесь я расскажу как собирать gcc с хостом на x86, генерирующий код под sparc.
Думаю вкратце понятно что такое кросс-компилятор, и для чего он нужен, поэтому немного о данной заметке. Во многом это будет вольный конспект данного поста. Основное различие в том, что там автор собирал компилятор для arm, а я делаю это для sparc, что вносит свои коррективы. Ну и я попытался немного автоматизировать данный процесс.

Итак, поехали. Создаём какую-нибудь директорию, и скачиваем туда всё необходимое:

$ mkdir tmp && cd tmp
$ svn checkout svn://gcc.gnu.org/svn/gcc/trunk gcc_trunk
$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.25.tar.gz
$ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/testing/linux-4.4-rc3.tar.xz
$ git clone git://sourceware.org/git/glibc.git
$ wget http://ftp.gnu.org/gnu/glibc/glibc-2.22.tar.xz
$ wget http://www.mpfr.org/mpfr-current/mpfr-3.1.3.tar.xz
$ wget https://gmplib.org/download/gmp/gmp-6.1.0.tar.xz
$ wget ftp://ftp.gnu.org/gnu/mpc/mpc-1.0.2.tar.gz
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.15.tar.bz2

$ for i in *.tar*; do tar -xpvf $i; done


Это набор необходимых пакетов. Здесь используется транковская версия gcc (можно и стабильную) и транковская версия glibc. Последнее связано с тем что >=gcc-5 не собирает glibc-2.22 из-за ошибок компиляции. Недавно вышел glibc-2.23, но я его не пробовал.

gcc использует сторонние библиотеки, поэтому для сборки нужно их заранее подготовить:

$ pushd gcc_trunk/
$ ln -s ../mpfr-3.1.3 mpfr
$ ln -s ../gmp-6.1.0 gmp
$ ln -s ../mpc-1.0.2 mpc
$ ln -s ../isl-0.15 isl
$ popd


Теперь создадим директорию куда будем устанавливать компилятор и библиотеки:

$ mkdir cross
$ export PREFIX="`pwd`/cross" # Директория установки
$ export TARGET="sparc-sun-linux" # Целевая архитектура
$ # export TARGET="sparc64-sun-linux" # Это если нам нужен 64-х битный sparc
$ export PATH="$PREFIX"/bin:$PATH # Пути для бинарников


Сначала соберём binutils. В нём содержатся кросс-ассемблер, кросс-линкер и прочие инструменты:

$ export BINUTILS_OBJS="`pwd`/binutils_objs"
$ export BINUTILS_SRC="`pwd`/binutils-2.25/"
$ mkdir -p "$BINUTILS_OBJS"
$ pushd "$BINUTILS_OBJS" > /dev/null
$ "$BINUTILS_SRC"/configure --prefix="$PREFIX" --target=$TARGET --with-sysroot

$ make -j5
$ make install
$ popd > /dev/null


Далее ставим некоторые файлы ядра чтобы приложения могли использовать спарковские системные вызовы

$ export LINUX_SRC="`pwd`/linux-4.4-rc3"
$ pushd "$LINUX_SRC" > /dev/null
$ export LINUX_ARCH="sparc"
$ # export LINUX_ARCH="sparc64" # Это для 64-х битной версии
$ make ARCH=$LINUX_ARCH INSTALL_HDR_PATH="$PREFIX/$TARGET" headers_install
$ popd > /dev/null


Собираем только компиляторы без библиотек

$ export GCC_OBJS="`pwd`/gcc_objs"
$ export GCC_SRC="`pwd`/gcc_trunk"
$ mkdir -p "$GCC_OBJS"
$ pushd "$GCC_OBJS" > /dev/null
$ "$GCC_SRC"/configure --prefix="$PREFIX" --target=$TARGET --enable-languages=c,c++,fortran --enable-gold=yes --enable-ld=yes --enable-lto CFLAGS="-O3" CXXFLAGS="-O3"
$ make -j5 all-gcc
$ make install-gcc
$ popd > /dev/null


Конфигурацию gcc следует подстраивать под себя, мне обычно нужно чтобы компилятор имел фронтенды только для c/c++/fortran (опция --enable-languages), а также чтобы он умел lto.

Теперь ставим заголовочные файлы glibc. При этом создадим заглушку для libc.so. Тут стоит обратить внимание на опцию "-fno-stack-protector", без неё версия для sparc не соберётся.

$ export GLIBC_OBJS="`pwd`/glibc_objs"
$ export GLIBC_SRC="`pwd`/glibc"
$ mkdir -p "$GLIBC_OBJS"
$ pushd "$GLIBC_OBJS" > /dev/null
$ "$GLIBC_SRC"/configure --prefix="$PREFIX"/$TARGET/ --build=$MACHTYPE --host=$TARGET --target=$TARGET --with-headers="$PREFIX"/$TARGET/include CFLAGS="-O2 -fno-stack-protector" CPPFLAGS="-O2 -fno-stack-protector"
$ make install-bootstrap-headers=yes install-headers
$ make -j5 csu/subdir_lib
$ install csu/crt1.o csu/crti.o csu/crtn.o "$PREFIX"/$TARGET/lib
$ "$PREFIX"/bin/$TARGET-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o "$PREFIX"/$TARGET/lib/libc.so
$ touch "$PREFIX"/$TARGET/include/gnu/stubs.h
$ popd > /dev/null


Теперь соберём библиотеки поддержки компилятора. В них, например, содержится обработка исключений c++.

$ pushd "$GCC_OBJS" > /dev/null
$ make -j5 all-target-libgcc
$ make install-target-libgcc
$ popd > /dev/null


Непосредственно собираем и устанавливаем glibc

$ pushd "$GLIBC_OBJS" > /dev/null
$ make -j8
$ make install
$ popd > /dev/null


И последнее - собираем и устанавливаем стандартную библиотеку c++:

$ pushd "$GCC_OBJS" > /dev/null
$ make -j8
$ make install
$ popd > /dev/null


Собственно, всё, теперь можно использовать кросс-компилятор. Пока что мне не удалось собрать версию под 64 бита с multilib'ом - т.е. чтобы компилятор целевой платформой имел sparc64, но при этом умел генерить 32-х битный код, но в целом это не большая потеря. Можно тупо собрать две версии компилятора.

Также у автора оригинального поста есть скрипт для автоматической сборки, но я его не тестировал.

Комментариев нет:

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.