Building Static Compilation Environments

Download Bootable CD (262MB)

Roadmap
The GCC/Linux developer community is sold on shared library executables. They like shared libraries due to the reduced memory and disk footprints, as well as the concept that upgrading one shared library eventually automatically upgrades all applications which use that library. Consequently, information on statically linked programs is rather sparse.

My most useful reference has been the LinuxFromScratch book, version 4-1 (http://www.linuxfromscratch.org). This book has detailed instructions on making a statically linked toolchain as the first part of their build process. The T2-project also has an emphasis on statically linked programs. I have not used their work as much as I wish. The BuildToolChain.cmd script I use here is based upon LinuxFromScratch.4-1, as well as a HLFS uClibC user note, for which I misplaced the credits, specifically regarding the obscure 'glob' Make options.

An alternative approach that I have also used, is to modify the specs preference file for the compiler collection to only create static executables regardless of user input. (This is the kludge approach.) I then build a new environment without any shared loader or libraries. At this point, I remove the modified specs, as all new compilation is satisfied by the static libraries created in the system. With the static specs file in place, we make standard static binaries. Without the specs file, using defaults, we create what is technically a shared executable (due to crtbegin.o elements, rather than crtbeginT.o), but without a dynamic section or dynamic loader. With modified specs in place, the Linux kernel does not build correctly. For my work environment, I usually have the modified specs file in place to force classically formed static executables. When compilation fails, I remove this file temporarily. However, for *this* distribution, we will use the starved shared library approach, which does not require attention (or presense) of the modified specs file.

Building the Toolchain

Actual script files to build the toolchain, and the various cpio.gz archives are on the CD in the /sources directory. Simple summary, make sure you have at least 4G hard drive space available on a Linux (not Windows or MacOS) drive, that you are booted off CD, that you see your hard drive as sda1 and the CD as sr0. The commands to build this system are then

# mkdir /mnt/cdrom
# mount /dev/sr0 /mnt/cdrom
# ln -s /mnt/cdrom/sources /source
# cd /mnt/sda1/root
# mkdir BuildZone
# cd BuildZone
# cp /sources/BuildGCCToolChain.cmd .
# cp /sources/AddInPerl .
# cp /sources/AddInModules .
# ./BuildGCCToolChain.cmd
# echo --- This is going to take some time. (I usually take an hour and running). 
# echo --- You will find Simplest.cpio.gz and StaticRamLinux.cpio.gz in /root
# ./AddInPerl
# echo --- This is pretty fast. Just a couple of minutes. You will find StaticRamLinuxWithPerl.cpio.gz in /root
# ./AddInModules
# echo --- This kernel image has a ton of drivers enabled. I plan about 40 minutes or so. Minimal kernels are much faster.
# echo --- You will find StaticRamLinuxWithPerlAndModules.cpio.gz in /root, as well as kernel-2.6.27.10 in /boot in the image.

When this is done, assuming no errors, you will have a StaticRamLinux directory in the BuildZone directory, and the various cpio.gz archives, and build debris around. The basic script with comments follows.

echo Build Static Linux Script   --  Kurt Nalty
echo
echo This is a script to build a statically linked busybox environment. The reference for this work is
echo LinuxFromScratch version 4.1
echo
echo I assume that the sources are at or linked to /sources.
echo
echo Here are commands which can be used to mount the cd and create the sources link
echo
echo mount /dev/sr0 /mnt/cdrom -t iso9660
echo ln -s /mnt/cdrom/sources /sources
echo


echo I am about to wipe out any StaticRamLinux folders at this location.
echo An error message indicating files not found is okay here.

rm -r StaticRamLinux

echo I am going to create a new StaticRamLinux husk folder here. 
echo This has directories, /etc and initialization scripts.
tar -xzf /sources/husk.tar.gz

echo I am copying the shell script to make the cpio.gz archive from the StaticRamLinux folder
cp /sources/makeStaticRamLinuxCpio .


echo I am going to extract and build busybox in this top directory. I assume static uclibc libraries are present.

tar -xjf /sources/busybox-1.14.1.tar.bz2
cd busybox-1.14.1
cp /sources/busybox-1.14.1.config .config
make

echo I am going to copy the executable into the StaticRamLinux image
cp busybox ../StaticRamLinux/bin/

echo I am going to create the busybox soft links


cd ../StaticRamLinux/bin
ln -s busybox ln
ln -s busybox [
ln -s busybox [[
ln -s busybox addgroup
ln -s busybox adduser
ln -s busybox adjtimex
ln -s busybox ar
ln -s busybox arp
ln -s busybox arping
ln -s busybox ash
ln -s busybox awk
ln -s busybox basename
ln -s busybox bbconfig
ln -s busybox blkid
ln -s busybox brctl
ln -s busybox bunzip2
ln -s busybox bzcat
ln -s busybox bzip2
ln -s busybox cal
ln -s busybox cat
ln -s busybox catv
ln -s busybox chat
ln -s busybox chattr
ln -s busybox chgrp
ln -s busybox chmod
ln -s busybox chown
ln -s busybox chpasswd
ln -s busybox chpst
ln -s busybox chroot
ln -s busybox chrt
ln -s busybox chvt
ln -s busybox cksum
ln -s busybox clear
ln -s busybox cmp
ln -s busybox comm
ln -s busybox cp
ln -s busybox cpio
ln -s busybox crond
ln -s busybox crontab
ln -s busybox cryptpw
ln -s busybox cttyhack
ln -s busybox cut
ln -s busybox date
ln -s busybox dc
ln -s busybox dd
ln -s busybox deallocvt
ln -s busybox delgroup
ln -s busybox deluser
ln -s busybox depmod
ln -s busybox devmem
ln -s busybox df
ln -s busybox dhcprelay
ln -s busybox diff
ln -s busybox dirname
ln -s busybox dmesg
ln -s busybox dnsd
ln -s busybox dos2unix
ln -s busybox du
ln -s busybox dumpkmap
ln -s busybox dumpleases
ln -s busybox echo
ln -s busybox ed
ln -s busybox egrep
ln -s busybox eject
ln -s busybox env
ln -s busybox envdir
ln -s busybox envuidgid
ln -s busybox ether-wake
ln -s busybox expand
ln -s busybox expr
ln -s busybox fakeidentd
ln -s busybox false
ln -s busybox fbset
ln -s busybox fbsplash
ln -s busybox fdflush
ln -s busybox fdformat
ln -s busybox fdisk
ln -s busybox fgrep
ln -s busybox find
ln -s busybox findfs
ln -s busybox fold
ln -s busybox free
ln -s busybox freeramdisk
ln -s busybox fsck
ln -s busybox fsck.minix
ln -s busybox ftpd
ln -s busybox ftpget
ln -s busybox ftpput
ln -s busybox fuser
ln -s busybox getopt
ln -s busybox getty
ln -s busybox grep
ln -s busybox gunzip
ln -s busybox gzip
ln -s busybox halt
ln -s busybox hd
ln -s busybox hdparm
ln -s busybox head
ln -s busybox hexdump
ln -s busybox hostid
ln -s busybox hostname
ln -s busybox httpd
ln -s busybox hwclock
ln -s busybox id
ln -s busybox ifconfig
ln -s busybox ifdown
ln -s busybox ifenslave
ln -s busybox ifup
ln -s busybox inetd
ln -s busybox init
ln -s busybox insmod
ln -s busybox install
ln -s busybox ip
ln -s busybox ipaddr
ln -s busybox ipcalc
ln -s busybox iplink
ln -s busybox iproute
ln -s busybox iprule
ln -s busybox iptunnel
ln -s busybox kbd_mode
ln -s busybox kill
ln -s busybox killall
ln -s busybox killall5
ln -s busybox klogd
ln -s busybox last
ln -s busybox length
ln -s busybox less
ln -s busybox linux32
ln -s busybox linux64
ln -s busybox linuxrc
ln -s busybox loadfont
ln -s busybox loadkmap
ln -s busybox logger
ln -s busybox login
ln -s busybox logname
ln -s busybox logread
ln -s busybox losetup
ln -s busybox lpd
ln -s busybox lpq
ln -s busybox lpr
ln -s busybox ls
ln -s busybox lsattr
ln -s busybox lsmod
ln -s busybox lzmacat
ln -s busybox makedevs
ln -s busybox makemime
ln -s busybox man
ln -s busybox md5sum
ln -s busybox mdev
ln -s busybox mesg
ln -s busybox microcom
ln -s busybox mkdir
ln -s busybox mkdosfs
ln -s busybox mkfifo
ln -s busybox mkfs.minix
ln -s busybox mkfs.vfat
ln -s busybox mknod
ln -s busybox mkpasswd
ln -s busybox mkswap
ln -s busybox mktemp
ln -s busybox modprobe
ln -s busybox more
ln -s busybox mount
ln -s busybox mountpoint
ln -s busybox mt
ln -s busybox mv
ln -s busybox nameif
ln -s busybox nc
ln -s busybox netstat
ln -s busybox nice
ln -s busybox nmeter
ln -s busybox nohup
ln -s busybox nslookup
ln -s busybox od
ln -s busybox openvt
ln -s busybox passwd
ln -s busybox patch
ln -s busybox pgrep
ln -s busybox pidof
ln -s busybox ping
ln -s busybox ping6
ln -s busybox pipe_progress
ln -s busybox pivot_root
ln -s busybox pkill
ln -s busybox popmaildir
ln -s busybox poweroff
ln -s busybox printenv
ln -s busybox printf
ln -s busybox ps
ln -s busybox pscan
ln -s busybox pwd
ln -s busybox raidautorun
ln -s busybox rdate
ln -s busybox rdev
ln -s busybox readahead
ln -s busybox readlink
ln -s busybox readprofile
ln -s busybox realpath
ln -s busybox reboot
ln -s busybox reformime
ln -s busybox renice
ln -s busybox reset
ln -s busybox resize
ln -s busybox rm
ln -s busybox rmdir
ln -s busybox rmmod
ln -s busybox route
ln -s busybox rtcwake
ln -s busybox run-parts
ln -s busybox runlevel
ln -s busybox runsv
ln -s busybox runsvdir
ln -s busybox rx
ln -s busybox script
ln -s busybox sed
ln -s busybox sendmail
ln -s busybox seq
ln -s busybox setarch
ln -s busybox setconsole
ln -s busybox setfont
ln -s busybox setkeycodes
ln -s busybox setlogcons
ln -s busybox setsid
ln -s busybox setuidgid
ln -s busybox sh
ln -s busybox sha1sum
ln -s busybox sha256sum
ln -s busybox sha512sum
ln -s busybox showkey
ln -s busybox slattach
ln -s busybox sleep
ln -s busybox softlimit
ln -s busybox sort
ln -s busybox split
ln -s busybox start-stop-daemon
ln -s busybox stat
ln -s busybox strings
ln -s busybox stty
ln -s busybox su
ln -s busybox sulogin
ln -s busybox sum
ln -s busybox sv
ln -s busybox svlogd
ln -s busybox swapoff
ln -s busybox swapon
ln -s busybox switch_root
ln -s busybox sync
ln -s busybox sysctl
ln -s busybox syslogd
ln -s busybox tac
ln -s busybox tail
ln -s busybox tar
ln -s busybox tcpsvd
ln -s busybox tee
ln -s busybox telnet
ln -s busybox telnetd
ln -s busybox test
ln -s busybox tftp
ln -s busybox tftpd
ln -s busybox time
ln -s busybox timeout
ln -s busybox top
ln -s busybox touch
ln -s busybox tr
ln -s busybox traceroute
ln -s busybox true
ln -s busybox tty
ln -s busybox ttysize
ln -s busybox tunctl
ln -s busybox udhcpc
ln -s busybox udhcpd
ln -s busybox udpsvd
ln -s busybox umount
ln -s busybox uname
ln -s busybox uncompress
ln -s busybox unexpand
ln -s busybox uniq
ln -s busybox unix2dos
ln -s busybox unlzma
ln -s busybox unzip
ln -s busybox uptime
ln -s busybox usleep
ln -s busybox uudecode
ln -s busybox uuencode
ln -s busybox vconfig
ln -s busybox vi
ln -s busybox vlock
ln -s busybox watch
ln -s busybox watchdog
ln -s busybox wc
ln -s busybox wget
ln -s busybox which
ln -s busybox who
ln -s busybox whoami
ln -s busybox xargs
ln -s busybox yes
ln -s busybox zcat
ln -s busybox zcip


cd ../..

echo I am going to make the Simplest.cpio.gz archive
./makeStaticRamLinuxCpio
mv /root/StaticRamLinux.cpio.gz /root/Simplest.cpio.gz
echo
echo /root/Simplest.cpio.gz is now ready.


echo We begin by getting the Linux 2.6.27.10 headers
tar -xjf /sources/linux-2.6.27.10.tar.bz2
cd linux-2.6.27.10
make headers_install
cp -rd usr/include ../StaticRamLinux/usr
cd ..
rm -r linux-2.6.27.10

echo
echo Now we compile uClibC, and install libraries and headers
tar -xjf /sources/uClibc-0.9.30.1.tar.bz2 
cp /sources/uClibc-0.9.30.1.config uClibc-0.9.30.1/.config
cd uClibc-0.9.30.1
make
make install
cd ..
cp -rd /usr/i386-linux-uclibc/usr/include/* StaticRamLinux/usr/include
cp -rd /usr/i386-linux-uclibc/usr/lib/* StaticRamLinux/lib
rm -r /usr/i386-linux-uclibc
rm -r uClibc-0.9.30.1

echo
echo Now we make 'make' , so that we can install within our chroot environment
tar -xjf /sources/make-3.81.tar.bz2
cd make-3.81
 env make_cv_sys_gnu_glob="no" GLOBINC=-I`pwd`/glob \
      GLOBLIB=glob/libglob.a \
      ./configure --prefix=/usr LDFLAGS="-static -s"

make
cp make ../StaticRamLinux/bin
cd ..



echo 
echo Now we make zlib. 
tar -xjf /sources/zlib-1.2.3.tar.bz2
cd zlib-1.2.3
./configure --disable-shared --enable-static
make
mv libz.a ../StaticRamLinux/lib
mv zlib.h ../StaticRamLinux/usr/include
mv zconf.h ../StaticRamLinux/usr/include
cd ..

echo
echo Now we make ncurses
tar -xzf /sources/ncurses-5.7.tar.gz
cd ncurses-5.7
./configure --disable-nls --disable-shared --enable-static --without-cxx \
--without-cxx-bindings --without-ada --without-progs --prefix=/usr --includedir=/usr/include/ncurses \
--without-libtool --without-gpm --without-dlsym --with-database=/usr/share/terminfo

make
cp lib/*.a ../StaticRamLinux/lib
mkdir ../StaticRamLinux/usr/include/ncurses
cp include/curses.h ../StaticRamLinux/usr/include/ncurses/
cp include/eti.h ../StaticRamLinux/usr/include/ncurses/
cp include/form.h ../StaticRamLinux/usr/include/ncurses/
cp include/menu.h ../StaticRamLinux/usr/include/ncurses/
cp include/ncurses_dll.h ../StaticRamLinux/usr/include/ncurses/
cp include/panel.h ../StaticRamLinux/usr/include/ncurses/
cp include/term.h ../StaticRamLinux/usr/include/ncurses/
cp include/termcap.h ../StaticRamLinux/usr/include/ncurses/
cp include/unctrl.h ../StaticRamLinux/usr/include/ncurses/
ln -s ../StaticRamLinux/usr/include/ncurses/ncurses.h ../StaticRamLinux/usr/include/ncurses/curses.h
cd ..

echo
echo Now we make bison
tar -xjf /sources/bison-2.3.tar.bz2
cd bison-2.3
LDFLAGS="-static -s" ./configure --disable-nls --disable-shared --enable-static
make
cp src/bison ../StaticRamLinux/bin
cd ..

echo
echo Now we make flex
tar -xjf /sources/flex-2.5.35.tar.bz2
cd flex-2.5.35
LDFLAGS="-static -s" ./configure --disable-nls --disable-shared --enable-static
make
cp flex ../StaticRamLinux/bin
cd ..

echo
echo Now we make M4
tar -xjf /sources/m4-1.4.12.tar.bz2
cd m4-1.4.12
LDFLAGS="-static -s" ./configure --disable-nls --disable-shared --enable-static
make
cp src/m4 ../StaticRamLinux/bin
cd ..

echo
echo Now we make gawk
tar -xjf /sources/gawk-3.1.6.tar.bz2
cd gawk-3.1.6
LDFLAGS="-static -s" ./configure --disable-nls --disable-shared --enable-static
make
cp gawk ../StaticRamLinux/bin
cd ..

echo
echo Now we make binutils
tar -xjf /sources/binutils-2.19.1.tar.bz2
cd binutils-2.19.1
LDFLAGS="-static -s" ./configure --disable-nls --disable-shared --enable-static
make

rm ../StaticRamLinux/bin/addr2line
rm ../StaticRamLinux/bin/ar
rm ../StaticRamLinux/bin/as
rm ../StaticRamLinux/bin/c++filt
rm ../StaticRamLinux/bin/gprof
rm ../StaticRamLinux/bin/ld
rm ../StaticRamLinux/bin/nm
rm ../StaticRamLinux/bin/objcopy
rm ../StaticRamLinux/bin/objdump
rm ../StaticRamLinux/bin/ranlib
rm ../StaticRamLinux/bin/readelf
rm ../StaticRamLinux/bin/size
rm ../StaticRamLinux/bin/strings
rm ../StaticRamLinux/bin/strip

cp binutils/addr2line ../StaticRamLinux/bin/addr2line
cp binutils/ar ../StaticRamLinux/bin/ar
cp gas/as-new ../StaticRamLinux/bin/as
cp binutils/cxxfilt ../StaticRamLinux/bin/c++filt
cp gprof/gprof ../StaticRamLinux/bin/gprof
cp ld/ld-new ../StaticRamLinux/bin/ld
cp binutils/nm-new ../StaticRamLinux/bin/nm
cp binutils/objcopy ../StaticRamLinux/bin/objcopy
cp binutils/objdump ../StaticRamLinux/bin/objdump
cp binutils/ranlib ../StaticRamLinux/bin/ranlib
cp binutils/readelf ../StaticRamLinux/bin/readelf
cp binutils/size ../StaticRamLinux/bin/size
cp binutils/strip-new ../StaticRamLinux/bin/strip

cd ..

echo
echo we need to install two libraries. gmp and mpfr. 
echo making gmp
tar -xjf /sources/gmp-4.3.1.tar.bz2
cd gmp-4.3.1
./configure --disable-shared --enable-static
make
make install
cp .libs/libgmp.a ../StaticRamLinux/lib/
cp gmp.h ../StaticRamLinux/usr/include/
cd ..

echo
echo making mpfr
tar -xjf /sources/mpfr-2.4.1.tar.bz2
cd mpfr-2.4.1
./configure --disable-shared --enable-static
make
make install
cp .libs/libmpfr.a ../StaticRamLinux/lib
cp mpfr.h ../StaticRamLinux/usr/include
cp mpf2mpfr.h ../StaticRamLinux/usr/include
cd ..


echo
echo Now we make GCC
tar -xjf /sources/gcc-4.3.3.tar.bz2
mkdir gcc-build
cd gcc-build
BOOT_LDFLAGS="-static" LDFLAGS="-static" ../gcc-4.3.3/configure \
--prefix=/gcc-uclibc \
--build=i686-pc-linux-uclibc \
--host=i686-pc-linux-uclibc \
--target=i686-pc-linux-uclibc \
--enable-languages=c,c++,fortran \
--disable-__cxa_atexit \
--with-gnu-ld \
--disable-shared \
--disable-nls \
--enable-threads \
--disable-multilib \
--disable-decimal-float \
--with-arch=i686 \
--with-tune=i686 \
--disable-largefile

BOOT_LDFLAGS="-static" make
make install

strip -s /gcc-uclibc/libexec/gcc/i686-pc-linux-uclibc/4.3.3/*
cp -rd /gcc-uclibc ../StaticRamLinux
cd ../StaticRamLinux/bin
ln -s ../gcc-uclibc/bin/i686-pc-linux-uclibc-gcc-4.3.3 gcc
ln -s ../gcc-uclibc/bin/i686-pc-linux-uclibc-gcc-4.3.3 cc
ln -s ../gcc-uclibc/bin/i686-pc-linux-uclibc-g++ g++
ln -s ../gcc-uclibc/bin/i686-pc-linux-uclibc-g++ c++
ln -s ../gcc-uclibc/bin/i686-pc-linux-uclibc-gfortran gfortran
ln -s ../gcc-uclibc/bin/i686-pc-linux-uclibc-gfortran fortran

echo done making gcc

cd ../../

echo I am going to make the StaticRamLinux.cpio.gz archive
./makeStaticRamLinuxCpio
echo
echo /root/StaticRamLinux.cpio.gz is now ready.

At this point, we now have a working toolchain, both on the hard drive in the StaticRamLinux folder, as well as in the StaticRamLinux.cpio.gz archive, suited for ram disk booting. For my routine casual programming, this is all I really need. I am appalled at a simple toolchain requiring 30M compressed, as compared to basic utilities fitting in 500K compressed. (TCC, lua, ACK are all worthy alternatives.) My belief is that we have such a general set of tools in GCC, reflecting such a huge number of years of contributed labor. However, I trust much simpler systems more than this complicated behemoth. I like GCC for the ability to run on so many architectures. I like the multiplicity of languages, and the optimizations. I just wish it fit on a 1.4MB floppy.

Imagine, now, how I feel about the add-on bloat of Perl and Python!

Perl
Perl, like GCC, has bloated with the cumulative work of large numbers of volunteers, The executables are now about 3MB, with about 50MB of supporting scripts. Unfortunately, Perl is now required for Linux kernel compilation. This is a shame, especially when there are Perl2C translators which could convert the developer's Perl to standard C. This perl bloat really irritates me when I want to use a native toolchain on a memory constrained device. Anyway, here we are adding Perl to StaticRamLinux. We will expand the perl archive in the target space, then compile Perl using the new compiler via a chroot script - BuildPerl.

cd StaticRamLinux/root
tar -xzf /sources/perl-5.10.0.tar.gz
cd ..
mount -t proc proc proc
mount -t sysfs sysfs sys
cp /sources/BuildPerl .
chroot . ./BuildPerl 
umount proc
umount sys
rm -r root/perl-5.10.0
rm BuildPerl
find | cpio --format=newc -o | gzip > /root/StaticRamLinuxWithPerl.cpio.gz
cd ..

BuildPerl Chroot Script
Here is the BuildPerl script.

cd /root/perl-5.10.0
sh Configure -de -Dprefix=/usr
make
make install
exit

At this point, we have the ability to rebuild the kernel, as well as all essential toolframe utilities. In /root, we have Simplest.cpio.gz (471.1K), StaticRamLinux.cpio.gz (22.9M), and StaticRamLinuxWithPerl.cpio.gz (34.8M). Our next step is to build the module set for linux, as well as the udev autoload utility, and finally the cdrecord tools to allow creation of iso images and burning of CDROMs, completing the task of making a self-replicatible minimal toolchain from source code.

Modules, udev, grub, and cdrecord utilities
We build the kernel, and install the modules inside our chroot StaticRamLinux environment. We remove the source files from the environment before making the archive. My goal is to minimize the size of the Linux kernel by only selecting the hardware drivers required for the customer systems, and incorporating these modules in the kernel. I ordinarily do not compile the kernel with module support, which closes a number of interesting rootkit vectors. In terms of identifying hardware, the lscpi program from pciutils is very nice. The hwinfo program from Debian is far more detailed, but I was unable to compile a static version of the current hwinfo program by presstime. The udev program is a rapidly evolving piece of software. I have a dated copy 113, used here for the simplicity of this earlier version.

cd StaticRamLinux/root
tar -xjf /sources/linux-2.6.27.10.tar.bz2
cp /sources/linux-2.6.27.10.config linux-2.6.27.10/.config
tar -xzf /sources/udev-113.tar.gz
tar -xzf /sources/pciutils-3.1.3.tar.gz
tar -xjf /sources/cdrtools-2.01.tar.bz2
tar -xzf /sources/grub-0.97.tar.gz
cd ..
mount -t proc proc proc
mount -t sysfs sysfs sys
cp /sources/BuildModules .
chroot . ash BuildModules 
cp /sources/26-modprobe.rules etc/udev/rules.d
umount proc
umount sys
cp root/linux-2.6.27.10/arch/x86/boot/bzImage boot/kernel-2.6.27.10
rm -r root/linux-2.6.27.10
rm -r root/udev-113
rm -r root/pciutils-3.1.3
rm -r root/cdrtools-2.01
rm -r root/grub-0.97
rm BuildModules
find | cpio --format=newc -o | gzip > /root/StaticRamLinuxWithPerlAndModules.cpio.gz
cd ..

The interior script file BuildModules follows
cd /root/linux-2.6.27.10
make
make modules_install
depmod
cd ../udev-113
make
make install
cd ../pciutils-3.1.3
make install
mv /usr/local/sbin/lspci /bin
cd ../cdrtools-2.01
make
cp mkisofs/OBJ/i686-linux-cc/mkisofs /bin
cp cdrecord/OBJ/i686-linux-cc/cdrecord /bin
cd ../grub-0.97
./configure --without-curses
make
make install
mkdir /boot
mkdir /boot/grub
cp /usr/local/lib/grub/i386-pc/* /boot/grub
cp /usr/local/sbin/grub /boot/grub/grub
rm -r /usr/local/lib/grub
exit


We've built the grub bootloader, and placed its collection of files in a new boot directory, which also got a courtesy copy of the linux kernel (as kernel-2.6.27.10 to be distinct from the distribution linux-2.6.27.10).

To use udev, boot the machine in the StaticRamLinuxWithPerAndModules option, then issue the commands

lspci                             # just for your information. Not really needed.
lsmod                             # no modules should be initially loaded.
echo > /proc/sys/kernel/hotplug   # ordinarily, I have mdev as a hotplug helper. Remove mdev from that task. Let udevd take over.
udevd --daemon                    # this starts the udevd
udevtrigger                       # this generates coldplug trigger events for most modules. They either get loaded or rejected
udevsettle                        # this just hangs the machine until all trigger events are processed.
lsmod                             # here is the list of the actual modules your machine needs. When you rebuild your kernel, include
                                  # these and turn off modules and other unwanted modules. The finished kernel should be under 3M compressed.
Since this distribution is via CDROM images, we need to include the iso generation software to complete the set. To generate a new CD image, make a folder (I use iso), stuff it per your wishes, and make a grub iso image with
 mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \
         -boot-load-size 4 -boot-info-table -o grub.iso iso

Studying the specs and machinedump files
As mentioned at the start of this document, one method of forcing the GCC compilers to produce static linked code by default is to modify the specs file. The specs file is ordinarily not present on machines. Instead, a compiled in version of defaults is used.

To see these defaults, issue the command

gcc -dumpspecs > specs

Specs files are intended as a machine friendly, user hostile method of indicating preferences for GCC operation. In the specs file, we find details such as run time files, termination files, default gcc files, how to profile programs, etc. I have a courtesy copy of the GCC manual documentation in the cd in /sources/Spec-Files-4.2.0.html.

This file varies between versions of GCC, and target machines. The specs used with GCC-4.3.3 on a i686-linux-pc-gnu environment is

*asm:
%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}

*asm_debug:
%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}} %{fdebug-prefix-map=*:--debug-prefix-map %*}

*asm_final:


*asm_options:
%{--target-help:%:print-asm-header()} %a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}

*invoke_as:
%{!S:-o %|.s |
 as %(asm_options) %|.s %A }

*cpp:
%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}

*cpp_options:
%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w} %{f*} %{g*:%{!g0:%{!fno-working-directory:-fworking-directory}}} %{O*} %{undef} %{save-temps:-fpch-preprocess}

*cpp_debug_options:
%{d*}

*cpp_unique_options:
%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{fmudflap:-D_MUDFLAP -include mf-runtime.h} %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h} %{E|M|MM:%W{o*}}

*trad_capable_cpp:
cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}

*cc1:
%(cc1_cpu) %{profile:-p}

*cc1_options:
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{--help=*:--help=%(VALUE)} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants} %{coverage:-fprofile-arcs -ftest-coverage}

*cc1plus:


*link_gcc_c_sequence:
%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}

*link_ssp:
%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}

*endfile:
%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s}    %{mpc32:crtprec32.o%s}    %{mpc64:crtprec64.o%s}    %{mpc80:crtprec80.o%s}    %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s

*link:
%{!static:--eh-frame-hdr} -m %(link_emulation) %{shared:-shared}   %{!shared:     %{!ibcs:       %{!static: 	%{rdynamic:-export-dynamic} 	%{!dynamic-linker:-dynamic-linker %(dynamic_linker)}} 	%{static:-static}}}

*lib:
%{pthread:-lpthread}    %{shared:-lc}    %{!shared:%{mieee-fp:-lieee} %{profile:-lc_p}%{!profile:-lc}}

*mfwrap:
 %{static: %{fmudflap|fmudflapth:  --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc --wrap=mmap --wrap=munmap --wrap=alloca} %{fmudflapth: --wrap=pthread_create}} %{fmudflap|fmudflapth: --wrap=main}

*mflib:
%{fmudflap|fmudflapth: -export-dynamic}

*link_gomp:


*libgcc:
-lgcc

*startfile:
%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}}    crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}

*switches_need_spaces:


*cross_compile:
0

*version:
4.3.3

*multilib:
. ;

*multilib_defaults:


*multilib_extra:


*multilib_matches:


*multilib_exclusions:


*multilib_options:


*linker:
collect2

*link_libgcc:
%D

*md_exec_prefix:


*md_startfile_prefix:


*md_startfile_prefix_1:


*startfile_prefix_spec:


*sysroot_spec:
--sysroot=%R

*sysroot_suffix_spec:


*sysroot_hdrs_suffix_spec:


*cc1_cpu:
%{mcpu=*:-mtune=%* %n`-mcpu=' is deprecated. Use `-mtune=' or '-march=' instead.
} %
We work our way through this file, assessing the logic for static, !static, shared, !shared, and find a simplified logic where we only have static, no shared.

As an example,

*startfile:
%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}}    crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}

becomes
*startfile:
%{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}    crti.o%s crtbeginT.o%s 


I find that the gcc -v command is also helpful for checking that the logic simplification matches. For example, compare the 'gcc -v hello.c' results against 'gcc -v -static hello.c' to verify that the correct files are being used.
*asm:
%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}

*asm_debug:
%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}

*asm_final:


*asm_options:
%{--target-help:%:print-asm-header()} %a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}

*invoke_as:
%{!S:-o %|.s |
 as %(asm_options) %|.s %A }

*cpp:
%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}

*cpp_options:
%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w} %{f*} %{g*:%{!g0:%{!fno-working-directory:-fworking-directory}}} %{O*} %{undef} %{save-temps:-fpch-preprocess}

*cpp_debug_options:
%{d*}

*cpp_unique_options:
%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{fmudflap:-D_MUDFLAP -include mf-runtime.h} %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h} %{E|M|MM:%W{o*}}

*trad_capable_cpp:
cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}

*cc1:
%(cc1_cpu) %{profile:-p}

*cc1_options:
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{--help=*:--help=%(VALUE)} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants} %{coverage:-fprofile-arcs -ftest-coverage}

*cc1plus:


*link_gcc_c_sequence:
--start-group %G %L --end-group

*link_ssp:
%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}

*endfile:
%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s}    %{mpc32:crtprec32.o%s}    %{mpc64:crtprec64.o%s}    %{mpc80:crtprec80.o%s}  crtend.o%s crtn.o%s 

*link:
 -m %(link_emulation) %{!ibcs:  -static}

*lib:
%{pthread:-lpthread}    %{mieee-fp:-lieee} %{profile:-lc_p}%{!profile:-lc}

*mfwrap:
 %{fmudflap|fmudflapth:  --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc --wrap=mmap --wrap=munmap --wrap=alloca} %{fmudflapth: --wrap=pthread_create} %{fmudflap|fmudflapth: --wrap=main}

*mflib:
%{fmudflap|fmudflapth: -export-dynamic}

*link_gomp:


*libgcc:
-lgcc

*startfile:
%{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}    crti.o%s crtbeginT.o%s 

*switches_need_spaces:


*cross_compile:
0

*version:
4.3.3

*multilib:
. ;

*multilib_defaults:


*multilib_extra:


*multilib_matches:


*multilib_exclusions:


*multilib_options:


*linker:
collect2

*link_libgcc:
%D

*md_exec_prefix:


*md_startfile_prefix:


*md_startfile_prefix_1:


*startfile_prefix_spec:


*sysroot_spec:
--sysroot=%R

*sysroot_suffix_spec:


*sysroot_hdrs_suffix_spec:


*cc1_cpu:
%{mcpu=*:-mtune=%* %n`-mcpu=' is deprecated. Use `-mtune=' or '-march=' instead.
} %
A copy of a static specs file for gcc 4.3.3 i686 is in the sources directory of the CD. To use this, place the file in the obscure location /usr/local/lib/gcc/i686-pc-linux-gnu/4.3.3/ if you are using a conventional default gcc location, or /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/ if you are using a large distro, or /gcc-build/lib/gcc/i686-pc-linux-gnu/4.3.3/ if you are using this toolchain. When you next gcc -v hello.c, you should see a message about using specs from the above location.