We are currently building the compiler for macOS using omnibus, bundling arm64 and x86_64 binaries together in a universal build. You can find the details in the distribution-scripts repository, in particular the ./darwin and ./omnibus folders. Note: it’s not trivial. You can also take a look into the specific commit that brought the universal build.
Not sure if your insinuating that, but I don’t think omnibus plays any particular role for this.
I’m not an expert on macOS but as far as I understand it, the process is technically relatively straight forward: You build two exectuables, one for x86_64 and one for aarch64, and then merge them together with lipo. Cross-compiling should be possible from either architecture to the other, so you can do all on a single machine. The tricky part is that you also need two versions of all the libraries.
@straight-shoota is 100% correct. lipo will create a universal/fat binary for multiple architectures. I’ve got an old script combine.sh on my machine which I used to use to merge PPC and Intel binaries about 15 years ago:
As mentioned, the challenge is to generate the binaries for the different architectures. I seem to recall (when I wrote combine.sh), my PPC and Intel binaries were generated by platform buildservers (I had a PPC/Mac and Intel/Mac). I fetched the binaries with scp and combine.sh creates the universal.
If you use this strategy, I think your binaries will work correctly as crystal compiled binaries depend on libraries in /usr/lib which are installed by Apple.
634 rmills@rmillsm1:~/gnu/crystal/hello/src $ cat hello.cr
#!/usr/bin/env crun
# TODO: Write documentation for `Hello`
module Hello
VERSION = "0.1.0"
puts "Hello World!"
end
635 rmills@rmillsm1:~/gnu/crystal/hello/src $ /opt/crystal/bin/crystal build hello.cr
636 rmills@rmillsm1:~/gnu/crystal/hello/src $ ./hello
Hello World!
637 rmills@rmillsm1:~/gnu/crystal/hello/src $ otool -L ./hello
./hello:
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
638 rmills@rmillsm1:~/gnu/crystal/hello/src $
By the way there’s Apple magic in macOS 11 and later (Big Sur, Monterey, Ventura) and files such as /usr/lib/libiconv.2.dylib are not on the File System. The dynamic loader dyld locates them in a secret and safe location (presumably for security reasons).
I’ve thought a little more about this. In the good old days of PPC/Intel “fat” binaries, I could build PPC and Intel on the same machine. You could pass arguments such as -arch ppc to the compiler/linker (gcc in those days).
I believe LLVM will be similar.
So when crystal build foo.cr calls LLVM, you should modify that code. You may have to invoke LLVM twice and use lipo to combine the results. It’s likely that LLVM (or Apple’s clang) can handle multiple architectures simultaneously.
Happy to get involved in working with you on this.