This article describes my infutile first attempt to compile a gcc 4 toolchain for my NAS DS 509+. Every step described works, but the endresult are binaries that do not run on my NAS. Never the less, this article may be worthwhile.
I purchased a NAS a Synology DiskStation 509+ to use as a Server. This NAS, as well as all others of the + series are based on a Freescale mpc8533 PowerPC with 64-Bit Memory Bus. The j series use the Freescale mpc8241 PowerPC with 32-Bit Memory Bus. Which are basically the same architecture (besides the Bus width). For the completeness sake is here a list of the products (up to 28.12.2009):
+-Series
- DS109+
- DS209+
- DS209+II
- DS409+
- DS509+
- RS409+
- RS409RP+
j-Series
- DS109j
- DS209j
[Source: http://forum.synology.com/wiki/index.php/What_kind_of_CPU_does_my_NAS_have]
Now guess what: There is are no Java binaries out there that work. Therefore you have to compile your own. But surprise, the NAS has no compiler. (Well there is a guide for cross-compiling from Synology).
Getting a compiler
The first step is to enable the NAS to compile the sources on its own. For that I need a GCC compiler tool-chain on the NAS. The easiest way is probably to use the steps in the aforementioned document to cross-compile the compiler (we need binutils, gcc and glibc possible also the Linux headers). The problem with this is the need to manually tweak the configure script to comply to the target architecture.
Another path may be the use of sections of the Cross-Compiled Linux From Scratch, which is just a bit heavy weight since you don’t want to compile a whole system. Therefore this description must be tweaked also.
A third path may be the lightweight description found at http://www.pages.drexel.edu/~sg64/stuff/cross-compile.htm.
As usual I tried the easy way out but ended up following the Linux from Scratch way. Using an Ubuntu 32bit on a 64bit machine I had to install several packages to comply:
- flex
- texinfo
- gawk
- bison
On the NAS I created a tools directory that I mounted on my host under /media/tools. If you map your share to another directory or compile into a local directory be sure to replace ‚/media/tools‘ with the appropriate value.
I used the following steps after downloading the needed packages and extracting them. For further details please referre to the CLFS.
unset CFLAGS unset CFLAGS export CLFS_HOST="$(echo $MACHTYPE | \ sed "s/$(echo $MACHTYPE | cut -d- -f2)/cross/")" export CLFS_TARGET="powerpc64-unknown-linux-gnu" export CLFS_TARGET32="powerpc-unknown-linux-gnu" export BUILD32="-m32" export BUILD64="-m64" cd linux-2.6.24.7 install -dv ../tools/include make mrproper
In scripts/unifdef.c I needed to replace all three instances of getline with lineread.
make ARCH=powerpc headers_check make ARCH=powerpc INSTALL_HDR_PATH=dest headers_install cp -rv dest/include/* ../tools/include cd .. mkdir cross-tools cd file-4.23 ./configure --prefix=/media/tools/cross-tools make make install cd .. cd binutils-2.18 patch -Np1 -i ../binutils-2.18-posix-1.patch patch -Np1 -i ../binutils-2.18-branch_update-3.patch patch -Np1 -i ../binutils-2.18-genscripts_multilib-1.patch mkdir -v ../binutils-build cd ../binutils-build AR=ar AS=as ../binutils-2.18/configure --prefix=/media/tools/cross-tools --host=${CLFS_HOST} --target=${CLFS_TARGET} \ --with-lib-path=/media/tools/tools/lib --disable-nls --enable-shared --enable-64-bit-bfd \ --disable-info make configure-host export CFLAGS="-Wno-error -g -O2" make export CFLAGS= make install cp -v ../binutils-2.18/include/libiberty.h /media/tools/tools/include cd .. cd gcc-4.2.4 patch -Np1 -i ../gcc-4.2.4-specs-1.patch patch -Np1 -i ../gcc-4.2.4-posix-1.patch patch -Np1 -i ../gcc-4.2.4-cross_search_paths-1.patch echo " #undef STARTFILE_PREFIX_SPEC #define STARTFILE_PREFIX_SPEC \"/media/tools/tools/lib/\"" >> gcc/config/rs6000/linux.h echo " #undef STARTFILE_PREFIX_SPEC #define STARTFILE_PREFIX_SPEC \"/media/tools/tools/lib/\"" >> gcc/config/rs6000/linux64.h cp -v gcc/Makefile.in{,.orig} sed -e "s@\(^CROSS_SYSTEM_HEADER_DIR =\).*@\1 /media/tools/tools/include@g" \ gcc/Makefile.in.orig > gcc/Makefile.in mkdir -v ../gcc-build cd ../gcc-build ../gcc-4.2.4/configure --prefix=/media/tools/cross-tools \ --host=${CLFS_HOST} --target=${CLFS_TARGET} --with-local-prefix=/media/tools/tools --disable-nls --disable-shared \ --disable-threads --enable-languages=c make all-gcc make install-gcc cd .. cd glibc-2.7 patch -Np1 -i ../glibc-2.7-branch_update-1A.patch patch -Np1 -i ../glibc-2.7-libgcc_eh-1.patch patch -Np1 -i ../glibc-2.7-localedef_segfault-1.patch mkdir -v ../glibc-build export PATH=$PATH:/media/tools/cross-tools/bin cd ../glibc-build echo "libc_cv_forced_unwind=yes" > config.cache echo "libc_cv_c_cleanup=yes" >> config.cache BUILD_CC="gcc" CC="${CLFS_TARGET}-gcc ${BUILD32}" \ AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \ ../glibc-2.7/configure --prefix=/media/tools/tools \ --host=${CLFS_TARGET32} --build=${CLFS_HOST} \ --disable-profile --enable-add-ons \ --with-tls --enable-kernel=2.6.0 --with-__thread \ --with-binutils=/media/tools/cross-tools/bin --with-headers=/media/tools/tools/include \ --cache-file=config.cache make make install cd .. cd glibc-2.7 patch -Np1 -i ../glibc-2.7-branch_update-1A.patch patch -Np1 -i ../glibc-2.7-libgcc_eh-1.patch patch -Np1 -i ../glibc-2.7-localedef_segfault-1.patch mkdir -v ../glibc-build cd ../glibc-build echo "libc_cv_forced_unwind=yes" > config.cache echo "libc_cv_c_cleanup=yes" >> config.cache echo "slibdir=/media/tools/tools/lib64" >> configparms BUILD_CC="gcc" CC="${CLFS_TARGET}-gcc ${BUILD64}" \ AR="${CLFS_TARGET}-ar" RANLIB="${CLFS_TARGET}-ranlib" \ ../glibc-2.7/configure --prefix=/media/tools/tools \ --host=${CLFS_TARGET} --build=${CLFS_HOST} --libdir=/media/tools/tools/lib64 \ --disable-profile --enable-add-ons \ --with-tls --enable-kernel=2.6.0 --with-__thread \ --with-binutils=/media/tools/cross-tools/bin --with-headers=/media/tools/tools/include \ --cache-file=config.cache make make install cd .. cd gcc-4.2.4 patch -Np1 -i ../gcc-4.2.4-PR31490-1.patch cp -v gcc/Makefile.in{,.orig} sed -e "s@\(^CROSS_SYSTEM_HEADER_DIR =\).*@\1 /media/tools/tools/include@g" \ gcc/Makefile.in.orig > gcc/Makefile.in cp -v configure{,.orig} sed -e '/FLAGS_FOR_TARGET.*\/lib\//s@-B[^ ]*/lib/@@g' configure.orig > \ configure cd ../gcc-build ../gcc-4.2.4/configure --prefix=/media/tools/cross-tools \ --target=${CLFS_TARGET} --host=${CLFS_HOST} \ --with-local-prefix=/media/tools/tools --disable-nls --enable-shared \ --enable-languages=c,c++ --enable-__cxa_atexit \ --enable-c99 --enable-long-long --enable-threads=posix make AS_FOR_TARGET="${CLFS_TARGET}-as" \ LD_FOR_TARGET="${CLFS_TARGET}-ld" make install
While configuring the glibc library I run into a snag that let me believe that I had to install autoconf for succesfull compilation. With autoconf installed the configuration would hang on „checking whether autoconf works“, which means that cd ../glibc-2.7 autoconf hangs. After removing autoconf from the system and fixing the original error (by installing gawk) everything was fine.
With that the cross compile tool chain is complete and this tool chain can now be set to use to compile the tools for the target system.
export CC="${CLFS_TARGET}-gcc" export CXX="${CLFS_TARGET}-g++" export AR="${CLFS_TARGET}-ar" export AS="${CLFS_TARGET}-as" export RANLIB="${CLFS_TARGET}-ranlib" export LD="${CLFS_TARGET}-ld" export STRIP="${CLFS_TARGET}-strip" rm -Rdf binutils-build mkdir binutils-build cd binutils-build CC="${CC} ${BUILD64}" \ ../binutils-2.18/configure --prefix=/media/tools/tools \ --libdir=/media/tools/tools/lib64 --with-lib-path=/media/tools/tools/lib \ --build=${CLFS_HOST} --host=${CLFS_TARGET} --target=${CLFS_TARGET} \ --disable-nls --enable-shared --enable-64-bit-bfd --disable-info make configure-host make make install cd ..
I had to replace the constant SSIZE_MAX in gcc-4.2.4/gcc/config/host-linux.c on line 207 with the constant LONG_MAX.
rm -Rdf gcc-build cd gcc-4.2.4 cp -v gcc/cppdefault.c{,.orig} sed -e '/#define STANDARD_INCLUDE_DIR/s@"/usr/include"@0@g' \ gcc/cppdefault.c.orig > gcc/cppdefault.c cp -v gcc/Makefile.in{,.orig} sed -e 's@\(^NATIVE_SYSTEM_HEADER_DIR =\).*@\1 /media/tools/tools/include@g' \ gcc/Makefile.in.orig > gcc/Makefile.in cp -v gcc/Makefile.in{,.orig2} sed -e "/MULTILIBS/s@\$(GCC_FOR_TARGET)@/media/tools/cross-tools/bin/${CC}@g" \ gcc/Makefile.in.orig2 > gcc/Makefile.in CC="${CC} ${BUILD64}" CXX="${CXX} ${BUILD64}" \ ../gcc-4.2.4/configure --prefix=/media/tools/tools --libdir=/media/tools/tools/lib64 \ --build=${CLFS_HOST} --host=${CLFS_TARGET} --target=${CLFS_TARGET} \ --with-local-prefix=/media/tools/tools --enable-long-long --enable-c99 \ --enable-shared --enable-threads=posix --enable-__cxa_atexit \ --disable-nls --enable-languages=c,c++ --disable-libstdcxx-pch make AS_FOR_TARGET="${AS}" \ LD_FOR_TARGET="${LD}" make install cd ..
Now we are done with the compiling section. The next part is a bit tricky: We must integrate the compiled binaries into the running system. Because the ‚/media/tools‘ directory was a mapped directory on my NAS all binaries are already there (in a directory /volume1/cross_compile/tools). We have to ensure that the next action can be undone. There are two sets of possibilities:
- The binary does not already exist: Therefore it should be possible to remove the binary
- A binary with the same name (possibly another version) exists: The original must be backed up so that it can be restored.
For the purpose of the backup I created a directory under /root named backup_sys_gcc and a script rollback that can either remove the new version or replace it from the backup directory. As I walked through the directories only some libraries in lib were also in /lib. I figured to leave the original and delay any potential problems that may arise when they occur.