ABOUT THIS GUIDE ================ This is a guide to building a custom BusyBox/Linux-libre system with the GNU toolchain. It mostly follows Linux From Scratch version 7.0, except that it uses more recent versions of some software packages, avoids applying patches where possible, builds cross-compiling GCC and other toolchain components in a "sysroot" configuration, and uses a BusyBox-based userspace rather than a GNU-based one. This guide assumes the use of a GNU/Linux host system with all the necessary development software (GCC, GNU Binutils, Subversion, etc.) already installed. It is recommended that you read Linux From Scratch version 7.0 to understand the full build process and the rationale behind various elements of the setup. PROCEDURE ========= Make a directory in which all work will be done. Under this directory, make directories 'src' and sys'. Download all of the necessary source archives and branches. src$ wget http://www.busybox.net/downloads/busybox-1.19.3.tar.bz2 src$ wget http://www.fsfla.org/svnwiki/selibre/linux-libre/download/releases/\ > LATEST-3.1.N/linux-3.1.6-libre.tar.bz2 src$ svn co svn://svn.eglibc.org/branches/eglibc-2_14 eglibc-2.14 src$ wget http://ftp.gnu.org/gnu/gcc/gcc-4.6.2/gcc-4.6.2.tar.bz2 src$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2 src$ wget http://ftp.gnu.org/gnu/make/make-3.82.tar.bz2 src$ wget http://ftp.gnu.org/gnu/automake/automake-1.11.2.tar.bz2 src$ wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.68.tar.bz2 src$ wget http://ftp.gnu.org/gnu/m4/m4-1.4.16.tar.bz2 src$ wget ftp://ftp.gmplib.org/pub/gmp-5.0.2/gmp-5.0.2.tar.bz2 src$ wget http://www.mpfr.org/mpfr-current/mpfr-3.1.0.tar.bz2 src$ wget http://www.multiprecision.org/mpc/download/mpc-0.9.tar.gz src$ for file in *.tar.bz2; do tar -xjf ${file}; done src$ for file in *.tar.gz; do tar -xzf ${file}; done Make and mount the filesystem. sys$ dd if=/dev/zero of=fs bs=1024 count=$((3*1024*1024)) sys$ sudo mkfs -t ext4 fs sys$ mkdir fsmnt sys$ sudo mount -o loop fs fsmnt Set up the toolchain environment. Be sure to change '' to the absolute path to the base work directory you made earlier. We're using GNU Bash as the new user's default shell for convenience; this has no effect on the target system. sys$ sudo mkdir -v fsmnt/tools fsmnt/tools/usr fsmnt/src sys$ sudo ln -sv "${PWD}/fsmnt/tools" /tools sys$ sudo cp -pR ../src/*/ fsmnt/src/ sys$ sudo groupadd bbll sys$ sudo useradd -s /bin/bash -g bbll -m -k /dev/null bbll sys$ sudo passwd bbll sys$ sudo chown -R bbll:bbll fsmnt/tools fsmnt/src sys$ su - bbll $ cat > ~/.bash_profile < exec env -i HOME="${HOME}" TERM="${TERM}" /bin/bash > EOF $ cat > ~/.bashrc < set +h > umask 022 > BBLL=/sys/fsmnt > LC_ALL=C > BBLL_TARGET=$(uname -m)-bbll-linux-gnu > PATH=/tools/bin:/tools/usr/bin:/bin:/usr/bin > export BBLL LC_ALL BBLL_TARGET PATH > PS1='$ ' > EOF $ source ~/.bash_profile Configure and build a cross-compiling GNU Binutils. $ cd "${BBLL}/src" $ mkdir binutils-build $ cd binutils-build $ ../binutils-2.22/configure --target=${BBLL_TARGET} --prefix=/tools/usr \ > --disable-nls --disable-werror $ make -j 4 $ case $(uname -m) in > x86_64) > mkdir -v /tools/usr/lib > ln -sv lib /tools/usr/lib64 > ;; > esac $ make install $ cd .. $ rm -Rf binutils-build Configure and build a cross-compiling GCC. $ mv gmp-5.0.2/ gcc-4.6.2/gmp $ mv mpfr-3.1.0/ gcc-4.6.2/mpfr $ mv mpc-0.9/ gcc-4.6.2/mpc $ mkdir gcc-build $ cd gcc-build $ ../gcc-4.6.2/configure --target=${BBLL_TARGET} --prefix=/tools/usr \ > --disable-nls --disable-shared --disable-multilib --disable-decimal-float \ > --disable-threads --disable-libmudflap --disable-libssp --disable-libgomp \ > --disable-libquadmath --enable-languages=c --without-ppl --without-cloog \ > --with-mpfr-include=$(pwd)/../gcc-4.6.2/mpfr/src \ > --with-mpfr-lib=$(pwd)/mpfr/src/.libs $ make -j 4 $ make install $ ln -sv libgcc.a $(${BBLL_TARGET}-gcc -print-libgcc-file-name | \ > sed 's/libgcc/&_eh/') $ cd .. $ rm -Rf gcc-build Install Linux's headers for use by EGLIBC. $ cd linux-3.1.6 $ make mrproper $ make headers_check $ make INSTALL_HDR_PATH=/tools/usr headers_install $ cd .. Configure and build a cross-compiling EGLIBC. Change '' to the lower of either version 3.1.6 or the version of Linux running on your host system. $ mkdir eglibc-build $ cd eglibc-build $ case $(uname -m) in > i?86) > echo 'CFLAGS += -march=i486 -mtune=native' > configparams > ;; > esac $ ../eglibc-2.14/libc/configure --prefix=/tools/usr --host=${BBLL_TARGET} \ > --build=$(../eglibc-2.14/libc/scripts/config.guess) --disable-profile \ > --enable-add-ons --enable-kernel= \ > --with-headers=/tools/usr/include \ > libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes libc_cv_ssp=no $ make -j 4 $ make install $ cd .. $ rm -Rf eglibc-build Edit GCC's specs file to point to the newly-compiled dynamic linker instead of the host system's dynamic linker, then build a test program to make sure everything works. $ SPECS=$(dirname $(${BBLL_TARGET}-gcc -print-libgcc-file-name))/specs $ ${BBLL_TARGET}-gcc -dumpspecs | sed -e 's@/lib\(64\)\?/ld@/tools/usr&@g' \ > -e '/^\*cpp:$/{n;s,$, -isystem /tools/usr/include,}' > ${SPECS} $ unset SPECS $ echo 'int main(){return 0;}' > test.c $ ${BBLL_TARGET}-gcc -B/tools/usr/lib test.c The following command should output something like "[Requesting program interpreter: /tools/usr/lib64/ld-linux-x86-64.so.2]". If you don't see this output, then you might not have edited your GCC specs file correctly. $ readelf -l a.out | grep ': /tools/usr' The following command should execute properly and output nothing. If you see "FATAL: kernel too old", then you set the value of '--enable-kernel' too low when configuring EGLIBC. $ ./a.out $ rm -v test.c a.out Cross-compile a native GNU Binutils. $ mkdir -v binutils-build $ cd binutils-build $ CC="${BBLL_TARGET}-gcc -B/tools/usr/lib" AR=${BBLL_TARGET}-ar \ > RANLIB=${BBLL_TARGET}-ranlib ../binutils-2.22/configure \ > --prefix=/tools/usr --disable-nls --with-lib-path=/tools/usr/lib $ make -j 4 $ make install $ make -C ld clean $ make -C ld LIB_PATH=/usr/lib:/lib $ cp -v ld/ld-new /tools/usr/bin $ cd .. $ rm -Rf binutils-build Prepare GCC for a native build, disabling the fixincludes script and adding the '-fomit-frame-pointer' flag that is missing from non-bootstrapped GCC builds. Note that the syntax in the cp command lines is a non-standard feature of GNU Bash; this may not work on other shells. $ cd gcc-4.6.2 $ cp -v gcc/Makefile.in{,.orig} $ sed 's@\./fixinc\.sh@-c true@' gcc/Makefile.in.orig > gcc/Makefile.in $ cp -v gcc/Makefile.in{,.tmp} $ sed 's/^T_CFLAGS =$/& -fomit-frame-pointer/' gcc/Makefile.in.tmp > \ > gcc/Makefile.in $ for file in $(find gcc/config -name linux64.h -o -name linux.h -o -name sysv4.h); do cp -uv ${file}{,.orig}; sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools/usr&@g' -e 's@/usr@/tools&@g' ${file}.orig > ${file}; touch ${file}.orig; done $ case $(uname -m) in x86_64) for file in $(find gcc/config -name t-linux64); do cp -v ${file}{,.orig}; sed '/MULTILIB_OSDIRNAMES/d' ${file}.orig > ${file}; done ;; esac $ cd .. Cross-comile a native GCC. $ mkdir gcc-build $ cd gcc-build $ CC="${BBLL_TARGET}-gcc -B/tools/usr/lib" AR=${BBLL_TARGET}-ar RANLIB=${BBLL_TARGET}-ranlib ../gcc-4.6.2/configure --prefix=/tools/usr --with-local-prefix=/tools/usr --with-sysroot="${BBLL}" --with-build-sysroot="${BBLL}" --enable-clocale=gnu --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-languages=c,c++ --disable-libstdcxx-pch --disable-multilib --disable-bootstrap --disable-libgomp --without-ppl --without-cloog --with-mpfr-include=$(pwd)/../gcc-4.6.2/mpfr/src --with-mpfr-lib=$(pwd)/mpfr/src/.libs