I used the [Dialog sample] from Retro68 as the basis of my Mac app. Here it is
running prior to Rust integration:
{{ figure(image="posts/2023/rust-on-ppc-classic-mac-os/dialog-sample.png", link="posts/2023/rust-on-ppc-classic-mac-os/dialog-sample.png", alt="Screenshot of SheepShaver running Mac OS 8.1. It shows some Finder windows with a frontmost dialog that has a text label, text field, radio buttons, check box and Quit button.", caption="Dialog Sample") }}
This is my tweaked version of the C file:
```c
/*
Copyright 2015 Wolfgang Thaller.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Quickdraw.h>
#include <Dialogs.h>
#include <Fonts.h>
#ifndef TARGET_API_MAC_CARBON
/* NOTE: this is checking whether the Dialogs.h we use *knows* about Carbon,
not whether we are actually compiling for Cabon.
If Dialogs.h is older, we add a define to be able to use the new name
for NewUserItemUPP, which used to be NewUserItemProc. */
to `CMakeLists.txt` to have CMake link with the Rust library.
{{ figure(image="posts/2023/rust-on-ppc-classic-mac-os/ParamText.jpg", link="posts/2023/rust-on-ppc-classic-mac-os/ParamText.jpg", alt="Photo of ParamText documentation from my copy of Inside Macintosh Volume Ⅰ", caption="ParamText documentation from my copy of Inside Macintosh Volume Ⅰ") }}
/home/wmoore/Source/github.com/autc04/Retro68-build/toolchain/lib/gcc/powerpc-apple-macos/9.1.0/../../../../powerpc-apple-macos/bin/ld:/home/wmoore/Projects/classic-mac-rust/target/powerpc-apple-macos/release/libclassic_mac_rust.a: file format not recognized; treating as linker script
Examining the objects in the new archive showed that they were now in the same
format as the objects generated by Retro68. I updated the `CMakeLists.txt` to
point at the new library and tried building again:
```
/home/wmoore/Source/github.com/autc04/Retro68-build/toolchain/lib/gcc/powerpc-apple-macos/9.1.0/../../../../powerpc-apple-macos/bin/ld: /home/wmoore/Projects/classic-mac-rust/target/powerpc-apple-macos/release/libclassic_mac_rust.obj(classic_mac_rust-80e61781bab75910.classic_mac_rust.9ba2ce33-cgu.0.rcgu.o): class 2 symbol `hello_rust' has no aux entries
```
Now we get further. It can read the `.a` now and even sees the `hello_rust`
symbol but it
[looks like it's looking for an aux entry to determine the symbol type](https://github.com/autc04/Retro68/blob/5f882506013a0a8a4335350197a1b7c91763494e/binutils/bfd/xcofflink.c#L1461-L1478)
One other thing I tried was setting the `llvm-target` in the custom target JSON
to `powerpc-ibm-aix`. Due to the heritage of PPC Mac OS the ABI is the same
(Apple used the AIX toolchain, which is why object files use XCOFF even though
executables use PEF). This target would be ideal as it would use the right ABI
and emit XCOFF by default.
Unfortunately it runs into unimplemented parts of LLVM's XCOFF implementation:
> LLVM ERROR: relocation for paired relocatable term is not yet supported
Rust uses a fork/snapshot of LLVM but the
[issue is still present in LLVM master](https://github.com/rust-lang/llvm-project/blob/5ef9f9948fca7cb39dd6c1935ca4e819fb7a0db2/llvm/lib/MC/XCOFFObjectWriter.cpp).
[This post on writing a Mac OS 9 application in Swift][swift] goes down a
similar path using the AIX target and also mentions patching the Swift compiler
to avoid the unsupported parts of LLVMs XCOFF implementation. That's an avenue
for future experimentation.
### rustc\_codegen\_gcc
At this point I decided to try a different approach.
[rustc\_codegen\_gcc](https://github.com/rust-lang/rustc_codegen_gcc) is a
codegen plugin that uses [libgccjit] for code generation instead of LLVM. The
motivation of the project is promising for my use case:
> The primary goal of this project is to be able to compile Rust code on
> platforms unsupported by LLVM.
I found the instructions for using `rustc_codegen_gcc` a bit difficult to
follow, especially when trying to build a cross-compiler.
I eventually managed to rebuild Retro68 with `libgccjit` enabled and then coax
`rustc_codegen_gcc` to use it. Unsurprisingly that quickly failed as Retro68 is
based on GCC 9.1 and `rustc_codegen_gcc` is building against GCC master and
there were many missing symbols.
Undeterred I noted that there is a WIP GCC 12.2 branch in the Retro68 repo so I
built that and tweaked `rustc_codegen_gcc` to disable the `master` cargo
feature that should in theory allow it to build against a GCC release. This did
in fact allow me to get a bit further but I ran into more issues in the step
that attempts to build `compiler-rt` and `core`. Eventually I gave up on this
route too. I was probably too far off the well tested configuration of x86,
against GCC master.
Future work here is to trying building a `powerpc-ibm-aix` libgccjit from GCC
master and see if that works.
### Wrap Up
[Bastian on Twitter](https://twitter.com/turbolent/status/1617231570573873152)
has had some success compiling Rust to Web Assembly, Web Assembly to C89, C89
to Mac OS 9 binary, which is definitely cool but I would still love to be able
to generate native PPC code directly from `rustc` somehow.
This is where I have parked this project for now. I actually only discovered
the post on building a Mac OS 9 application with Swift while writing this post.
There are perhaps some ideas in there that I could explore further.