Thought Mountain

by
Wenton L. Davis

Building a Cross-Compiler

WARNING! (May 23, 2012): Due to various changes in compilers, The commands below aren't quite right.  I will leave them in tact for historical references, but to get the corrected versions, please scroll to the bottom.  These were used on binutils 2.22, gcc 4.7.0, and I think newlib 1.19.

One thing that was very difficult for me for a while was the mystery of how to build a cross-compiler.  It took over a year of bashing my face into the keyboard, searching blogs and posting "help me" comments on these sites, I finally managed to sctratch together enough information to put together some basic means of building a cross compiler.  This small page is provided so that if anyone comes across it, this are the exact steps I used to build my compilers that seems to work.  I have NOT been able to fully test these by any means, so I welcome feedback on problems (especially when accompanied by solutions) that other people find in this procedure.

So, let's get to it then! To get started, you need at least the binutils, gcc, and newlib files, and the gdb file is recommended, a lot.  (...although I rarely use it myself, because I usually debug on the target hardware, I have found that running the debugger can simplify a lot of the "what the heck is this thing doing!?" kinds of questions!)  Here are files I have downloaded the past few days (Dec. 7, 2008) (Updated on May 14, 2010):

I tried to use binutils-2.20.tar.bz2 and gcc-4.5.0.tar.bz2, but both failed.  binutils complained about an empty if block, and gcc-4.5.0 needed me to go out and update a bunch of packages.  Maybe I'll do that later.

Here is the documentation for newlib (also available from redhat.com on the same page):
libc libm
libc.dvi or libc.pdf libm.dvi or libm.pdf

There may be newer versions of these files out there, so always check the GNU websites and (ick) Red Hat (did I mention, ick?) to get the newlib.  If you really have to download the files off my server, please remember the only company that would allow me to have a static IP only offered 256K DSL service in my area! :-(  So, you get those files, and put them all in a new directory - just trying to keep everything nice and tidy.  In this new directory, expand each archive file:

    tar jxfv binutils-2.20.tar.bz2
    tar jxfv gcc-4.5.0.tar.bz2 
    tar zxfv gdb-7.1.tar.gz
    tar zxfv newlib-1.18.0.tar.gz
    mkdir objdir
    cd objdir
  

You now have your source code expanded, and a new directoty yo build binaries into.  It's probably not necessary to build this other directory, but it provides a clean space to work in without corrupting data or files.  If you are only building a single toolchain for a single target, probably no big deal because you'll just go back and delete the binutils, gcc, newlib and gdb source trees directories anyway when your done.  If, however, you are going to build the toolchain for ARM, Blackfin, MIPS, SPARC, ... on and on and on... processors, you don't want any old files when you rebuild for the next processor.  In either case, it's still just a good idea (as recommended in the readme files), to use a seperate directory anyway.

Now that the directories are set up, it's time to build the files.  Because binutils is needed for all the other programs, it must be built first.  binutils usually buils pretty easily; the configure command is the most difficult part of all of the toolchain components.  I have not been able to find a definative list of legal targets to build.  (If anyone finds such a list, please email me and I'll post it here.)  if you know your target is supported by gcc, the "safe" choice seems to be to suffix the processor type with '-elf' to define the target.  Assuming you are building the toolchain for the arm procressor, the target is arm-elf.  It is also a good idea to use the target name as part of each programs' names, but include an extra dash at the end, to seperate the prefix from the rest of the program name.  Knowing this, the binutils can now be configured and built with the following series of commands:

  export DESTINATION=/usr/local
  export TARGET=arm-elf
  ../binutils-2.20/configure ../binutils-2.20/configure \
     --prefix=${DESTINATION} --target=${TARGET} --program-prefix=${TARGET}-
  make
  make install
  rm -Rf *
  

You should now see all of the arm binutils in the /usr/local/bin directory!

Don't forget to empty out the directory! I'm not sure it is absolutely necessary, but better safe than sorry!

Now it's time to build the bootstrap 'C' Compiler.  This is not the final compiler - it is just a temporary one to use to build the newlib, later.  Again, the command-line options are more than just a little difficult to find, but these options generally seem to do the trick.  Note that the DESTINATION and TARGET environment variables were defined above, and should be the same as earlier.

  ../gcc-4.5.0/configure --prefix=${DESTINATION} --target=${TARGET} --program-prefix=${TARGET}- \
      --disable-libssp --enable-languages=c --with-arch=armv4t --with-float=soft \
      --without-headers --enable-softfloat --disable-hardfloat --disable-thread -disable-shared \
      --enable-interwork --enable-targets=arm-thumb-elf -disable-nls --with-newlib
  make
  make install
  rm -Rf *
  

In this example, the ARM processor needs a lot of other switches set.  Normally, only the --disable-libssp, --enable-languages=c, --with-newlib, and --without-headers are needed, although I've used the additional switches, --disable-libstdc-pch, --disable-symvers, and --disable-libffi and these seem to work well.

So far so good, right? So far, you should have the binutils and a basic 'C' compiler built.  If you don't need any of the math or 'C' libraries, you're done.  Ultimately, though, you'll probably want these other libraries; enter newlib.  Newlib is what allows you to use the more standard functions like printf() and scanf(), as well as the math functions like sin() and sqrt().  Because the tough stuff (configuring the compiler) is already done, building the newlib is the esiest part of the project:

  ../newlib-1.18.0/src/configure  --prefix=/usr/local --target=arm-elf
  make all
  make install
  rm -Rf *
  

And now for the fun part - the final version of the compiler.  Earlier, a "bootstrap" compiler was built, which was just a simple 'C' compiler, which was needed to build newlib for the target system.  Playing "Chicken and the Egg," we now want to build the full compiler, which needs the libraries! This was why the bootstrap 'C' compiler was needed - because it was needed to build the libraries.  Now that the libraries have been built, it is possible to build the compiler... the real one this time! The process is almost exactly the same as before, but this time, instead of just the basic 'C' compiler, we can build the C++, ForTran, and other compilers.  Personally, I just build the 'C', C++, and ForTran compilers, but if you need them, you can build Ada, Java, and ObjC copilers as well by setting the --enable-languages switch to look like --enable-languages=ada,c,c++,fortran,java,objc.  If you want to leave out any of the compilers, just don't include them in the list.

  ../gcc-4.5.0/configure --prefix=${DESTINATION} --target=${TARGET} --program-prefix=${TARGET}- \
      --disable-libssp --enable-languages=c,c++,fortran --with-newlib \
      --disable-libstdc-pch --disable-symvers --disable-libffi
  make
  make install
  rm -Rf *
  

Fair warning, though... this will take a while.  On my 2.53GHz DuoCore, just the 'C,' C++, and ForTran compilers took 35 minutes to build, so you might go fix yourself a sandwich.

Now, a few notes.  Every processor architecture is going to have different parameters you'll need to research before building your toolchain.  The most difficult one I've done so far has been the ARM toolchain, which was why I selected it for my page, here.  I have successfully build the toolchain for ARM and Blackfin. When I tried to build for the m68hc11, the binutils built OK, but the 'C' compiler failed, reqesting a bug report to be sent... which I'll do someday.  A year ago (before I knew about newlib), I was able to build the binutils and the basic 'C' compiler for ARM, AVR, MIPS, and SPARC64 processors, so I know at least those will work.




OK, here are the corrected commands:

Addendum, in 2013: I obviously am not able to keep up with all the changes out there.  At some point, the arm-elf was dropped.  Use arm-eabi instead.

To build binutils:

development# export DESTINATION=/opt/arm_tools
development# export TARGET=arm-eabi
development# ../binutils-2.22/configure \
               --prefix=${DESTINATION} --target=${TARGET} --program-prefix=${TARGET}-
development# make
development# make install
development# rm -Rf *

To build the bootstrap compiler:

development# ../gcc-4.7.0/configure --prefix=${DESTINATION} \
               --target=${TARGET} --program-prefix=${TARGET}- \
               --disable-libssp --enable-languages=c --with-arch=armv4t \
               --with-float=soft -without-headers --enable-softfloat \
               --disable-hardfloat --disable-thread --disable-shared \
               --enable-interwork --enable-targets=arm-thumb-elf \
               -disable-nls --with-newlib --enable-obsolete 
               
development# make
development# make install
development# rm -Rf *

NOTE: when I used arm-eabi instead of arm-elf, I left off the --enable-obsolete and it seems to be OK.

To build newlib:

development# ../newlib/src/configure --prefix=${DESTINATION} --target=${TARGET}
development# make all
development# make install
development# rm -Rf *

To build the "real" compiler:

development# ../gcc-4.7.0/configure --prefix=${DESTINATION} \
               --target=${TARGET} --program-prefix=${TARGET}- \
               --disable-libssp --enable-languages=c,c++,fortran --with-arch=armv4t \
               --with-float=soft -without-headers --enable-softfloat \
               --disable-hardfloat --disable-thread --disable-shared \
               --enable-interwork --enable-targets=arm-thumb-elf \
               -disable-nls --with-newlib --enable-obsolete 
development# make
development# make install
development# rm -Rf *

Notice the --enable-obsolete switches.... apparently GNU is having trouble finding developers to support their efforts.  They are advertising that without help, some processors are not going to be supported, starting with the next major release, version 5.0.  BUMMER!




September 29,2015

I am doing this once again, this time using binutils-2.25, gcc-4.8.2, gdb-7.10, and newlib-2.2.0.20150924; all the most recent versions I could find.  One meaningful change is I wanted to include more of the ARM architectures.  So, I tried

... --with-arch=armv4t,armv6-m,armv7-m,armv7e-m,armv7-a ...

but it didn't like that.  It tried to find a single architecture with that long, nonsensical name.  instead, I had to list each one seperately:

... --with-arch=armv4t --with-arch=armv6-m \
    --with-arch=armv7-m --with-arch=armv7e-m,armv7-a ...

And everything ran fine.

Then, when I tried to build newlib, I was slapped with the reminder that ${DESTINATION}/bin needs to be added to the $PATH before continuing.  However, the build for newlib was looking for arm-eabi-cc, which does not exist.  I had to switch to my ${DESTINATION}/bin and link:

development# ln -s arm-eabi-gcc arm-eabi-cc

So I fix the link and I modify $PATH and I am able to build newlib... until:

#error "double and long double are the same size but LDBL_EQ_DBL is not
#defined"

At the moment, my current needs do not require IEEEFP, and I really don't need C++ or ForTran, so the bootstrap compiler will work fine.  I would like to know how to fix this so I can




Update: April 2, 2019:

I am doing a quick update based on the 68HC12.  Here is the binutils-2.32.tgz.  You can build it thus:

tar zxfv binutils-2.32.tgz
cd binutils-2.32
./configure --target=m6812-elf --program-prefix=m6812-elf-
make
su
make install

And if you want the debugger:

git clone git://sourceware.org/git/binutils-gdb.git
cd binutils-gdb
./configure --target=m6812-elf --program-prefix=m6812-elf-
make
su
make install

Since this is for an assembly-language-specific class, I did not waste time wih the higher level languages.




home

Need to contact me? Try emailing me wenton@ieee.org