#!/bin/bash # Set up a known host environment, providing known versions of all required # prerequisites, built from source. # This script serves a similar purpose to the temporary chroot system in # Linux From Scratch chapter 5, isolating the new build from the host system # so information from the host doesn't accidentally leak into the target. # This script populates a build/host directory with busybox and symlinks to # the host's toolchain, then adds the other packages (genext2fs, e2fsprogs, # squashfs-tools, distcc, and qemu) that might be needed to package and run # a system image. This lets the rest of the build run with the $PATH pointing # at the new build/host directory and nothing else. # The tools provided by this stage are as similar as possible to the ones # provided in the final system image. The fact the system can build under # these tools is a good indication that it should be able to rebuild itself # under itself. # This script is optional. The build runs fine without it, assuming the # host has all the necessary packages installed and doesn't have any extra # packages (such as libtool, pkg-config, python...) that might provide # false information to autoconf or attach themselves as dependencies to # the newly generated programs. (In practice, this can be quite fiddly.) setglobal SAVEPATH = $PATH source sources/include.sh || exit 1 setglobal STAGE_DIR = $(HOSTTOOLS) # Blank $WORK but accept $STAGE_DIR if it exists. Re-running this script # should be a NOP. blank_tempdir $WORK mkdir -p $STAGE_DIR || dienow # Populate a directory with host versions of all the command line utilities # we're going to install into root-filesystem. When we're done, PATH can be # set to include just this directory and nothing else. # This serves three purposes: # # 1) Enumerate exactly what we need to build the system, so we can make sure # root-filesystem has everything it needs to rebuild us. If anything is # missing from this list, the resulting root-filesystem probably won't have # it either, so it's nice to know as early as possible that we actually # needed it. # # 2) Quick smoke test that the versions of the tools we're using can compile # everything from source correctly, and thus root-filesystem should be able # to rebuild from source using those same tools. # # 3) Reduce variation from distro to distro. The build always uses the # same command line utilities no matter where we're running, because we # provide our own. # Use the new tools we build preferentially, as soon as they become # available. setglobal PATH = ""$[hosttools_path]:$PATH"" # Sanity test for the host supporting static linking. if test $BUILD_STATIC != none { $CC "$SOURCES/root-filesystem/src/hello.c" --static -o /dev/null if test $Status -ne 0 { echo "Your host toolchain does not support static linking." > !2 echo "Either install support, or export BUILD_STATIC=none" > !2 dienow } } # Start by building busybox. We have no idea what strange things our host # system has (or lacks, such as "which"), so throw busybox at it first # thing. # Building packages with hush breaks stuff. Symlink host sh until toysh ready test ! -f "$STAGE_DIR/busybox" && build_section busybox && rm -f "$STAGE_DIR/sh" test ! -f "$STAGE_DIR/toybox" && build_section toybox # Create symlinks to the host toolchain. We need a usable existing host # toolchain in order to build anything else (even a new host toolchain), # and we don't really want to have to care what the host type is, so # just use the toolchain that's already there. # This is a little more complicated than it needs to be, because the host # toolchain may be using ccache and/or distcc, which means we need every # instance of these tools that occurs in the $PATH, in order, each in its # own fallback directory. for i in [ar as nm cc make ld gcc objdump sh $HOST_EXTRA] { if test ! -f "$STAGE_DIR/$i" { # Loop through each instance, populating fallback directories. setglobal X = '0' setglobal FALLBACK = $STAGE_DIR env PATH=$SAVEPATH "$STAGE_DIR/which" -a $i | while read j { if test ! -e "$FALLBACK/$i" { mkdir -p $FALLBACK && ln -sf $j "$FALLBACK/$i" || dienow } setglobal X = $shExpr('$X+') setglobal FALLBACK = ""$STAGE_DIR/fallback-$X"" } if test ! -f "$STAGE_DIR/$i" { echo "Toolchain component missing: $i" > !2 dienow } } } # Workaround for a bug in Ubuntu 10.04 where gcc became a perl script calling # gcc.real. Systems that aren't crazy don't need this. setglobal ET_TU_UBUNTU = $[env PATH=$SAVEPATH "$STAGE_DIR/which" gcc.real] test ! -z $ET_TU_UBUNTU && ln -s $ET_TU_UBUNTU "$STAGE_DIR/gcc.real" !2 >/dev/null # We now have all the tools we need in $STAGE_DIR, so trim the $PATH to # remove the old ones. setglobal PATH = $[hosttools_path] if test ! -z $[find $STAGE_DIR -newer "$BUILD/record-commands" !2 >/dev/null] { cd $TOP && more/record-commands.sh || dienow setglobal PATH = $WRAPDIR } # This is optionally used by root-filesystem to accelerate native builds when # running under qemu. It's not used to build root-filesystem, or to build # the cross compiler, but it needs to be on the host system in order to # use the distcc acceleration trick. # Note that this one we can use off of the host, it's used on the host where # the system image runs. The build doesn't actually use it, we only bother # to build it at all here as a convenience for run-from-build.sh. # Build distcc (if it's not in $PATH) if test -z $[which distccd] { setupfor distcc && ./configure --with-included-popt --disable-Werror && make -j $CPUS && cp distcc distccd $(STAGE_DIR) cleanup } # Build genext2fs. We use it to build the ext2 image to boot qemu with # in system-image.sh. if test ! -f "$(STAGE_DIR)"/genext2fs { setupfor genext2fs && ./configure && make -j $CPUS && cp genext2fs $(STAGE_DIR) cleanup } # Build e2fsprogs. # The hdb.img of run-emulator.sh and run-from-build.sh uses e2fsprogs' # fsck.ext2 and tune2fs. These are installed by default in most distros # (which genext2fs isn't), and genext2fs doesn't have ext3 support anyway. # system-image.sh will also use resize2fs from this package if # SYSIMAGE_TYPE=ext2 to expand the image to SYSIMAGE_HDA_MEGS, because # genext2fs is unreasonably slow at creating large files. (It has a -b # option that should do this... if you want your 8-way server with 32 gigs # of ram to sit there and drool for over 10 minutes to create a 2 gig file # that's mostly empty. Yeah: not doing that.) if test ! -f "$(STAGE_DIR)"/mke2fs { setupfor e2fsprogs && ./configure --disable-tls --disable-nls --enable-htree && make -j $CPUS && cp misc/{mke2fs,tune2fs} resize/resize2fs $(STAGE_DIR) && cp e2fsck/e2fsck "$STAGE_DIR"/fsck.ext2 cleanup } # Squashfs is the default toolchain packaging option. if test ! -f "$(STAGE_DIR)"/mksquashfs { setupfor zlib && ./configure && make -j $CPUS && mv z*.h libz.a .. cleanup setupfor squashfs && cd squashfs-tools && # Disable xattr support, uClibc doesn't support it and it's deeply pointless # anyway. (I left extended attributes behind with OS/2, thanks.) sed -i "/^XATTR_/d" Makefile && env CC="$CC -I ../.. -L ../.." make -j $CPUS && cp mksquashfs unsquashfs $(STAGE_DIR) && rm ../../{z*.h,libz.a} cleanup } # One more update with new packages if test ! -z $[find $STAGE_DIR -newer "$BUILD/record-commands" !2 >/dev/null] { cd $TOP && more/record-commands.sh || dienow } echo -e "\e[32mHost tools build complete.\e[0m"