#! /bin/bash # Build a native toolchain, binutils+gcc+glibc+gdb, that coexists rather # than replacing the system tools and libraries. They will be built in # build/* relative to the current working dir. # Where the toolchain should be installed dest=/home/alan/toolchain # Where to install binutils and gcc that use the host glibc # If this isn't set it is assumed that the host tools are sufficiently recent # to support -mdata-plt. host_dest= # Where various sources may be found. These are all copied to src/* # relative to the current working dir. kernel_src=/src/ppc-2.6.11.10 gcc_src=/src/gcc-4.0 glibc_src=/src/libc-current binutils_src=/src/binutils-current gdb_src=/src/gdb-current # If this is set, then binutils and gdb will be extracted from the cygnus # source tree. cygnus_src= # If combined_tree is set to "yes", then a combined binutils/gcc tree will be # built. In general this only works for mainline CVS source, because the top # level directory make and configure files of each need to be virtually # identical. conbined_tree= # Stop on errors. set -e # Find as and ld for gcc if test -n "${host_dest}"; then # We'll be building new ones. gcc_as="${host_dest}"/as gcc_ld="${host_dest}"/ld else # Find as and ld from the users path save_IFS="$IFS" IFS=: for d in $PATH; do if test -x "$d/as"; then gcc_as="$d/as" break fi done for d in $PATH; do if test -x "$d/ld"; then gcc_ld="$d/ld" break fi done IFS="$save_IFS" if test -z "$gcc_as"; then echo "Cannot find as!" exit 1 fi if test -z "$gcc_ld"; then echo "Cannot find ld!" exit 1 fi # Sanity check the ld we found if ! "$gcc_ld" --help 2>&1 | grep -q bss-plt; then echo "$gcc_ld is too old!" exit 1 fi # Also check host gcc if ! gcc -v --help 2>&1 | grep -q data-plt; then echo "host gcc is too old!" exit 1 fi fi # Set up local copies of sources. if test -n "${kernel_src}"; then mkdir -p src/kernel rsync -rptgoC --delete "${kernel_src}"/ src/kernel/ kernel_src=`cd src/kernel; pwd` fi if test -n "${cygnus_src}"; then mkdir -p src/binutils # Pull binutils source out of the whole cygnus repo. # Exclude top level dirs that we don't need to build. rsync -rptgoLC --delete \ --exclude blt \ --exclude compile \ --exclude contrib \ --exclude dejagnu \ --exclude depcomp \ --exclude expect \ --exclude gdb \ --exclude itcl \ --exclude iwidgets \ --exclude libgloss \ --exclude libgui \ --exclude mmalloc \ --exclude newlib \ --exclude rda \ --exclude readline \ --exclude sid \ --exclude sim \ --exclude tcl \ --exclude tk \ --exclude utils \ --exclude winsup \ "${cygnus_src}"/ src/binutils binutils_src=`cd src/binutils; pwd` mkdir -p src/gdb # Pull gdb source out of the whole cygnus repo. Exclude some top level # dirs, and some under gdb; gdbtk is old stuff we don't want. rsync -rptgoLC --delete \ --exclude /binutils \ --exclude /blt \ --exclude /cgen \ --exclude /compile \ --exclude /contrib \ --exclude /dejagnu \ --exclude /depcomp \ --exclude /expect \ --exclude /gas \ --exclude /gdb/gdbtk \ --exclude /gdb/testsuite/gdb.gdbtk \ --exclude /gprof \ --exclude /intl \ --exclude /itcl \ --exclude /iwidgets \ --exclude /ld \ --exclude /libgloss \ --exclude /libgui \ --exclude /mmalloc \ --exclude /newlib \ --exclude /rda \ --exclude /sid \ --exclude /tcl \ --exclude /tk \ --exclude /utils \ --exclude /winsup \ "${cygnus_src}"/ src/gdb gdb_src=`cd src/gdb; pwd` else if test -n "${binutils_src}"; then mkdir -p src/binutils rsync -rptgoC --delete "${binutils_src}"/ src/binutils/ binutils_src=`cd src/binutils; pwd` fi if test -n "${gdb_src}"; then mkdir -p src/gdb rsync -rptgoC --delete "${gdb_src}"/ src/gdb/ gdb_src=`cd src/gdb; pwd` fi fi if test -n "${gcc_src}"; then mkdir -p src/gcc rsync -rptgoC --delete "${gcc_src}"/ src/gcc/ gcc_src=`cd src/gcc; pwd` fi if test -n "${glibc_src}"; then mkdir -p src/glibc rsync -rptgoC --delete "${glibc_src}"/ src/glibc/ glibc_src=`cd src/glibc; pwd` fi if test ! -d "${kernel_src}"; then echo "No kernel source!" exit 1 fi if test ! -d "${binutils_src}"; then echo "No binutils source!" exit 1 fi if test ! -d "${gcc_src}"; then echo "No gcc source!" exit 1 fi if test ! -d "${glibc_src}"; then echo "No glibc source!" exit 1 fi unset combined_src if test x${combined_tree} = xyes; then # Use a combined source tree rm -rf src/combined mkdir -p src/combined cp -al "${binutils_src}"/* src/combined cp -alf "${gcc_src}"/* src/combined combined_src=`cd src/combined; pwd` fi if test -n "${host_dest}"; then # host binutils+gcc build # We do this because glibc requires at least gcc-3.4, and the system # compiler may be older. We also need host tools that support -mdata-plt. # NOTE! This build must not use gcc sources hacked to provide -rpath if test -z "${combined_src}"; then rm -rf build/host_bin mkdir -p build/host_bin cd build/host_bin CFLAGS="-g -O" CXXFLAGS="-g -O" "${binutils_src}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --target=powerpc-linux \ --enable-targets=powerpc64-linux \ --prefix="${host_dest}" \ --disable-nls \ >& _configure make >& _make make install >& _install cd ../.. fi rm -rf build/host_gcc mkdir -p build/host_gcc cd build/host_gcc CFLAGS="-g -O" CXXFLAGS="-g -O" "${combined_src:-${gcc_src}}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --target=powerpc-linux \ --enable-targets=powerpc64-linux \ --prefix="${host_dest}" \ --enable-__cxa_atexit \ --enable-languages=c \ --enable-shared \ --disable-nls \ >& _configure make bootstrap >& _make make install >& _install cd ../.. # Sanity check the ld we just built if ! "$gcc_ld" --help 2>&1 | grep -q bss-plt; then echo "$gcc_ld is too old!" exit 1 fi PATH="${host_dest}/bin:$PATH" fi # Hack the gcc source so that binaries generated will be able to use # the new glibc. This isn't necessary (or desirable) when building # a cross-compiler because with a cross-compiler you would be running # the binaries on another system, which presumably would have glibc # installed in the usual place. It is also possible to hack the gcc # specs file after gcc is built instead of editing the source, but that # presents a problem when trying to bootstrap gcc. A gcc bootstrap is # a multi-stage process, and you'd need to hack specs after each stage. # It is not possible to simply set LD_LIBRARY_PATH in the environment # because existing dynamic apps would then try to use the old ld.so # with the new libc.so. This fails miserably. # Add -rpath to where new shared libs will be installed, and modify # --dynamic-linker to point there too. Use new dtags so that we get # DT_RUNPATH in binaries rather than DT_RPATH. DT_RPATH can't be overridden # with LD_LIBRARY_PATH. s1='s@%{!shared: %{!static:@%{!static: %{!shared:@' s2='s@\(-dynamic-linker \)\(/lib[^/]*\)\(.*\)}"@\1'"${dest}"'\2\3 --enable-new-dtags -rpath '"${dest}"'\2}"@' for f in "${combined_src:-${gcc_src}}"/gcc/config/rs6000/{linux64.h,sysv4.h} do sed -e "$s1" -e "$s2" < "$f" > tmp.$$ \ && { cmp -s tmp.$$ "$f" || mv -f tmp.$$ "$f"; } || exit 1 rm -f tmp.$$ done # Hack the glibc source so that the -rpath option we add on all shared libs # and executable won't bomb ld.so, which checks that -rpath is not given. s1='s@assert (\(info\[DT_R.*PATH\]\) == NULL)@\1 = NULL@' for f in "${glibc_src}"/elf/dynamic-link.h do sed -e "$s1" < "$f" > tmp.$$ \ && { cmp -s tmp.$$ "$f" || mv -f tmp.$$ "$f"; } || exit 1 rm -f tmp.$$ done # kernel headers. ( cd "${kernel_src}" yes "" | make ARCH=ppc64 distclean oldconfig \ include/linux/autoconf.h include/linux/version.h >& _make ) rm -rf "${dest}"/include/{linux,asm,asm-generic,asm-ppc,asm-ppc64} mkdir -p "${dest}"/include/asm cp -a "${kernel_src}"/include/linux "${dest}"/include/linux cp -a "${kernel_src}"/include/asm-generic "${dest}"/include/asm-generic cp -a "${kernel_src}"/include/asm-ppc "${dest}"/include/asm-ppc cp -a "${kernel_src}"/include/asm-ppc64 "${dest}"/include/asm-ppc64 ( cd "${dest}"/include/asm-ppc64 header_list="$(/bin/ls *.h)" cd ../asm for header in ${header_list}; do rm -f ${header} macro=$(echo ${header} | sed 'y/.abcdefghijklmnopqrstuvwzyz/_ABCDEFGHIJKLMNOPQRSTUVWXYZ/') cat >> ${header} < # elif defined __powerpc__ # include # endif #endif EOF done ) # glibc headers rm -rf build/glibc mkdir -p build/glibc cd build/glibc "${glibc_src}"/configure \ --build=powerpc-linux \ --host=powerpc64-linux \ --prefix="${dest}" \ --with-headers="${dest}"/include \ --disable-sanity-checks \ --without-cvs \ >& _configure make sysdeps/gnu/errlist.c >& _make mkdir -p stdio-common touch stdio-common/errlist-compat.c make install-headers >& _install # Some headers aren't installed by install-headers, so do them by hand. mkdir -p "${dest}"/include/gnu if test ! -f "${dest}"/include/gnu/stubs.h; then touch "${dest}"/include/gnu/stubs.h fi if test ! -f "${dest}"/include/gnu/stubs-32.h; then touch "${dest}"/include/gnu/stubs-32.h fi if test ! -f "${dest}"/include/gnu/stubs-64.h; then touch "${dest}"/include/gnu/stubs-64.h fi if test ! -f "${dest}"/include/features.h; then cp "${glibc_src}"/include/features.h "${dest}"/include/features.h fi if test ! -f "${dest}"/include/bits/stdio_lim.h; then cp bits/stdio_lim.h "${dest}"/include/bits/stdio_lim.h fi cd ../.. # first binutils+gcc build # This can't be a "make bootstrap" because we don't have glibc installed yet. if test -z "${combined_src}"; then rm -rf build/bin mkdir -p build/bin cd build/bin CFLAGS="-g -O" CXXFLAGS="-g -O" "${binutils_src}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --target=powerpc-linux \ --enable-targets=powerpc64-linux \ --prefix="${dest}" \ --disable-nls \ >& _configure make >& _make make install >& _install cd ../.. fi rm -rf build/gcc mkdir -p build/gcc cd build/gcc AS="$gcc_as" LD="$gcc_ld" \ "${combined_src:-${gcc_src}}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --target=powerpc-linux \ --enable-targets=powerpc64-linux \ --prefix="${dest}" \ --enable-dataplt \ --disable-shared \ --disable-threads \ --disable-libmudflap \ --enable-languages=c \ >& _configure make >& _make make install >& _install cd ../.. # Install powerpc-linux-* and powerpc64-linux-* aliases for our new tools # This is in case these already exist somewhere on the system. Many # configure scripts prefer to use eg. "powerpc-linux-as" over plain "as". # ( cd "${dest}"/bin for z in addr2line ar as c++filt ld nm objcopy objdump ranlib size strings strip do test -x $z && test ! -e powerpc-linux-$x && ln -sfn $z powerpc-linux-$z done for z in addr2line ar c++filt nm objcopy objdump ranlib size strings strip do test -x $z && test ! -e powerpc64-linux-$x && ln -sfn $z powerpc64-linux-$z done if test ! -e powerpc64-linux-as; then cat > powerpc64-linux-as <<\EOF #!/bin/sh exec powerpc-linux-as -a64 "$@" EOF chmod a+x powerpc64-linux-as fi if test ! -e powerpc64-linux-ld; then cat > powerpc64-linux-ld <<\EOF #!/bin/sh exec powerpc-linux-ld -melf64ppc "$@" EOF chmod a+x powerpc64-linux-ld fi if test ! -e powerpc64-linux-gcc; then cat > powerpc64-linux-gcc <<\EOF #! /bin/sh case "$@" in *-m32*) powerpc-linux-gcc "$@";; *) powerpc-linux-gcc -m64 "$@";; esac EOF chmod a+x powerpc64-linux-gcc fi if test -x powerpc-linux-g++; then if test ! -e powerpc64-linux-g++; then cat > powerpc64-linux-g++ <<\EOF #! /bin/sh case "$@" in *-m32*) powerpc-linux-g++ "$@";; *) powerpc-linux-g++ -m64 "$@";; esac EOF chmod a+x powerpc64-linux-g++ fi ln -f powerpc64-linux-g++ powerpc64-linux-c++ fi ) # first ppc32 glibc build # We can't use the newly built gcc to compile glibc because it will set the # dynamic linker to be ${dest}/lib/ld.so.1, which isn't installed until the # glibc build finishes. So trying to run anything compiled with the new gcc # will fail, in particular, glibc configure tests. I suppose you might be # able to supply glibc configure with lots of libc_cv_* variables to # avoid this, but then you'd forever be changing this script to keep up with # new glibc configure tests. # Note that dynamically linked programs built here with the old host gcc are # subtly broken too; The glibc build sets their dynamic linker to # ${dest}/lib/ld.so.1 but doesn't provide rpath. Which means you'll get the # new ld.so trying to use the system libc.so, which doesn't work. ld.so and # libc.so share data structures so are tightly coupled. To run the new # programs, you need to set LD_LIBRARY_PATH for them, or better (so as to not # affect forked commands that might need the system libs), run ld.so.1 # explicitly, passing --library-path as is done for localedef below. # This is one of the reasons why you need to build glibc twice. rm -rf build/glibc32 mkdir -p build/glibc32 cd build/glibc32 CC="gcc -mdata-plt" \ "${glibc_src}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --prefix="${dest}" \ --with-headers="${dest}"/include \ --enable-add-ons=nptl \ --with-tls \ --without-cvs \ >& _configure make >& _make make install >& _install cd ../.. if test ! -f "${dest}"/etc/ld.so.conf; then cat > "${dest}"/etc/ld.so.conf < configparms echo bindir="${dest}"/bin64 >> configparms echo sbindir="${dest}"/sbin64 >> configparms echo rootsbindir="${dest}"/sbin64 >> configparms # We know the compiler we are using supports everything glibc needs, # but glibc can't run all its configure tests because a 64-bit glibc isn't # yet installed. So tell configure some answers. libc_cv_forced_unwind=yes \ libc_cv_c_cleanup=yes \ "${glibc_src}"/configure \ --build=powerpc-linux \ --host=powerpc64-linux \ --prefix="${dest}" \ --libdir="${dest}"/lib64 \ --libexecdir="${dest}"/libexec64 \ --with-headers="${dest}"/include \ --enable-add-ons=nptl \ --with-tls \ --without-cvs \ >& _configure make >& _make make install >& _install cd ../.. # Build locale files. mkdir -p "${dest}"/lib64/locale sed -n -e '/SUPPORTED-LOCALES/,$ s@\([^/]*\)/\([^ \\]*\).*@\1 \2@p' \ < "${glibc_src}"/localedata/SUPPORTED | sort | \ while read l c x; do echo localedef -i ${l%\.*} -f $c $l "${dest}"/bin64/localedef -i ${l%\.*} -f $c $l || true done # second binutils+gcc build # This time we build a full compiler. Pass AS and LD to configure, # because configure isn't clever enough to find the right as and ld if test -z "${combined_src}"; then rm -rf build/bin_1 mv build/bin build/bin_1 mkdir -p build/bin cd build/bin CFLAGS="-g -O" CXXFLAGS="-g -O" "${binutils_src}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --target=powerpc-linux \ --enable-targets=powerpc64-linux \ --prefix="${dest}" \ --disable-nls \ >& _configure make >& _make make install >& _install cd ../.. fi rm -rf build/gcc_1 mv build/gcc build/gcc_1 mkdir -p build/gcc cd build/gcc AS="${dest}"/bin/as \ LD="${dest}"/bin/ld \ "${combined_src:-${gcc_src}}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --target=powerpc-linux \ --enable-targets=powerpc64-linux \ --prefix="${dest}" \ --enable-dataplt \ --enable-__cxa_atexit \ --enable-shared \ --enable-languages=all \ >& _configure make STAGE1_CFLAGS="-g -O" bootstrap >& _make make install >& _install cd ../.. # second ppc32 glibc build rm -rf build/glibc32_1 mv build/glibc32 build/glibc32_1 mkdir -p build/glibc32 cd build/glibc32 "${glibc_src}"/configure \ --build=powerpc-linux \ --host=powerpc-linux \ --prefix="${dest}" \ --with-headers="${dest}"/include \ --enable-add-ons=nptl \ --with-tls \ --without-cvs \ >& _configure make >& _make make install >& _install cd ../.. # second ppc64 glibc build # This is hardly necessary, since we built ppc64 glibc using the new gcc in # the first build. However, we fudge glibc configure params here to say we # aren't really cross-compiling, which lets us build a few more parts of # glibc. rm -rf build/glibc64_1 mv build/glibc64 build/glibc64_1 mkdir -p build/glibc64 cd build/glibc64 # We want shared libs in ${dest}/lib64, and we don't want to trample on # any 32-bit binaries. Also say that we can run 64-bit binaries (assuming # ppc64 hardware!). echo slibdir="${dest}"/lib64 > configparms echo bindir="${dest}"/bin64 >> configparms echo sbindir="${dest}"/sbin64 >> configparms echo rootsbindir="${dest}"/sbin64 >> configparms echo cross-compiling=no >> configparms "${glibc_src}"/configure \ --build=powerpc-linux \ --host=powerpc64-linux \ --prefix="${dest}" \ --libdir="${dest}"/lib64 \ --libexecdir="${dest}"/libexec64 \ --with-headers="${dest}"/include \ --enable-add-ons=nptl \ --with-tls \ --without-cvs \ >& _configure make >& _make make install >& _install cd ../.. # ppc gdb build if test -n "${gdb_src}"; then rm -rf build/gdb32 mkdir -p build/gdb32 cd build/gdb32 "${gdb_src}"/configure \ --host=powerpc-linux \ --prefix="${dest}" \ --program-suffix=32 \ --disable-tcl \ --disable-tui \ >& _configure make >& _make make install >& _install cd ../.. fi # ppc64 gdb build if test -n "${gdb_src}"; then rm -rf build/gdb64 mkdir -p build/gdb64 cd build/gdb64 "${gdb_src}"/configure \ --host=powerpc64-linux \ --prefix="${dest}" \ --libdir="${dest}"/lib64 \ --program-suffix=64 \ --disable-tcl \ --disable-tui \ >& _configure make >& _make make install >& _install cd ../.. fi