Thursday, June 18, 2026

Building an Ada Cross-Compiler

Introduction

I previously described how to build a SPARC V9 cross-compiler for the C programming language in this article: SPARC V9 Boot Process – Part 2: sysboot. The resulting cross-compiler was used to compile a SPARC V9 bootloader written predominantly in C.

For complex software development, Ada is a far more suitable programming language than C. My next goal is to rewrite the bootloader in Ada, which requires building an Ada cross-compiler along with several additional development tools.

My build platform is Linux on ARM aarch64 and my target platform is bare metal sparc64. Building an Ada compiler requires an existing Ada compiler on the host system for bootstrapping. Ada compilers are available for many operating systems and can usually be installed through the operating system's package management tools.

$ /bin/gnat --version
GNAT 12.2.0
Copyright (C) 1996-2022, Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

I have a native GNAT Ada compiler 12.2.0 that can be used to build a new Ada cross-compiler. The steps required to achieve this are described below.

1. Download Source Code

The first step is to download the required development tools. These consist of Binutils, GCC, XML Ada, and GPRbuild.

# Create various build directories
BUILD_ROOT="${HOME:?}/gcc_build" &&
TAR_DIR="${BUILD_ROOT:?}/tar" &&
SRC_DIR="${BUILD_ROOT:?}/src" &&
OBJ_DIR="${BUILD_ROOT:?}/obj"
mkdir -p ${TAR_DIR:?} ${SRC_DIR:?} ${OBJ_DIR:?}

# Download the latest Binutils, GCC, XML Ada, and GPRbuild
BINUTILS_VER="2.46.0" &&
GCC_VER="15.2.0" &&
GPRBUILD_VER="25.0.0" &&
GPRCONFIG_KB_VER="25.0.0" &&
XMLADA_VER="25.0.0" &&
cd ${TAR_DIR:?} &&
wget https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VER:?}.tar.gz &&
wget https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER:?}/gcc-${GCC_VER:?}.tar.gz &&
wget -O gprbuild-${GPRBUILD_VER:?}.tar.gz \
  https://github.com/AdaCore/gprbuild/archive/refs/tags/v${GPRBUILD_VER:?}.tar.gz &&
wget -O gprconfig_kb-${GPRCONFIG_KB_VER:?}.tar.gz \
  https://github.com/AdaCore/gprconfig_kb/archive/refs/tags/v${GPRCONFIG_KB_VER:?}.tar.gz &&
wget -O xmlada-${GPRCONFIG_KB_VER:?}.tar.gz \
  https://github.com/AdaCore/xmlada/archive/refs/tags/v${XMLADA_VER:?}.tar.gz

# Unpack all downloaded files
cd ${SRC_DIR:?} &&
for i in $(ls ${TAR_DIR:?}); do tar -xf ${TAR_DIR:?}/$i & done; wait

# Before building GCC we need to download a few prerequisites
cd ${SRC_DIR:?}/gcc-${GCC_VER:?} &&
/bin/sh contrib/download_prerequisites

2. Build Native Development Tools

The GCC documentation strongly recommends using a native Ada compiler that matches the version of the cross-compiler being built. Using a different version may lead to unexpected build failures. Therefore, in this step, I build a native Ada compiler that will later be used to bootstrap the corresponding Ada cross-compiler.

The native Ada compiler can also be used to build GPRbuild, a build system that integrates closely with Ada development tools while supporting multiple programming languages. Although the use of GPRbuild is optional and some developers may prefer traditional Makefiles, it can be particularly beneficial for managing large and complex projects. For this reason, instructions for building GPRbuild are included here.

# Set various build options
MAKE_JOBS=4 &&
PREFIX="${HOME:?}/gcc-${GCC_VER:?}_native" &&
PATH="${PREFIX:?}/bin:/bin:/usr/bin:/sbin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
unset LDFLAGS &&
export PATH CC CXX

# Build and install Binutils with static standard libs
pkg="binutils-${BINUTILS_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} --libdir=${PREFIX:?}/lib \
  --enable-shared --enable-64-bit-bfd \
  --with-static-standard-libraries --disable-nls &&
gmake -j ${MAKE_JOBS:?} && gmake install &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?}

# Build and install GCC
pkg="gcc-${GCC_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
mkdir -p ${PREFIX:?}/lib && ln -sf lib ${PREFIX:?}/lib64 &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} --libdir=${PREFIX:?}/lib \
  --enable-languages=c,ada --enable-shared \
  --disable-nls --disable-multilib &&
gmake --output-sync=target -j ${MAKE_JOBS:?} && gmake install &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?}

# Build and install temporary bootstrap gprbuild
# This will be used to build xmlada and final gprbuild
pkg="gprbuild-${GPRBUILD_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && cp -a ${SRC_DIR:?}/${pkg:?} ./ && cd ${pkg:?} &&
GNATMAKEFLAGS="-j${MAKE_JOBS:?}" ${SRC_DIR:?}/${pkg:?}/bootstrap.sh \
  --prefix=${PREFIX:?}/gprbuild_bootstrap \
  --with-xmlada=${SRC_DIR:?}/xmlada-${GPRCONFIG_KB_VER:?} \
  --with-kb=${SRC_DIR:?}/gprconfig_kb-${GPRCONFIG_KB_VER:?} &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?}

# Build and install xmlada
pkg="xmlada-${XMLADA_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && cp -a ${SRC_DIR:?}/${pkg:?} ./ && cd ${pkg:?} &&
PATH=${PREFIX:?}/gprbuild_bootstrap/bin:${PATH} \
  ${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} --libdir=${PREFIX:?}/lib &&
PATH=${PREFIX:?}/gprbuild_bootstrap/bin:${PATH} \
  gmake -j ${MAKE_JOBS:?} && gmake install &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?}

# Build and install final gprbuild
pkg="gprbuild-${GPRBUILD_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
PATH=${PREFIX:?}/gprbuild_bootstrap/bin:${PATH}
  gmake -f ${SRC_DIR:?}/${pkg:?}/Makefile \
  prefix=${PREFIX:?} SOURCE_DIR=${SRC_DIR:?}/${pkg:?} setup &&
PATH=${PREFIX:?}/gprbuild_bootstrap/bin:${PATH} \
  gmake -f ${SRC_DIR:?}/${pkg:?}/Makefile -j ${MAKE_JOBS:?} &&
PATH=${PREFIX:?}/gprbuild_bootstrap/bin:${PATH} \
  gmake -f ${SRC_DIR:?}/${pkg:?}/Makefile install &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?} &&
rm -rf ${PREFIX:?}/gprbuild_bootstrap

3. Build Target Development Cross Tools

In this step, the native Ada compiler built in the previous step, is used to build an Ada cross-compiler targeting the sparc64-unknown-elf architecture. Because this is a bare-metal target, the resulting compiler does not include an Ada runtime library. Without a runtime, the compiler is limited in the types of Ada programs it can build, as many language features depend on runtime support.

A future article will describe how to build a minimal Ada runtime and integrate it with the cross-compiler to support bare-metal Ada development projects.

# Set various build options
MAKE_JOBS=4 &&
BUILD="aarch64-unknown-linux-gnu" &&
HOST="${BUILD:?}" &&
TARGET="sparc64-unknown-elf" &&
PREFIX="${HOME:?}/gcc-${GCC_VER:?}_${TARGET:?}" &&
PATH="${PREFIX:?}/bin:${HOME:?}/gcc-${GCC_VER:?}_native/bin:/bin:/usr/bin:/sbin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
unset LDFLAGS &&
export PATH CC CXX

# Build and install Binutils with static standard libs
pkg="binutils-${BINUTILS_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} --libdir=${PREFIX:?}/lib \
  --build="${BUILD:?}" --host="${HOST:?}" --target="${TARGET:?}" \
  --enable-shared --enable-64-bit-bfd \
  --with-static-standard-libraries --disable-nls &&
gmake -j ${MAKE_JOBS:?} && gmake install &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?}

# Build and install GCC
pkg="gcc-${GCC_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
mkdir -p ${PREFIX:?}/lib && ln -sf lib ${PREFIX:?}/lib64 &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} --libdir=${PREFIX:?}/lib \
  --build="${BUILD:?}" --host="${HOST:?}" --target="${TARGET:?}" --with-cpu=v9 \
  --enable-languages=c,ada --enable-shared \
  --disable-nls --disable-multilib --disable-libssp --disable-libada &&
gmake --output-sync=target -j ${MAKE_JOBS:?} &&
gmake -C gcc --output-sync=target -j ${MAKE_JOBS:?} cross-gnattools &&
gmake -C gcc --output-sync=target -j ${MAKE_JOBS:?} ada.all.cross &&
gmake install &&
cd ${OBJ_DIR:?} && rm -rf ${pkg:?}

After completing the above steps, we obtain the following development tools:

${HOME}/gcc-15.2.0_native - This directory contains native C and Ada compilers and GPRbuild framework.

${HOME}/gcc-15.2.0_sparc64-unknown-elf - This directory contains sparc64 C and Ada cross-compilers.