Log in

No account? Create an account
'Twas brillig, and the slithy toves did gyre and gimble in the wabe [entries|archive|friends|userinfo]

[ website | Beware the Jabberwock... ]
[ deviantArt | the-boggyb ]
[ FanFiction | Torkell ]
[ Tumblr | torkellr ]

[Random links| BBC news | Vulture Central | Slashdot | Dangerous Prototypes | LWN | Raspberry Pi]
[Fellow blogs| a Half Empty Glass | the Broken Cube | The Music Jungle | Please remove your feet | A letter from home]
[Other haunts| Un4seen Developments | Jazz 2 Online | EmuTalk.net | Feng's shui]

Silly things with cross-compilers, parts 2 (building binutils) and 3 (kernel and libc headers) [Friday 20th January 2012 at 11:35 pm]

[Tags|, ]
[Feeling |accomplishedaccomplished]
[Playing |Utopia ~ Within Temptation]

Where was I? Ah yes, building stuff...

Part 2: Building binutils

The one thing that all the instructions agree on is that you have to compile binutils before you can even start on gcc. So, unpack the binutils sources into /cross/src (I'm using binutils version 2.21.53 here):

cd /cross/src
tar -xvf /mingw/var/cache/mingw-get/packages/binutils-2.21.53-1-mingw32-src.tar.lzma

Then build the thing using the usual linux mantra of configure, make, make install. I'm using relative paths to invoke configure because some stuff (gcc in particular) will fail to build if you use an absolute path.

mkdir -p $PREFIX/build/binutils-2.21.53
cd $PREFIX/build/binutils-2.21.53
../../../src/binutils-2.21.53/configure --prefix=$PREFIX --target=$TARGET --with-sysroot=$SYSROOT
make install

That was surprisingly easy. The hard part was figuring out what to specify as the target, since there's no such thing as an up-to-date list of valid targets. After a bit of trial and error I came up with armv5l-linux - this doesn't quite match the NAS (uname -m claims it's an armv5tel) but with any luck will be close enough.

Part 3: Kernel and libc headers

The kernel and libc headers tend to be highly specific to a particular target. If the manufacturer's been good, there should be a zip or tarball containing the kernel and libc they've used (look for a file on their website like "GPL firmware"). If they've been bad, then you'll have to put your own one together and hope it matches whatever they've used. Thecus fall somewhere in the middle - the GPL sources for the N2100 contain the kernel but not libc. Fortuantly they've used glibc and not some ultra-optimised alternative, so with any luck I should be able to get away with building my own glibc.

Anyway, time to unpack their kernel and get the files in the right place. I'm running tar twice because in some cases it tries to create a symlink before creating the file the symlink points to. Since I'm running on Windows, MinGW simulates symlinks by copying the target and so fails if the target doesn't already exist.

cd $PREFIX/src
tar -xvf "N2100 Firmware 2.01.10 GPL sources.tar.bz2"
tar -xvf "N2100 Firmware 2.01.10 GPL sources.tar.bz2"

There's still a few warnings about symlinks to files outside that directory structure, but hopefully those won't be an issue as I don't intend to actually build the kernel. That's just as well, because the kernel sources contains several files where the name differs only in case - Windows treats those files are identical and so the later one in the archive blats the earlier one!

Anyway, I now have a kernel. Now to run some magic commands (based on these) to get everything in hopefully the right place. I'm trusting the current configuration to be accurate, so I'll skip running make.

cd n2100_2.01.10_GPL/linux/
cp -a include/linux ${SYSROOT}/usr/include/linux
cp -a include/asm-arm ${SYSROOT}/usr/include/asm
cp -a include/asm-generic ${SYSROOT}/usr/include/asm-generic

Next step is to get hold of glibc. This seems slightly out of order, but apparently to compile gcc you either need your libc for whatever you're targetting or have to apply some horrid hack. Anyway, running libc.so.6 claims that the NAS has "GNU C Library stable release version 2.2.5". It also claims that it was compiled by "GNU CC version 3.3.2", which may be an issue as I'm trying to build GCC 4.6.1. Anyway, grab the necessary files and unpack them into /cross/src:

cd /cross/src
tar -xvf glibc-2.2.5.tar.gz
cd glibc-2.2.5
tar -xvf ../glibc-linuxthreads-2.2.5.tar.gz

And run configure (yes, this is being run with the host compiler - remember, I don't have a cross-compiler yet):

cd $PREFIX/build
mkdir glibc-2.2.5
cd glibc-2.2.5
../../../src/glibc-2.2.5/configure --prefix=/usr --host=${TARGET} --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/usr/include
checking for gcc... gcc
checking version of gcc... 4.6.1, bad
checking for gnumake... no
checking for gmake... no
checking for make... make
checking version of make... 3.81, ok
configure: error:
*** These critical programs are missing or too old:gcc
*** Check the INSTALL file for required versions

Um. It should be noted that the INSTALL file recommends "GCC 2.95 or newer". One would hope that GCC 4.6.1 would suffice, but apparently not. In fact, the configure script rejects anything that's more recent than the current versions of the time. Or, at least it did until I fixed it. Muwhahaha.

Anyway, here's a diff of what I changed:

--- /cross/src/glibc-2.2.5/configure.orig       2012-01-20 23:08:43 +0000
+++ /cross/src/glibc-2.2.5/configure    2012-01-20 23:10:47 +0000
@@ -1476,7 +1476,7 @@
   ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
   case $ac_prog_version in
     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    *gcc-2.9[5-9].*|*2.8.[1-9]*|*2.9|*2.9.[0-9]*|2.9[5-9]*|3.[0-9]*|cygnus-2.9[1-9]*|gcc-2.9[5-9]|gcc-2.1[0-9][0-9]|sgicc-*)
+    *gcc-2.9[5-9].*|*2.8.[1-9]*|*2.9|*2.9.[0-9]*|2.9[5-9]*|3.[0-9]*|cygnus-2.9[1-9]*|gcc-2.9[5-9]|gcc-2.1[0-9][0-9]|sgicc-*|4.[0-9.]*)
        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;

This time configure worked, although it complained that I wasn't using versioning because my binutils package was too old. Meh. The next step is to run make install-headers, and then create a couple of files that gcc apparently needs to exist but not necessarily actually contain any content:

make cross-compiling=yes install_root=${SYSROOT} install-headers
mkdir ${SYSROOT}/usr/include/gnu
touch ${SYSROOT}/usr/include/gnu/stubs.h
touch ${SYSROOT}/usr/include/bits/stdio_lim.h

In theory I've now got a vaguely sensible set of glibc headers that gcc can actually use when compiling. The next step will be to at long last actually build my cross-compiler.

Link | Previous Entry | Share | Flag | Next Entry[ 3 pennies | Penny for your thoughts? ]

From: pewterfish
Saturday 21st January 2012 at 9:30 pm (UTC)
The target should be fine. ARM use the string of letters after the number in the processor name to indicate optional features, so a 5tel is the same device as a 5l, it just has more bells and whistles. As long as the compiler doesn't get too clever, code for a 5tel should be just fine on a 5l, just maybe a bit slower than optimal.
(Reply) (Thread)
[User Picture]From: boggyb
Sunday 22nd January 2012 at 10:25 pm (UTC)
Don't you mean "code for a 5l should be just fine on a 5tel"?
(Reply) (Parent) (Thread)
From: pewterfish
Sunday 22nd January 2012 at 10:27 pm (UTC)
Yes, yes I do. Challenging weekend.
(Reply) (Parent) (Thread)