1

I am trying to set up a GCC 4.9.4 cross-compiler for a QCA955X-based router with Linux 2.6.31. This is a MIPS32R2-abi CPU that uses uClibc-0.9.30.1 (as found in /lib.) Due to this, I have decided to compile a GCC 4.x with the matching uClibc and binutils-2.19.1a. My host system is Ubuntu 18.04 with Linux 4.17-rc5 and gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)

~/mips-cross-gcc/staging_dir is my prefix, and ~/mips-cross-gcc/staging_dir/sysroot is the makeshift sysroot for my system.

1) I downloaded binutils-2.19.1a.tar.bz2, gcc-4.9.4.tar.bz2, linux-2.6.31.9.tar.xz, and uClibc-0.9.30.1.tar.bz2 into ~/mips-cross-gcc/sources.

2) I untar'd all the sources.

3) Install linux headers:

make ARCH=mips INSTALL_HDR_PATH=/home/user/mips-cross-gcc/staging_dir/sysroot/usr headers_install

4) Build binutils:

cd binutils-2.19.1
./configure --prefix=/home/user/mips-cross-gcc/staging_dir --target=mips-linux-uclibc --disable-multilib --disable-werror --enable-shared --without-newlib --with-sysroot=/home/user/mips-cross-gcc/staging_dir/sysroot --enable-languages=c,c++ --disable-libgomp

make all-binutils
make all-ld
make all-gas
make install-binutils
make install-ld
make install-gas

5) Build "stage 1" gcc, to bootstrap uClibc:

cd gcc-4.9.4
mkdir -p build/gcc-stage1
../../configure --target=mips-linux-uclibc --prefix=/home/user/mips-cross-gcc/staging_dir --disable-werror --disable-libgomp --without-newlib --disable-multilib --enable-languages=c,c++ --enable-shared --disable-__cxa_atexit --enable-target-optspace --disable-nls --disable-libmudflap  --disable-libssp --with-float=soft --with-sysroot=/home/user/mips-cross-gcc/staging_dir/sysroot --with-gnu-ld --without-headers
make all-gcc
make install-gcc

6) Install uClibc headers:

cd uClibc-0.9.30.1
make PREFIX=/home/user/mips-cross-gcc/staging_dir/sysroot install_headers

7) Build libgcc for target arch: cd gcc-4.9.4 make all-target-libgcc

Libgcc is compiled all the way until the final libgcc_s linking stage:

/home/daniel/mips-cross-gcc/staging_dir/mips-linux-uclibc/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
Makefile:937: recipe for target 'libgcc_s.so' failed

I thought that bootstrapping a GCC would not require a libc, because it has not been compiled yet, right? What could I be doing wrong? I would use this compiled GCC to build uClibc, and then I would compile GCC again with my new uClibc so that I can cross-compile software. The fact that GCC requires libc in the first build seems wrong.

I tried to use the first gcc without compiling libgcc for building uClibc, but nearly instantly I received:

LD ld-uClibc-0.9.30.1.so
mips-linux-uclibc-gcc: error: libgcc.a: No such file or directory
ldso/ldso/Makefile.in:54: recipe for target 'lib/ld-uClibc.so' failed

So, uClibc needs libgcc to link itself, and gcc needs a libc (of any type, including uClibc) to link its own libgcc. This seems like a chicken-and-egg problem. How would one fix this?

  • Is there an "official" build mechanism for your router's firmware that will take care of setting up the toolchain? For example, OpenWrt uses a build system based on Buildroot. Or are you trying to build a C compiler that will run on the router itself? – Ian Abbott Jun 01 '18 at 15:03
  • There is, however this is a router that uses an Openwrt "Kamikaze" derived firmware with unreleased modifications. The Openwrt buildroot uses old scripts and there are too many errors to debug on a modern computer, sadly. Kamikaze is quite old, and the svn servers it used are forever gone as well. So, this is the only option I currently have :( – Daniel Rodriguez Jun 02 '18 at 01:55
  • Regarding the use of old build systems on up-to-date hosts, I've occasionally resorted to setting up Docker containers (based off some old Linux distro) for that purpose. It can't help much with missing svn servers though! – Ian Abbott Jun 04 '18 at 10:02

1 Answers1

2

I fixed it. Apparently, GCC has to be built without shared libraries enabled (--disable-shared) so that it doesn't link the generated libraries like libgcc dynamically (i.e to libc,) but that still didn't work. -lc was still not found.

I did some more googling, and I found this helpful message from eglibc, about making their own toolchain with gcc: eglibc.org

The First GCC

For our work, we need a cross-compiler targeting a PowerPC Linux system. However, that configuration includes the shared library 'libgcc_s.so', which is compiled against the EGLIBC headers (which we haven't installed yet) and linked against 'libc.so' (which we haven't built yet).

Fortunately, there are configuration options for GCC which tell it not to build 'libgcc_s.so'. The '--without-headers' option is supposed to take care of this, but its implementation is incomplete, so you must also configure with the '--with-newlib' option. While '--with-newlib' appears to mean "Use the Newlib C library", its effect is to tell the GCC build machinery, "Don't assume there is a C library available."

Looks like with enough digging, someone's bound to find the exact problem one has.

In short, changing --enable-shared to --disable-shared and adding --with-newlib to GCC's ./configure solved the issue and compiled + linked a libgcc_s.so that I used to compile uClibc, and then recompiled gcc with the newly generated libc, from uClibc. Indeed, it is possible to compile a 2016 GCC 4.x with a 2011 uClibc on a 2018 GCC 7.x.