DragonLace.Net
Home of the GNAT AUX and future DRACO Ada compilers.

How to bootstrap GNAT AUX to another Operating System or Architecture

After several weeks of trying to liberat GNAT GPL 2009 from DragonFly 1.2 to the latest release at the time, I finally succeeded by cross-compiling it. I actually did it twice, once through DragonFly Release 1.2 (i386 only) and again through Open Solaris SXCE 130 (i386 dual core) with identical results. If I had read Mark Rothwell's bootstrapping/compiling GNAT on FreeBSD x86_64 instructions first, maybe I could have saved a few days of aggravation. Mark assumes there's only one machine available, it's x86_64 based, and a i386-based version of GNAT is available for the system. As I just described, there's no benefit of using the same OS or the same machine when you are cross-compiling, so I am going to document how to bootstrap GNAT AUX to DragonFly x86_64 from 32-bit FreeBSD where recent versions of GNAT are readily available, instead of setting up a jail environment.

Gameplan

A full bootstrap is pretty tedious. We'll break it up into four stages.

  • Stage 1: Obtain Native i386 Host / Build / Target Compiler
  • Stage 2: Build Native i386 Host / Build / Target => Native i386 Host & Build / Foreign x86_64 Target Compiler
  • Stage 3: Build Native i386 Host & Build / Foreign x86_64 Target => Foreign x86_64 Host / Build / Target Compiler
  • Stage 4: Bootstrap x86_64 Compiler on Foreign Platform

This means we may have to build at least three distinct compilers, and possible four of them if you want to use the same version of the compiler to build itself. GCC takes a long time to build, even if you disable bootstrapping, so this process is going to take a while.

Stage 1

Stage 1: Obtain Native i386 Host / Build / Target Compiler

You must obtain a fairly recent binary of GNAT FSF, GNAT GPL, or GNAT AUX which is capable of building the latest GNAT AUX. You also need to obtain the following native libraries for use in this stage and/or the next one:

  • GMP (libgmp) GNU Multiple Precision
  • MPFR (libmpfr) Multiple-Precision Floating-point computations w/ correct Rounding (version >= 2.3.1 required, >= 2.4.2 rec.)
  • MPC (libmpc) (version >= 0.8 required)

Once you get this binary and the libraries, you can move directly to Stage 2. However, it may be a good idea to build a new native compiler with these libraries on your i386 system to both prove that the source code results in a functioning compiler and to be assured that you have the latest compiler available. These libraries are often available as packages, but they generally are easy to build from source. Ports and packages aren't always set on the most recent version, so visit [www.mpfr.org|www.mpfr.org] , [gmplib.org|http://gmplib.org] and [www.multiprecision.org|http://www.multiprecision.org] to obtain the latest source and build them from scratch if this is the case.

If you want to build a native host, build, and target compiler with your acquired GNAT binary (again, this is recommended), follow the instructions of another "How-To" I wrote to learn how to build GNAT AUX from the git repository. Once it is built and installed, you can move to the next stage.

Stage 2

Stage 2: Build Native i386 Host / Build / Target => Native i386 Host & Build / Foreign x86_64 Target Compiler

The goal of this stage is to produce a cross-compiler. This compiler will run in the 32-bit environment, but it will produce code executable on a 64-bit machines. GNAT has a default policy of using the newly built compiler to build the gnatlib and gnat tools. We have to override this policy, because obviously we can't run the 64-bit library and tools on the 32-bit machine. The latest versions of GCC don't allow you to explicitly state if you want to built cross-compiler versions of the library and tools, but does this for you when it detects we're cross compiling. It's a case where trying to be helpful gives one a lot less flexibility, plus it invalidates the existing gcc build instructions that nobody bothered to update after making the Makefile "smarter".

Stage 2A: Copy key 64-bit operating system files to the i386 machine

We needed to create linkers and assemblers that produce 64-bit executables on the 32-bit host. To compile these, we need to obtain core files from the target. Luckily in our case these readily exist and we only need to copy them over. I will create a work area under the directory /usr/DFS because /usr is the partition with the most free space and DFS is a cute name "Dragonfly-from-scratch" that lifted from the Linux-From-Scratch project.

In the 64-bit system, create a compressed tarball of the /usr/include and /usr/lib directories:

  # cd /
  # tar -cyf dragonfly64_headlib.tar.bz2 usr/lib usr/include

Move this file to the 32-bit machine via any method you want (FTP, SCP, usb stick, etc) to your home directory. Now we will install the files:

  # mkdir /usr/DFS
  # cd /usr/DFS/
  # tar -xyf ~/dragonfly64_headlib.tar.bz2

Stage 2B: Build binutils on your i386 machine for your 64-bit target

Download version 2.20 of binutils. You can get it from any GNU mirror, or just go directly to http://ftp.gnu.org/gnu/binutils and download binutils-2.2.1.tar.bz2 . DragonFly BSD isn't completely supported by binutils, so it needs to be patched (patch lost). Inspect the configuration files to see if your target is adequately supported by binutils. Here's how I built binutils for the Dragonfly x86_64 target:

  # tar -zyf binutils-2.20.1.tar.bz2
  # patch < fix-binutils-2.20.1.diff
  # cd binutils-2.20.1
  # ./jrmconfigure.sh
  # gmake all
  # gmake install

Here is the custom jrmconfigure.sh file referenced above (save this script in the binutils-2.20.1 directory and add execute permissions to it)

  #!/bin/sh

  DFS=/usr/DFS
  PREFIX=$DFS/cross220
  PKGS=/usr/local
  TARGET=x86_64-backplane-dragonfly2.6
  CC=gcc
  export CC

  ./configure
   --target=$TARGET
   --prefix=$PREFIX
   --with-sysroot=$DFS
   --with-gmp=$PKGS
   --with-mpc=$PKGS
   --with-mpfr=$PKGS
   --disable-shared
   --disable-multilib
   --disable-nls

Stage 2C: Build the cross-compiler

When building the cross-compiler, there are some new or changed parameters during the configure step. For one, you must specify the --target parameter, which will be different than the guessed (or explicitly specified) --host and --build parameters (that's the whole purpose of the cross-compiler, right?) We also must specify the system root, which points to our target system libraries and headers. An undocumented requirement is that gcc-cross compilers must use either the program-prefix parameter and it must be set to the same value as the target plus a hyphen. You can also use the program name transformation parameter (sed-based), but the program prefix is a lot simpler to use. The following script example may give you an idea how to configure your cross-compiler. Don't forget to disable the bootstrap!

  #!/bin/sh

  NATIVE_HOST=i386-portbld-freebsd8.0
  DFLY_TARGET=x86_64-backplane-dragonfly2.6
  XCOM_SYSROOT=/usr/DFS
  PREFIX=$XCOM_SYSROOT/cross220
  PKGS=/usr/local
  CC=/usr/local/bin/gnatgcc

  export CC

  ../gcc-4.5-20100401/configure
   --enable-languages=c,ada
   --build=$NATIVE_HOST
   --host=$NATIVE_HOST
   --target=$DFLY_TARGET
   --program-prefix=$DFLY_TARGET-
   --prefix=$PREFIX
   --with-system-zlib
   --with-gmp=$PKGS
   --with-mpc=$PKGS
   --with-mpfr=$PKGS
   --with-libiconv-prefix=$PKGS
   --with-sysroot=$XCOM_SYSROOT
   --enable-threads=single
   --disable-bootstrap
   --disable-shared
   --disable-multilib
   --disable-libmudflap
   --disable-libgomp
   --disable-libssp
   --disable-nls

Don't forget to move to the work/build directory and type "gmake install" when you finally get the compiler built.

Stage 3

Stage 3: Build Native i386 Host & Build / Foreign x86_64 Target => Foreign x86_64 Host / Build / Target Compiler

We now have a compiler that lets us create code that executes on our 64-bit target. Let's use it to create a compiler that runs on that target and creates code for the same target.

Stage 3A: Build GMP, MPC, MPFR, and ICONV on the target machine

Obtain or otherwise build the GMP, MPC, MPFR, and iconv libraries on the 64-bit target machine. When you are done, this is the list of files that are of interest:

  /include/
    gmp.h
    gmpxx.h
    iconv.h
    libcharset.h
    localcharset.h
    mpfr2mpfr.h
    mpfr.h
    mpc.h

  /lib/
    libcharset.*
    libgmp.*
    libgmpxx.*
    libiconv.*
    libmpfr.*
    libmpc.*

The library files usually have five variations with file extensions of .a, .la, .so, .so.x, .so.x.y.z. Usually only one .so file is real, the other two are symlinked to it. Copy the $PKG_PREFIX/include files to the 32-bit environment at /usr/DFS/cross220/local/include directory and copy the library files to /usr/DFS/cross220/local/lib directory.

Stage 3B: Build a native compiler with the cross compiler

The configuration of the next generation compiler is similar to the cross compiler +except there is no sysroot+, and the host value is the same as the target rather than the build machine. We don't want to overwrite the stage 2 compiler, so we designate a new directory of /usr/DFS/crosstools220/native as the location for the native 64-bit compiler. We also need to redefine the path so that the previous Ada compilers don't get picked up by the build script (gnatmake and gnatbind are at risk of this). A sample configuration file for this 64-bit native compiler follows:

  #!/bin/sh

  NATIVE_HOST=i386-portbld-freebsd8.0
  DFLY_TARGET=x86_64-backplane-dragonfly2.6
  XCOM_SYSROOT=/usr/DFS
  PREFIX=$XCOM_SYSROOT/cross220
  PKGS=$PREFIX/local
  CC=$PREFIX/bin/$DFLY_TARGET-gcc

  PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PREFIX/bin:/usr/local/sbin:/usr/local/bin
  export PATH CC

  ../gcc-4.5-20100401/configure
   --enable-languages=c,ada
   --build=$NATIVE_HOST
   --host=$DFLY_TARGET
   --target=$DFLY_TARGET
   --program-prefix=$DFLY_TARGET-
   --prefix=$PREFIX/native
   --with-system-zlib
   --with-gmp=$PKGS
   --with-mpc=$PKGS
   --with-mpfr=$PKGS
   --with-libiconv-prefix=$PKGS
   --enable-threads=single
   --disable-bootstrap
   --disable-shared
   --disable-multilib
   --disable-libmudflap
   --disable-libgomp
   --disable-libssp
   --disable-nls

Don't forget to move to the work/build directory and type "gmake install" when you finally get the compiler built.

Stage 4

Stage 4: Bootstrap x86_64 Compiler on Foreign Platform

At this point you should have a 64-bit compiler located at /usr/DFS/cross220/native directory. The subdirectories of interest are bin, lib, and libexec.

  # cd /usr/DFS/cross220/native
  # strip bin/*
  # strip libexec/gcc/x86_64-backplane-dragonfly2.6/4.5.0/*
  # tar -cyf native_compiler.tar.bz2 bin lib libexec

Transfer this tarball to the 64-bit machine and unzip it in a standard location such as /usr/local/

Theoretically you have a fully functioning compiler, but it's highly recommended that you only use it to build a fully bootstrapped version of itself, and overwrite it in the same location with its child.

That's the process. Enjoy!

Last edited Fri May 24 16:28:01 2013
© 2010 John Marino | design elements by styleshout | artwork by Arturo Aguirre