Dr. Brian Robert Callahan
academic, developer, with an eye towards a brighter techno-social life
After getting a port of GDC working on my new MacBook Pro, there are still two languages left in the GCC suite that I don't have: Ada and Go. Some searching around makes it seem pretty clear that Gccgo is not yet really on the table to macOS. But there should not be any reason we can't add Ada to our GCC suite, seeing as there is already support for macos/aarch64 in the repository. I wanted to get a macOS/aarch64 native Ada through the GNAT compiler in GCC.
But try as I might, I could not find any precompiled packages for it. I guess part of the issue is that macOS/aarch64 support is not fully upstreamed into GCC propre; instead, Iain Sandoe has a GitHub repository that includes the necessary changes for full support. I used his gcc-14-branch repository to build GDC.
So let's get to work.
I don't have Rosetta on my machine. I know it takes all of two seconds to install it, but I also wanted an excuse to play around with Apple's virtualization framework. After some googling around, I settled on using VirtualBuddy as my virtualization manager. It made installing a virtualized copy of Sequoia 15.2 incredibly easy; just say you want to install from the Internet, choose the version you want to install, and away you go. I gave my virtualized machine 4 CPUs and 16 GB of RAM and a 128 GB hard disk, and it felt just as snappy as the host (the host is a MacBook Pro M4 Max with 64 GB of RAM). I installed the command line tools, Rosetta, and some Homebrew packages on this virtualized machine and I was ready to go.
So why did I install Rosetta? My suspicion was that someone had a binary package of GNAT for macOS/x86_64. But I looked in the usual places: Homebrew, pkgsrc, MacPorts, and Fink, and none of them had a package. I was beginning to wonder if our project was going to end before it began. Because GNAT is written in Ada, you need an Ada compiler to compile it.
I eventually stumbled upon Alire which bills itself as Ada's version of Rust's cargo or OCaml's opam. The Alire homepage directly states that they have a recent Ada package for macOS/x86_64. This was our way in. I followed the tutorial to get the alr
binary installed on the virtual machine and got a copy of the GNAT compiler, which happened to be version 14.2.0. That's great, because that's the same version we built with our GDC compiler, and what we will be building from the gcc-14-branch repository.
The compiler was built for a x86_64-apple-darwin21.6.0
target. We will use this to get to a aarch64-apple-darwin24.2.0
target.
I added this Alire-provided GNAT to my PATH
and set up the gcc-14-branch repository to prepare to build. Make sure it goes at the front of your PATH
so that clang doesn't get picked up instead. I did run the contrib/download_prerequisites
script so that GMP, MPFR, MPC, and ISL would be built statically into GCC; that way I don't have to deal with any shared libraries and they're not that big so it won't take long to build them.
This first pass we need to build a compiler that is built (effectively) from macOS/x86_64, will run on (effectively) macOS/x86_64, but produces code that runs on macOS/aarch64. We also need to remember that all the build tools understand both x86_64 and aarch64; that will be a big help for us. To start, we can run a configure
invocation that looks like this:
env OTOOL=otool AS=as AR=ar RANLIB=ranlib LIPO=lipo NM=nm DSYMUTIL=dsymutil ../gcc-14-branch-gcc-14.2-darwin-r2/configure --prefix=/opt/gcc14 --enable-languages=ada,c,c++ --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk --build=x86_64-apple-darwin21.6.0 --host=x86_64-apple-darwin21.6.0 --target=aarch64-apple-darwin24.2.0 --disable-nls --with-ld=/usr/bin/ld --with-as=/usr/bin/as
Then we can run our build with:
gmake V=1 -j4
I installed GNU make from Homebrew since that is much newer than what I got from the command line tools.
For now, I am only going to worry about getting GNAT up and running; once we have it then I can worry about combining GNAT and GDC together into one suite.
I did encounter a few build failures but these all seemed to revolve around autotools wanting prefixed versions of the tools; I would just edit Makefile
s and re-run gmake
when that happened. Eventually it did succeed and so I installed it into a fake directory, tarred it up, and then installed it on the virtual machine.
Now we can use this new compiler to build another new compiler. This new compiler will be built with the compiler we just built: because the compiler we just built produces code for aarch64-apple-darwin24.2.0
, even though it runs on x86_64-apple-darwin21.6.0
, once it is finished compiling GCC, that GCC will be a native macOS/aarch64 compiler.
We'll need to reset our PATH
to get rid of the Alire-provided compiler. We don't need it any more. We do need to add the compiler we just built to our PATH
as that will be used to create our native compiler.
Let's create a new build directory and run our configure
invocation as follows:
env OTOOL=otool AS=as AR=ar RANLIB=ranlib LIPO=lipo NM=nm DSYMUTIL=dsymutil ../gcc-14-branch-gcc-14.2-darwin-r2/configure --prefix=/opt/gcc14 --enable-languages=ada,c,c++ --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk --build=x86_64-apple-darwin21.6.0 --host=aarch64-apple-darwin24.2.0 --target=aarch64-apple-darwin24.2.0 --disable-nls --with-ld=/usr/bin/ld --with-as=/usr/bin/as
So what we are saying here is that our build machine is (effectively) macOS/x86_64 but we would like to build a compiler that runs on macOS/aarch64 and produces code for macOS/aarch64. A compiler that produces code for the platform it runs on is a native compiler.
This failed very quickly. Turns out the stage 1 collect2
binary was miscompiled and segfaults when it is used. What I did to overcome this was copy the native collect2
binary from my GDC compiler to the GNAT compiler. Everything was happy after that.
Now, we can compile with:
gmake V=1 -j4
Like with the stage 1 compiler, there are some intermittent build failures. But none of these are catastrophic; it is a matter of just editing the Makefile
s in question and re-running gmake
. The most difficult error was that when linking libstdc++.dylib
, there was a linker error that you were linking the library with a library of the same name. The problem is that the infrastructure incorrectly wanted to link with g++
instead of gcc
. There is a comment in the right place in the Makefile
so it's relatively clear that you just need to replace g++
with gcc
and it will work. I've never had that problem before so perhaps it is something with cross compiling.
Eventually it will complete successfully, and then same thing: I installed to a fake directory, removed the stage 1 compiler, then tarred and installed the stage 2 compiler.
Now that I have a native GNAT for macOS/aarch64, I want one single GCC package that will have all the languages that are available: Ada, C, C++, D, Fortran, Modula-2, Objective-C, and Objective-C++. I moved the tarball of the stage 2 GNAT compiler to my host machine, shutdown the virtual machine, and installed the stage 2 compiler. I then put the stage 2 compiler in front of the GDC compiler in my PATH
and built the gcc-14-branch compiler one last time:
../gcc-14-branch-gcc-14.2-darwin-r2/configure --prefix=/opt/gcc14 --enable-languages=ada,c,c++,d,fortran,m2,objc,obj-c++ --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk
That's all we need now. All of build, host, and target are aarch64-apple-darwin24.2.0
, a fully native compiler. And GCC will detect that automatically and create a new native compiler.
One last time to build GCC, but let's go a little faster now that we have more CPU cores:
gmake V=1 -j10
This built without any problems. Then for one last time, install to a fake directory, tar it up, remove the old stage 2 compiler and old GDC compiler, and install this new complete GCC suite.
I've uploaded the tarball here for those that want it. You will need to have the command line tools installed. If someone knows how to get GCC to autoselect between Xcode and the command line tools, please let me know. You'll also need to put /opt/gcc14/bin
at the front of your PATH
to use it.
Even better, now no one will ever have to go through the hassle of bringing up Ada support on macOS/aarch64 again. We now have a compiler that can be used as a bootstrap for future releases of GCC. Maybe we'll even have some package managers provide GNAT compilers since the hard work has been done.