|
|
Unsuccessfully predicting the end of the world since 1765.
Bootstrapping Linux on an Indy |
| Last updated |
Introduction |
| Bootstrapping is the process of bringing up an operating system on a new type of system for the first time (alternately, it is the subprocess which consists of building a full cross-compilation environment, or that subprocess which consists or building a full cross-compiler only. We will use it in the largest sense here.). This document covers bootstrapping GNU/Linux on a Silicon Graphics Indy system. |
| I will address a FAQ right away: "What is cross compilation?" Simply put, cross compilation is the process of running a compiler on a system of one type to generate code for a system of a different type. As you would expect, a cross compiler is the program which does this. Similarly, there exist cross assemblers, linkers, debuggers, and other utilities. In short, a cross toolchain deals with binary files not native to the system on which it runs. |
| There are three possible systems involved in a bootstrapping operation; the GNU autoconf terminology for them is host, build, and target. The host is the system on which programs are actually run. The build is the system on which a particular package is being built. The target, applicable only to certain packages such as gcc and binutils, is the system for which the software in question generates output (normally, this is the system for which the cross toolchain generates binaries). All three can be different, but this discussion centers on a setup in which Phase 1 binutils and gcc have build=host=sparc-linux and target=mips-linux, Phase 1 kernel and glibc have build=sparc-linux and host=mips-linux, Phase 2 packages have build=sparc-linux and host=target=mips-linux, and Phase 3 packages have build=host=target=mips-linux. Please note that you are free to replace sparc-linux with any supported environment for which you already have an acceptable native toolchain (see below). |
| There are three main phases to bootstrapping a new system: Building a cross-toolchain, building a native build environment, and finishing up by building a full suite of applications natively. Phase 1 is usually the hardest, because it involves porting the toolchain to your new platform. However, for MIPS targets most of that work has already been done. As an experimenter you need only build the existing software. Phase 2 is difficult because it uses features of the toolchain build environment that are rarely used. With some hacking, however, you can build a native C compiler and binutils. Phase 3 is relatively easy. Most applications written portably can be built out of the box. Some applications will need fixes, possibly major. |
I discuss here a step by step approach to bootstrapping
Linux on an SGI Indy. By convention, the following machines
and software are in use:
|
| Our ultimate objective is to start with an empty filesystem on ice and end with a functioning Linux installation. Some portions of this are not covered; for example, using an initial NFS root setup to transfer your environment is not covered in detail. It is assumed that you are familiar with the basics of building software from source and with the capabilities and features of the Linux kernel and common Free software. |
Phase 1 - the cross toolchain |
To begin, we will build a cross toolchain on pimp. We will
use the sources binutils-000702.tar.gz, gcc-000703.tar.gz,
and glibc-000622.tar.gz, which can be obtained from
ftp.foobazco.org/pub/people/wesolows/mips-linux/. Alternately
you are free to acquire the current CVS trees and build
those instead. We begin by creating two directories on a
large, empty disk. I will call the space /s and
the two directories crossdev and
crossdev-build.
$ mkdir /s/crossdev $ mkdir /s/crossdev-buildExtract the tarballs into the crossdev-build directory. $ cd /s/crossdev-build $ tar xzvf /path/to/gcc-000703.tar.gz $ tar xzvf /path/to/glibc-000622.tar.gz $ tar xzvf /path/to/binutils-000703.tar.gz $ tar xzvf /path/to/linux/linux-2.4.0-test3-pre2.tar.gzPlease note that even the current (as of 4 July 2000) CVS gcc will abort while compiling a kernel. To fix the problem, get and apply gcse-regcopy.diff.gz from the Foobazco FTP site as follows: $ cd egcs-000703 $ zcat /path/to/gcse-regcopy.diff.gz | patch -p1Make separate directories for building - that is, build outside the source tree. This requires that you have GNU make (or some other make which properly supports the VPATH feature. If you don't know, get GNU make 3.79). $ mkdir gcc-000703-build $ mkdir glibc-000622-build $ mkdir binutils-000702-buildBefore doing anything else, if you are on an UltraSparc system running Linux, as I am, switch to the 32-bit userland mode: $ sparc32 bashSome general notes in advance: we will make frequent use of options and environment variables to configure. You are strongly advised to consult
each individual program's documentation on the usage and
purpose of these arguments. However, for most programs, the
following hold:
$ cd binutils-000622-build $ ../crossdev/binutils-000622/configure --prefix=/s/crossdev --target=mips-linux $ make MAKE="make -j3"This should go smoothly. If it does not, your host's toolchain may be broken or you may have found a bug in binutils. When it has completed, just install it: $ make installPlease note: you will not ever need root access on the host system during this process (provided that the system has sufficient user-writable disk space). If you install into a public location as root, you are on your own. If you do so and make a mistake you can destroy your host system. This is especially true of the glibc install. The next step is building gcc. This should be fairly straightforward as well. Please note that you should not use gcc 2.95.x, and you cannot use egcs < 1.0.2. I recommend using the 3.2 or 3.3 CVS tree, despite some lingering issues. Before going on, it's a good idea to add a PATH entry for your new development tools. $ PATH=$PATH:/s/crossdev/binNow build gcc. $ cd ../gcc-000622-build $ AR=mips-linux-ar RANLIB=mips-linux-ranlib ../gcc-000622/configure --prefix=/s/crossdev --target=mips-linux --with-newlib --disable-threads --disable-shared $ make -C libiberty LANGUAGES=c MAKE="make -j3" $ make -C gcc LANGUAGES=c MAKE="make -j3"The use of --disable-threads and --disable-shared is only needed the first time you build a gcc (eg before you have glibc built). Now install gcc (the build should have worked; if not you may have found a gcc bug): $ make -C libiberty install LANGUAGES=c $ make -C gcc install LANGUAGES=cYou now have a basic cross-toolchain. The next step is to build glibc. However, in order to do that you will need some headers from the kernel. Specifically, the include/linux and include/asm-mips directories. We also need include/linux/version.h so we will need to unpack the kernel and configure it. Since we're going to do this anway, we might as well put off building glibc and just build a kernel. We already have sufficient tools to do so (glibc is not needed to build kernels). When you configure your kernel, I recommend not adding much of anything. If you do, your kernel may not boot. You can probably remove features you know you won't need. Make sure you don't disable kernel-level autoconfig or root fs on NFS as you will need them later. $ cd ../linux $ make menuconfig $ make dep boot MAKE="make -j3" CROSS_COMPILE=mips-linux-And copy the headers: $ cd include $ mkdir /s/crossdev/mips-linux/include $ cp -rd linux /s/crossdev/mips-linux/include $ cp -rd asm-mips /s/crossdev/mips-linux/include $ cp -rd asm-generic /s/crossdev/mips-linux/include $ mv /s/crossdev/mips-linux/include/asm-mips /s/crossdev/mips-linux/include/asmSave your ELF and ECOFF kernels (/s/crossdev-build/linux/vmlinux and /s/crossdev-build/linux/arch/mips/boot/vmlinux.ecoff) in a safe place for later; we'll use them to boot your system. Now we can build glibc. $ cd ../glibc-000622-build $ AR=mips-linux-ar RANLIB=mips-linux-ranlib CC=mips-linux-gcc HOST_CC=cc BUILD_CC=cc ../glibc-000622/configure --prefix=/usr --host=mips-linux --enable-add-ons --with-elf --disable-profile --with-headers=/s/crossdev/mips-linux/include $ makeNow install glibc. It's important to get this right - if you don't give the right arguments, it will try (and hopefully fail) to overwrite your system's native libraries. $ mkdir ../glibc-000622-inst $ make install install_root=/s/crossdev-build/glibc-000622-instNow we need to use this glibc for two things: To cross-compile against, and to use natively. To get the native set, we just want a full image of the installation: $ cd /s/crossdev-build/glibc-000622-inst $ tar czf ../glibc-000622-inst.tar.gz .Later on we'll extract this into our new root filesystem. To get the cross-build library set up, just copy the libraries and headers into the cross-compiler's search path: $ cd lib && find . -print | cpio -pumd /s/crossdev/mips-linux/lib $ cd ../usr/lib && find . -print | cpio -pumd /s/crossdev/mips-linux/lib $ cd ../include && find . -print | cpio -pumd /s/crossdev/mips-linux/includeThat should conclude Phase 1. You are now ready to build native programs. |
Phase 2: the native core |
| We now use our cross toolchain to build a set of utilities sufficient for building programs natively on ice. This set generally includes a C compiler, binutils, fileutils, textutils, diffutils, sh-utils, grep, sed, make, tar, gzip, and util-linux. You may want additional packages, but remember that our goal is to build just enough that we can then build natively whatever we wish. |
In the list above, there are three major classes of
packages: gcc, util-linux, and everything else. The
"everything else" list will generally build all in the same
fashion, and will do so fairly cleanly. For these packages,
use the following build commands:
$ CC=mips-linux-gcc AR=mips-linux-ar RANLIB=mips-linux-ranlib LD=mips-linux-ld BUILD_CC=cc HOST_CC=cc CC_FOR_BUILD=cc CFLAGS="-I/s/crossdev/mips-linux/include" ./configure --prefix=/usr --disable-largefile $ make $ make install prefix=/s/crossdev-build/native/package-name/usr $ cd /s/crossdev-build/native/package-name $ tar czf ../package-name.tar.gz .Note that you can adjust the --prefix argument to reflect the location you want the programs to live in. You need --disable-largefile for the moment; once the remaining issues with stat64 and friends are worked out that argument will no longer be necessary. Some of these packages' configure script will fail with an error about setvbuf while cross-compiling. You can resolve this problem by placing the following line into config.cache:
ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed=no}
Again, note that you need not and should not install as
root, except for the sh-utils package, which wants to setuid
the passwd program. Make very sure you properly specify the
prefix= variable when installing; otherwise native programs
may be overwritten.
|
Unfortunately, gcc and util-linux are trickier. Util-linux
was never really meant to be cross-compiled, and it's a
portability nightmare anyway. Nevertheless, I've put
together a
patch that allows this. Note that there are other
patches for util-linux available there; I recommend you get
and apply them all. Once you've done this, actually building
util-linux should be pretty straightforward.
$ CC=mips-linux-gcc AR=mips-linux-ar RANLIB=mips-linux-ranlib CFLAGS="-I/s/crossdev/mips-linux/include -I../lib -I. -O2" ./configure $ make CC=mips-linux-gcc AR=mips-linux-ar RANLIB=mips-linux-ranlib CFLAGS="-I/s/crossdev/mips-linux/include -I../lib -I. -O2" $ make CC=mips-linux-gcc AR=mips-linux-ar RANLIB=mips-linux-ranlib CFLAGS="-I/s/crossdev/mips-linux/include -I../lib -I. -O2" install DESTDIR=/s/crossdev-build/native/ul-inst $ cd /s/crossdev-build/native/ul-inst/bin $ mv * ../usr/bin $ cd .. $ rmdir bin $ tar czf ../util-linux.tar.gz .Building gcc used to be the worst part of all. This method seems to work well, however, and if you use sufficiently new versions it should steer you away from trouble. Don't forget to patch the sources as above. $ CC="mips-linux-gcc -I/scratch/crossdev/mips-linux/mips-linux/include" CC_FOR_BUILD=cc GCC_FOR_TARGET="mips-linux-gcc -I/s/crossdev/mips-linux/include" AR=mips-linux-ar RANLIB=mips-linux-ranlib LD=mips-linux-ld ../egcs-000703/configure --prefix=/usr --enable-threads --enable-languages=c --host=mips-linux --target=mips-linux --build=`../egcs-000703/config.guess` $ make $ make install prefix=/s/crossdev-build/native/gcc/usr $ cd /s/crossdev-build.native/gcc $ tar xzvf ../gcc.tar.gz .At least with the versions described within, several files will not be compiled correctly; they will fail to assemble. You can work around this by waiting for these files to come up, adding -Os to the CFLAGS variable, compiling that file, then killing the build process, removing -Os, and continuing. Note that building with -Os takes much longer than normal building. Hopefully this problem will be fixed soon. The last thing you will need is a statically linked copy of bash. I recommend obtaining one from the several available distributions. At this point you should extract the glibc package from phase 1 and all the native packages from phase 2 into a directory on your NFS server, for use as a root filesystem. You can do this as follows, assuming your NFS-exported directory will be called /nfs: $ cd /nfs $ tar xzvf /s/crossdev-build/glibc-000622-inst/glibc-000622-inst.tar.gz $ tar xzvf /s/crossdev-build/native/pacakge-name.tar.gz ... $ cp /tmp/static-bash usr/bin/bash $ cd bin $ mv * ../usr/bin $ cd .. $ rmdir bin $ ln -s usr/bin bin $ mkdir procYou will also need to acquire a /dev/tree from somewhere, or use mknod to create a few required entries. This should set up an appropriate root filesystem to start with. Boot the kernel built in phase 1 using this root filesystem (the details of doing this are outside the scope of this document but may be found in the Simple Linux/MIPS installation HOWTO). Don't forget to use the init=/bin/bash option, since init isn't set up or available yet. If all goes well, you should get a shell prompt. At this point I recommend you follow the basic directions on setting up your system to boot from its own disk as found in the aforementioned HOWTO. Note that you will need to obtain or write your own init scripts, and move /sbin/simpleinit to /sbin/init, and possibly do other things as well. Once your system is up and running from local disk, you should add a non-root account for yourself and give yourself a home directory with at least a few hundred MB free. When your non-root account is working, you're ready to proceed to phase 3. |
Phase 3: The spit and polish |
| Nowhere else will you see critical system components like the init scripts termed "mere spit and polish." The parts of the system you have built so far are, if you're lucky, sufficient to have a working development environment - that is, to complete the bootstrap procedure. Thus your taska at this point involve building native versions of all the software you want to use. This is usually easier than cross-building, so I will not go into details here. Consult the documentation that comes with each piece of software you want to use. |