AArch64 cross toolchain

The community has long expressed interest in supporting Ada on ARM64 and Apple Silicon platforms. Unfortunately, GitHub Action Runners are not available for ARM for open-source projects. The publication of the Ada extension for VS Code (as well as Alire) relies on GitHub Actions, limiting ARM support. However, it turns out that creating an ARM version is still possible, and I’d like to share my experience with using cross-compilers for this purpose.

Through the actions described below, I managed to obtain two cross-compilers for the aarch64 CPU (running on x86_64), one for Linux and the other for macOS. These proved sufficient to build ALS and VSCode extensions for these platforms.

I began by building the Ada Language Server version for ARM64/Linux since this platform is more familiar to me. Ubuntu provides cross-versions of dependencies for GNAT (glibc, binutils). Ubuntu even has GNAT GCC 13, but on newer versions than the one (20.04) we use for ALS building. The first thing I did was attempt to rebuild GCC 13 on Ubuntu 20.04 from the source package of the latest Ubuntu distribution (23.10). Although this might be the most correct method from a reuse perspective, it didn’t suit me - too many packages and installation steps.

Building GNAT from the GCC 13 source texts proved much simpler. The resulting script was just a dozen lines long.

      sudo apt remove -y gcc binutils
      sudo apt autoremove -y
      sudo apt install -y libc6-dev-arm64-cross linux-libc-dev-arm64-cross binutils-aarch64-linux-gnu libc6-dev texinfo bison m4 flex
      curl -L https://github.com/alire-project/GNAT-FSF-builds/releases/download/gnat-13.2.0-1/gnat-x86_64-linux-13.2.0-1.tar.gz | tar xzf -
      curl -L https://ftp.gwdg.de/pub/misc/gcc/releases/gcc-13.2.0/gcc-13.2.0.tar.xz |tar xJf -
      export PATH=$PWD/gnat-x86_64-linux-13.2.0-1/bin:$PATH
      cd gcc-13.2.0
      echo '--ipv4' >> ~/.curlrc
      ./contrib/download_prerequisites
      mkdir ../build
      cd ../build
      CC="x86_64-pc-linux-gnu-gcc" CXX="x86_64-pc-linux-gnu-g++" \
      ../gcc-13.2.0/configure \
        --prefix=/usr \
        --enable-languages=c,ada,c++ \
        --enable-libstdcxx --enable-libstdcxx-threads --enable-libada --disable-nls \
        --without-libiconv-prefix --disable-libstdcxx-pch --enable-lto \
        --libdir=/usr/lib --includedir=/usr/aarch64-linux-gnu/include --with-sysroot=/ \
        --without-target-system-zlib --program-prefix=aarch64-linux-gnu- \
        --with-gnu-ld --with-gnu-as \
        --target=aarch64-linux-gnu --build=x86_64-pc-linux-gnu
      make -j4 all
      make install-strip DESTDIR=$PWD/../destdir
      # missing files required to rebuild RTS
      cp -v gcc/ada/rts/*.{c,h,gpr,lst} ../gcc-13.2.0/libgcc/unwind-pe.h \
         ../destdir/usr/lib/gcc/aarch64-linux-gnu/13.2.0/adainclude/
      cd ..
      tar cavf aarch64-Linux-gcc-13.2.tar.bz2 -C destdir .

If you unpack the resulting archive in /, gprbuild finds the cross-compiler and using it subsequently is straightforward: you just need to specify the option --target=aarch64-linux.

Mac OS also provides cross-versions of binutils and libc, which come with the standard installation of Xcode Command Line Tools. For example, /usr/bin/as can create object files for both x86_64 and aarch64, depending on the --target. Therefore, we only need to build GNAT using the GCC sources from the repository iains/gcc-13-branch.

      brew install texinfo bison m4 flex
      curl -L https://github.com/alire-project/GNAT-FSF-builds/releases/download/gnat-13.2.0-1/gnat-x86_64-darwin-13.2.0-1.tar.gz | tar xzf -
      git clone --depth=1 https://github.com/iains/gcc-13-branch gcc-13.2.0
      export PATH=$PWD/gnat-x86_64-darwin-13.2.0-1/bin:$PATH
      cd gcc-13.2.0
      ./contrib/download_prerequisites
      mkdir ../build
      cd ../build
      CC="x86_64-apple-darwin21.6.0-gcc" CXX="x86_64-apple-darwin21.6.0-g++" \
      ../gcc-13.2.0/configure \
        --prefix=/usr/local \
        --enable-languages=c,ada,c++ \
        --enable-libstdcxx --enable-libstdcxx-threads --enable-libada --disable-nls \
        --without-libiconv-prefix --disable-libstdcxx-pch \
        --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk \
        --without-target-system-zlib \
        --with-as=/usr/bin/as --with-ar=/usr/bin/ar --with-ld=/usr/bin/ld \
        --with-dsymutil=/usr/bin/dsymutil --with-ranlib=/usr/bin/ranlib \
        --disable-multilib --disable-libcilkrts --without-build-config \
        --with-specs='%{!sysroot=*:--sysroot=%:if-exists-else(/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk)}'\
        --target=aarch64-apple-darwin21.6.0 --build=x86_64-apple-darwin21.6.0 \
        AS_FOR_TARGET=/usr/bin/as LD_FOR_TARGET=/usr/bin/ld \
        NM_FOR_TARGET=/usr/bin/nm RANLIB_FOR_TARGET=/usr/bin/ranlib \
        AR_FOR_TARGET=/usr/bin/ar LIPO_FOR_TARGET=/usr/bin/lipo \
        DSYMUTIL_FOR_TARGET=/usr/bin/dsymutil \
        STRIP_FOR_TARGET=/usr/bin/strip

      make -j4 all
      make install-strip DESTDIR=$PWD/../destdir
      # missing files required to rebuild RTS
      cp -v gcc/ada/rts/*.{c,h,gpr,lst} ../gcc-13.2.0/libgcc/unwind-pe.h \
         ../destdir/usr/local/lib/gcc/aarch64-apple-darwin21.6.0/13.2.0/adainclude/
      cd ..
      tar cavf aarch64-macOS-gcc-13.2.tar.bz2 -C destdir .

If you need binaries for these cross-compilers or have ideas on how to use them, please leave a comment in this thread.

PS Thanks to Simon Wright for experimenting with Mac OS and providing advices.

1 Like

Good work!

I’ve been advised (can’t find where) not to use --with-build-config=no, which I think is the same as your --without-build-config (but build-config doesn’t appear in the GCC configuration documentation!)

I wrote up some notes about installing aarch64 compilers with Alire.

2 Likes