crosstool-howto

Crosstool is a set of scripts to build and test several versions of gcc and glibc for most architectures supported by glibc. It will even download and patch the original tarballs for you. The resulting script and associated patches, and the latest version of this doc, are available at kegel.com/crosstool.

It includes minimal gcc and glibc needed to build a few combinations of (alpha, arm, cris, i686, ia64, mips, ppc750, ppc405, sh4, sparc, s390, x86_64) x (gcc-2.95.3, gcc-3.2.3, gcc-3.3). The patches for each tool are stored in a subdirectory of patches/ named after the tool, (e.g. patches/gcc-3.3, Each patch starts with comments about what it's for, and has links to the bug it fixes and any associated discussion.

To get started, unpack the tarball, and read the shell scripts. Start with demo.sh, which runs all.sh, which runs getandpatch.sh, crosstool.sh, and crosstest.sh. Or start with demo-{ppc405,ppc750,mipsel}.sh, which are shorter, and show how to put the resulting toolchains somewhere useful.

If you want to build gcc-3.3 or later, you'll need a recent gcc (3.2 or later) on your workstation to build it with.

Then edit the script demo.sh, uncomment just the line for the toolchain you want to build, and run it. About an hour or two later, you should have a toolchain. Use testhello.sh to compile simple statically linked 'hello, world' programs in both C and C++, and try to run them on the target.

Then, if needed, tweak the parameters of the script to match your exact CPU type if needed, or add any patches needed to the patches/* directories, and run the build script again. In particular, if your CPU lacks an FPU, you might need to tell glibc that by setting before running all.sh. For example, see powerpc-405.dat, which sets

GLIBC_EXTRA_CONFIG="--without-fp"

Once you trust the toolchain can build and run the statically linked 'hello, world' programs, run the remote regression test, which checks whether your new toolchain can compile and run a large number of test programs correctly.

If you use these scripts to build a toolchain, please send a note to the crossgcc mailing list indicating which platform you used it on, and how well it worked for you. Please be sure to mention which release of the crosstool scripts you used.

Options

all.sh takes four options:

Testing

demo.sh runs all.sh with the --notest option, since you need to prepare a bit before you can run the tests.

Unless you give the --notest option when running all.sh, it will try to test the resulting tools using their built-in regression test, which is based on Dejagnu, and which requires a remote target to run on, preferably with a chroot jail that allows remote login.

Before you try this, you may wish to read dejagnu-remote-howto.html and chroot-login-howto.html, which explain how one uses Dejagnu with remote targets, and how one sets up a chroot jail that allows remote login.

Before you use all.sh to test the toolchain, you need to do six things:

  1. add an entry in /etc/hosts for each target you want to test. e.g. if you want to test sh4-unknown-linux-gnu, you must have an sh4 system running linux online somewhere, and 'ping sh4-unknown-linux-gnu' must be able to get packets to it. This is not normal dejagnu practice, but it made it much easier to write this doc and the example scripts. (It also restricts you to just one remote target of each type, but if that limitation ever bothers you, you can probably afford to set up your own dejagnu configuration and not use these scripts.)
  2. set up rsh/rlogin/rcp client and server apps on your workstation and on each target system, and make sure they work. (chroot-login-howto.html should be helpful here.) (Note: if you run into a strange "Unable to allocate memory" error when using rcp to retrieve files from an sh4 system, you may need to apply the patch inetutils-1.4.2/sh4-div.patch.)
  3. The rsh / rcp protocol only has 512 IP ports available, so if you launch more than 512 rsh or rcp commands during a 2MSL (120 second) period, the resulting zombie TCP connections hanging around in TIME_WAIT state (you can observe this with netstat -pant) will cause rsh or rcp to fail with error "rcmd: socket: All ports in use".

    To prevent this, issue the following command both locally and on the target (only works on Linux):

    # echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
    
    This is completely illegal with respect to the Internet RFCs, but it does prevent the rsh and rcp connections from stacking up in state TIME_WAIT. (crosstest.sh checks to make sure you've done this locally, but doesn't check that you've done it on the target.)
  4. Following the instructions in chroot-login-howto.html, set up and test a chroot jail in /jail for user root-jail on each target system you want to test on, and make sure you can use rsh and rcp into the jail remotely as user root-jail.
  5. Make sure you can re-initialize the chroot jails remotely; see testjail.sh for an example of how to test this.
  6. Run mkdejagnu.sh to compile a known good copy of dejagnu.
Once all the above are working, you should be able to run all.sh without the --notest argument. For instance, to test a gcc-3.3/glibc-2.2.5 toolchain you already built for sh4-unknown-linux-gnu:
eval `cat sh4.dat` `cat gcc-3.3-glibc-2.2.5.dat`    sh all.sh --nounpack --nobuild > x.log 2>&1 &
Keep an eye on the log file; after twenty seconds or so, you should check that dejagnu is able to download and run test apps. Easiest way to check is to use grep to look for passed tests. For example:
$ egrep 'PASS|FAIL|UNRESOLVED' x.log
PASS: gcc.c-torture/execute/20000112-1.c compilation,  -O0 
PASS: gcc.c-torture/execute/20000112-1.c execution,  -O0 
PASS: gcc.c-torture/execute/20000112-1.c compilation,  -O1 
PASS: gcc.c-torture/execute/20000112-1.c execution,  -O1 
...
If you see lots of FAILed or UNRESOLVED tests, something's wrong, and you'll have to start digging. For instance, make sure there's enough free RAM and disk space on the target system.

The test will take some time to run. When it's done, it will create $TOP_DIR/$TARGET-$TOOLCOMBO-{gcc,binutil}.sum (e.g. sh4-unknown-linux-gnu-gcc-3.3-glibc-2.2.5-gcc.sum) which will tell how many tests failed unexpectedly. Interpreting these results is tricky; see Installing GCC: Testing at the GCC home page, and /or the gcc-testresults mailing list for what kind of results other people are getting.

If you use these scripts to test your toolchain, please send the test results to the crossgcc mailing list and the gcc-testresults mailing list. Be sure to mention which release of the crosstool scripts you used.

Notes on testing

If testing a small (< 64 MB RAM) target with no swap space, you probably want to reboot the target before starting each run.

The glibc tests probably require about 16MB RAM free on the target system (before setting up the jail) and about 16MB of free disk space. On systems with less than 128MB of physical RAM and no swap, you may want to mount /jail via NFS from some Linux box with a bit of free disk space.

I have seen the testcases forget to delete files on the target after trying to run them. (Possibly this is normal in the case of failed tests?) On small targets, you should run cleantmp.sh in the background before starting the first test to prevent /tmp from filling up.

If your toolchain is missing some crucial patches or is misconfigured, you might not be able to get a chroot jail working. In that case, try linking the gcc regression tests statically, and running them without the jail; edit crosstest.sh where it's creating boards/$TARGET.exp, and uncomment the lines that set cflags to -static and username to root. That should get you to a point where you can at least run the gcc and glibc tests and see what's screwing up!

You can rerun an individual gcc test by hand with a command like

$ cd ~/crosstool-0.25/build/powerpc-405-linux-gnu/gcc-3.3-glibc-2.2.5/build-gcc
$ DEJAGNU=~/crosstool-0.25/boards/master.exp PATH=~/crosstool-0.25/result/dejagnu/bin:$PATH RUNTESTFLAGS="--target=powerpc-405-linux-gnu -v -v -v -v -a execute.exp=20000731-1.c" make check-gcc
(Be sure to edit that command to match your paths and target!) That tells runtest to run just testcase gcc/testsuite/gcc.c-torture/execute/20000731-1.c. It may be easier to run runtest directly, rather than through make. The same command above can be run as
$ cd ~/crosstool-0.25/build/powerpc-405-linux-gnu/gcc-3.3-glibc-2.2.5/build-gcc/testsuite
$ DEJAGNU=~/crosstool-0.25/boards/master.exp PATH=~/crosstool-0.25/result/dejagnu/bin:$PATH runtest --tool=gcc --target=powerpc-405-linux-gnu -v -v -v -v -a execute.exp=20000731-1.c

You can also rerun individual tests by just compiling them by hand, transferring them to the target, and running them. Dejagnu is just a fancy way of doing that automatically.

When running gcc execution tests with whatever glibc is laying about, you may get the error "error in loading shared libraries: undefined symbol: __register_frame_info" To work around this, see register_frame_info_fix.{sh,c} The right fix is probably to use a chroot environment and test with your newly built glibc, as documented above.

The dejagnu in debian is old, and will fail on c-torture's first test (20000112-1.c) unless you copy share/dejagnu/standard.exp to share/dejagnu/baseboards/ That one reason I tell you to compile dejagnu-1.4.3 fresh instead of using the system's copy of dejagnu.

If you're testing on a busybox-0.65 system, sometimes tar -z fails. Using uncompressed tar archives is safer.

Current Issues

See the ChangeLog for more issues.

Contributed Patches

A few users of the crosstool scripts have submitted patches. I'm saving these in the 'contrib' directory until I have time to test them.

Links

There are many good references for people building crosscompilers: And some not so good ones :-)


Portions copyright 2003, Ixia Communications.
Released under the GPL.
Last revision 11 November 2003 by dkegel@ixiacom.com / dank@kegel.com