Skip to content

Instantly share code, notes, and snippets.

@maoueh
Last active January 16, 2022 17:49
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save maoueh/14ef25a03d5722bc1e03 to your computer and use it in GitHub Desktop.
Save maoueh/14ef25a03d5722bc1e03 to your computer and use it in GitHub Desktop.
Build steps to create a (cross-)compiler creating native code executable targeting raspberry pi (RPi), running on MSYS2 and using MSYS2 to compile the cross-compiler

Build Steps

This document details extra that were needed to build the rpi cross-compiler on MSYS2. The original instructions are located on gurucodings.

This cross-compiler has been created targeting the Raspbian Wheezy OS which is based on Debian Wheezy with special support for the Raspberry PI architecture. The version that was installed on my rpi is 2014-06-20-wheezy-raspbian.

Here the version of the various tools currently present in this version of Raspbian (Guest OS):

  • gcc (Debian 4.6.3-14+rpi1) 4.6.3
  • GNU ld (GNU Binutils for Debian) 2.22
  • Binutils target target of arm-linux-gnueabihf
  • ldd (Debian EGLIBC 2.13-38+rpi2+deb7u1) 2.13
  • Linux raspberrypi 3.12.22+ #691 PREEMPT Wed Jun 18 18:29:58 BST 2014 armv6l GNU/Linux

Here the relevant list of programs that were used (at time of writing) on MSYS2 to create the actual cross-compiler:

  • GNU Make 4.0
  • gcc version 4.8.2 (GCC)
  • GNU ld (GNU Binutils) 2.24.51.20140326
  • MSYS2 2.0.0(0.273/5/3) 2014-06-24 09:17 x86_64 Msys
  • gmp 6.0.0-2 (pacman -S msys/gmp msys/gmp-devel)
  • mpfr 3.1.2.p8-1 (pacman -S msys/mpfr msys/mpfr-devel)
  • mpc 1.0.2-1 (pacman -S msys/mpc msys/mpc-devel)
  • gettext 0.18.3.2-2 (pacman -S msys/gettext msys/gettext-devel)
  • libexpat 2.1.0-1(pacman -S msys/libexpat msys/libexpat-devel)

Some utilities:

  • gzip pacman -S msys/gzip
  • patch pacman -S msys/patch
  • svn pacman -S msys/svn
  • tar pacman -S msys/tar
  • wget pacman -S msys/patch

And finally, here the list of programs that were downloaded from the interweb to compile the rpi cross-compiler:

  • binutils-2.22
  • eglibc-2.13
  • gcc-4.6.4
  • linux-3.12.22
  • gdb-7.7
  • patches

Patches

If patches go missing from the link above, ping me, I will upload them somewhere.

Preparation

Initial preperation simply involves creating a directory where you will put everything. In my case, I always work from my home directory work folder, so I created:

mkdir -p ~/work/rpi-cross

This folder (i.e. ~/work/rpi-cross) will be known in the instructions below as the $ROOT variable. You can export it right now to make it easier to copy & paste below instructions:

export ROOT=~/work/rpi-cross

Download

cd $ROOT && mkdir archives && mkdir src && mkdir patches
wget -d archives https://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.gz
svn co svn://svn.eglibc.org/branches/eglibc-2_13 archives/eglibc-2.13
wget -d archives https://ftp.gnu.org/gnu/gcc/gcc-4.6.4/gcc-4.6.4.tar.gz
wget -d archives https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.12.22.tar.gz
wget -d archives https://ftp.gnu.org/gnu/gdb/gdb-7.7.tar.gz
wget -d archives http://www.gurucoding.com/en/rpi_cross_compiler/downloads/patches-for-raspberry-pi-toolchain.tar.gz

Extraction

cd $ROOT/src
tar -xzvf ../archives/binutils-2.22.tar.gz
tar -xzvf ../archives/gcc-4.6.4.tar.gz
tar -xzvf ../archives/linux-3.12.22.tar.gz
tar -xzvf ../archives/gdb-7.7.tar.gz

cd $ROOT/patches
tar -xzvf ../archives/patches-for-raspberry-pi-toolchain.tar.gz

Compilation

We are compiling a cross-compiler for MSYS2 system which is derived directly from Cygwin. However, the guess build system is not Cygwin at all but instead x86_64-pc-msys. This can cause some of the programs above to not compile correctly because of a wrongly choose set of options.

To overcome this, add --build=x86_64-pc-cygwin to all configure scripts that do not have already the --build arguments specified. In fact, always use this value for --build.

Patching

cd $ROOT/src/gcc-4.6.4
cat ../../patches/gcc--armhf-triplet.diff | patch -p2
cat ../../patches/gcc--arm-dynamic-linker.diff | patch -p2
cat ../../patches/gcc--arm-multilib-defaults.diff | patch -p2

cd $ROOT/src/eglibc-2.13
cat ../../patches/eglibc--remove-manual.diff | patch -p1
cat ../../patches/eglibc--cross-cygwin.diff | patch -p1
cat ../../patches/eglibc--armhf-triplet.diff | patch -p1
cat ../../patches/eglibc--armhf-linker.diff | patch -p1
cat ../../patches/eglibc--ldconfig-cache-abi.diff | patch -p1
cat ../../patches/eglibc--soname-hack.diff | patch -p1
find . -type f | xargs grep -l "\.oS" | xargs sed -i 's/\.oS/\.oZ/g'

Binutils

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET

Commands:

cd $ROOT/build/binutils
../../src/binutils-2.22/configure \
--build=x86_64-pc-cygwin --target=$TARGET --prefix=$PREFIX \
--with-sysroot=$TARGET --disable-nls --with-arch=armv6

make all
make install

GCC (Cross-compiler #1)

Patch file gcc-4.6.4/gcc/doc/invoke.texi by adding @comment in front of line #1405:

-@include @value{srcdir}/../libiberty/at-file.texi
+@comment @include @value{srcdir}/../libiberty/at-file.texi

This remove libiberty manual inclusion.

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET
export PATH=$PATH:$PREFIX/bin

Commands:

cd $ROOT/build/gcc
../../src/gcc-4.6.4/configure \
--build=x86_64-pc-cygwin --target=$TARGET --prefix=$PREFIX \
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
--disable-sjlj-exceptions --enable-checking=release --enable-linker-build-id \
--enable-gnu-unique-object --disable-nls --enable-languages=c --without-headers \
--disable-shared --disable-threads --disable-multilib --disable-decimal-float \
--disable-libmudflap --disable-libssp --disable-libgomp --disable-lto \
--without-ppl --without-cloog

make all-gcc
make install-gcc
make all-target-libgcc
make install-target-libgcc

Linux Kernel (Headers)

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET
export PATH=$PATH:$PREFIX/bin

Commands:

make ARCH=arm CROSS_COMPILE=$TARGET- INSTALL_HDR_PATH=$PREFIX/usr headers_install
find $PREFIX/usr/include -name '..install.cmd' -delete
find $PREFIX/usr/include -name '.install' -delete

Eglibc (Headers)

Patch file eglibc-2.13/configure by accepting version 4.* of make. Apply the following change to line #5350:

-     3.79* | 3.[89]*)
+     3.79* | 3.[89]* | 4.*)

Patch file eglibc-2.13/Makeconfig by removing subdir manual. We don't really need the manual and the packaged eglibc I downloaded does not seem to have the required files to generate the manual. Apply the following change to line #971:

-	      gnulib iconv iconvdata wctype manual shadow gshadow po argp   \
+	      gnulib iconv iconvdata wctype shadow gshadow po argp   \

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET
export PATH=$PATH:$PREFIX/bin

Commands:

cd $ROOT/build/eglibc
CC=$PREFIX/bin/$TARGET-gcc \
CXX=$PREFIX/bin/$TARGET-g++ \
AR=$PREFIX/bin/$TARGET-ar \
RANLIB=$PREFIX/bin/$TARGET-ranlib \
MAKEINFO=: \
../../src/eglibc-2.13/configure \
--prefix=/usr --build=x86_64-pc-cygwin --host=$TARGET \
--with-headers=$PREFIX/usr/include --enable-kernel=3.0.0 \
--disable-profile --without-gd --without-cvs --enable-add-ons

make install_root=$PREFIX install-headers install-bootstrap-headers=yes
mkdir -p $PREFIX/usr/lib
make csu/subdir_lib
cp csu/crt1.o csu/crti.o csu/crtn.o $PREFIX/usr/lib
$PREFIX/bin/$TARGET-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $PREFIX/usr/lib/libc.so

GCC (Cross-compiler #2)

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET
export PATH=$PATH:$PREFIX/bin

Commands:

cd $ROOT/build/gcc
find . -delete
../../src/gcc-4.6.4/configure \
--build=x86_64-pc-cygwin --target=$TARGET --prefix=$PREFIX \
--with-sysroot=$PREFIX --disable-libquadmath \
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
--disable-sjlj-exceptions --enable-checking=release \
--enable-linker-build-id --enable-gnu-unique-object \
--disable-nls --enable-languages=c --with-headers \
--disable-multilib --disable-libmudflap --disable-libssp \
--disable-libgomp --disable-lto --without-ppl --without-cloog

make
make install

Eglibc

Patch file eglibc-2.13/Makerules by changing how generated libraries source location is determined. Instead of using $(<F) (which seems to return filename and not path, not sure about this), we will use $(<) instead which returns a full path. Apply the following change to line #996:

-$(LN_S) $(<F) $@
+$(LN_S) $(<) $@

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET
export PATH=$PATH:$PREFIX/bin

Commands:

cd $ROOT/build/eglibc
BUILD_CC=gcc \
CC=$PREFIX/bin/$TARGET-gcc \
CXX=$PREFIX/bin/$TARGET-g++ \
AR=$PREFIX/bin/$TARGET-ar \
RANLIB=$PREFIX/bin/$TARGET-ranlib \
MAKEINFO=: \
../../src/eglibc-2.13/configure \
--prefix=/usr --build=i686-pc-cygwin --host=$TARGET \
--with-headers=$PREFIX/usr/include --enable-kernel=3.0.0 \
--disable-profile --without-gd --without-cvs --enable-add-ons

make
make install_root=$PREFIX install

GCC (Cross-compiler #3)

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET
export PATH=$PATH:$PREFIX/bin

Commands:

cd $ROOT/build/gcc
find . -delete
../../src/gcc-4.6.4/configure \
--build=x86_64-pc-cygwin --target=$TARGET --prefix=$PREFIX \
--with-arch=armv6 --with-fpu=vfp --with-float=hard \
--with-sysroot=$PREFIX \
--disable-sjlj-exceptions --enable-checking=release \
--enable-linker-build-id --enable-gnu-unique-object \
--disable-nls --enable-languages=c,c++ \
--with-headers --enable-shared --enable-threads=posix \
--disable-multilib -enable-__cxa_atexit \
--disable-libmudflap --disable-libssp \
--disable-libgomp --disable-lto  --without-ppl --without-cloog

make
make install

GDB (Cross)

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/gcc-4.6.4-rpi/$TARGET

Commands:

cd $ROOT/build/gdb
find . -delete
cp -R ../gdb-7.4.1/. .
./configure --build=x86_64-pc-cygwin --prefix=$PREFIX --target=$TARGET --with-expat
make
make install

cd $ROOT/build/gdb/gdb/gdbserver
CC=$PREFIX/bin/$TARGET-gcc LDFLAGS=-static ./configure --build=x86_64-pc-cygwin --host=$TARGET
CC=$PREFIX/bin/$TARGET-gcc LDFLAGS=-static make

cp ./gdbserver $PREFIX/usr/bin
cp ./gdbreplay $PREFIX/usr/bin

ZLib

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/$TARGET

Commands:

cd /opt/crosstool/arm-linux-gnueabihf
mkdir pkg
cd pkg
wget http://zlib.net/zlib-1.2.8.tar.gz

cd ..
mkdir src
cd src
tar -xzvf ../pkg/zlib-1.2.8.tar.gz

cd zlib-1.2.8
CHOST="Linux" \
CC=$PREFIX/bin/$TARGET-gcc \
CXX=$PREFIX/bin/$TARGET-g++ \
AR=$PREFIX/bin/$TARGET-ar \
RANLIB=$PREFIX/bin/$TARGET-ranlib \
./configure --prefix=$PREFIX/usr

make
make install

OpenSSL

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/$TARGET

Commands:

cd /opt/crosstool/arm-linux-gnueabihf
mkdir pkg
cd pkg
wget http://www.openssl.org/source/openssl-1.0.1h.tar.gz

cd ..
mkdir src
cd src
tar -xzvf ../pkg/openssl-1.0.1h.tar.gz

cd openssl-1.0.1h.tar.gz
CC=$PREFIX/bin/$TARGET-gcc \
CXX=$PREFIX/bin/$TARGET-g++ \
AR=$PREFIX/bin/$TARGET-ar \
RANLIB=$PREFIX/bin/$TARGET-ranlib \
./Configure dist threads -D_REENTRANT -O3 --prefix=$PREFIX/usr

make
make install

libwebsockets

Environment:

export TARGET=arm-linux-gnueabihf
export PREFIX=/opt/crosstool/$TARGET

Commands:

cd /opt/crosstool/arm-linux-gnueabihf

mkdir src
cd src
git clone https://github.com/warmcat/libwebsockets.git

mkdir build
cd build

# Update ../cross-arm-linux-gnueabihf.cmake
# CROSS_PATH to `<Windows path to crosschain installation path`
# Add .exe to compiler executables

cmake .. -G "MSYS Makefiles" \
-DCMAKE_INSTALL_PREFIX:PATH=$PREFIX/usr \
-DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake \
-DLSW_IPV6=OFF
@IAXES
Copy link

IAXES commented Apr 19, 2017

Proposed minor change:

export PATH=$PATH:$PREFIX/bin

to ...

export PATH=$PREFIX/bin:$PATH

Otherwise, you won't be forcing path resolution to prioritize your cross-compile toolchain over the default/native one already installed on the system, and the resulting binary will be for the current system rather than the cross-compile target.

@fischerjd
Copy link

In the 'Binutils' section, the configure step, I think the '--with-sysroot' option should be assigned the value ${PREFIX} instead of ${TARGET}--i.e., '--with-sysroot=${PREFIX}'.

Copy link

ghost commented Apr 9, 2019

Here I wrote my automated script based on this gist, It supports many arches!
Link: https://github.com/danielkot/danio-gcc

Feel free to contribube :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment