Support building the aarch64 cross-compiler on macOS - #171
Conversation
3032513 to
195c1b9
Compare
|
We could split this pull request into several parts, including one concerning A conservative approach would be to apply the change only to macOS, where it appears that
We can then properly iterate through the rest (the |
Add a macOS/arm64 host case: configure.sh accepts a clang / ld.lld / llvm-objcopy ELF cross toolchain and resolves the keg-only Homebrew llvm-objcopy to an absolute path. solo5-cross-aarch64 cross-compiles with those tools, declares the llvm + lld depexts, and a CI job builds it on macos-latest. The toolchain is pure LLVM: no libgcc is bundled. The downstream link needs none: ocaml-solo5's nolibc no longer pulls long double soft-float and its wrapper does not pass -lgcc (mirage/ocaml-solo5#171).
Add a macOS/arm64 host case: configure.sh accepts a clang / ld.lld / llvm-objcopy ELF cross toolchain and resolves the keg-only Homebrew llvm-objcopy to an absolute path. solo5-cross-aarch64 cross-compiles with those tools, declares the llvm + lld depexts, and a CI job builds it on macos-latest. The toolchain is pure LLVM: no libgcc is bundled. The downstream link needs none: ocaml-solo5's nolibc no longer pulls long double soft-float and its wrapper does not pass -lgcc (mirage/ocaml-solo5#171).
|
Thanks, I'll split the nolibc double/long double change into its own PR with the context. One clarification on the conservative approach: this is a property of the target, not the macOS host. The cross targets aarch64-linux-gnu (via clang -target), where long double is IEEE binary128 (quad), so printf pulls in __extenddftf2/__trunctfdf2 regardless of whether we build on macOS or Linux. On Linux the cross toolchain is gcc and libgcc supplies those routines; the LLVM-only macOS toolchain has no libgcc, which is why the link fails there. Since it's really "nolibc's printf shouldn't require quad soft-float" (useful to any freestanding aarch64 target, not only macOS), I'd lean to keeping it unconditional, but I'm happy to gate it to the macOS build if you'd prefer. Then we can iterate on configure.sh and the CI. |
shym
left a comment
There was a problem hiding this comment.
If I trust CI builds, I think that #179 would avoid the need for the no-asm-operand-widths fix.
For the changes in gen_toolchain_tool.sh, I think I’m missing something: the resolved variable allow to work around the fact that some tools are in PATH during the build of the OCaml/Solo5 package but they won’t be later when using the cross compiler. Is that it? If so, why is that happening?
If that’s indeed the case, I’d suggest adding a configuration option, for instance --toolchain-use-absolute-path, that would enable that behaviour only when needed (I’m thinking of all the efforts put into avoiding absolute paths in OCaml, so I’d try to avoid absolute paths to come back when not absolutely needed (pun intended)).
| if ! command -v "${MAKECONF_TOOLPREFIX}ar" >/dev/null 2>&1; then | ||
| for bindir in \ | ||
| "$(command -v brew >/dev/null 2>&1 && brew --prefix llvm 2>/dev/null)/bin" \ | ||
| /opt/homebrew/opt/llvm/bin /usr/local/opt/llvm/bin \ | ||
| /opt/local/libexec/llvm-*/bin; do | ||
| if [ -x "${bindir}/${MAKECONF_TOOLPREFIX}ar" ]; then | ||
| MAKECONF_TOOLPREFIX="${bindir}/${MAKECONF_TOOLPREFIX}" | ||
| break | ||
| fi | ||
| done | ||
| fi |
There was a problem hiding this comment.
This is modifying MAKECONF_TOOLPREFIX which was set by the user so I think this could have unintended consequences. I wonder if we could make it more robust by using a defined depext so that the path we look for is fixed (this might be a naïve suggestion from a homebrew non-user) and use it when the user asked explicitly for absolute paths with a configure option.
|
@shym thanks, I think I've addressed all your comments. |
b399315 to
b057f0e
Compare
On targets where long double is IEEE quad (aarch64), vfprintf's `union arg` held the float value as long double, so `%f` (and the fmt_fp call) round-tripped double -> long double -> double through __extenddftf2/__trunctfdf2. That pulls libgcc (or compiler-rt) soft-float into every freestanding link that uses printf, even for integer-only formats. fmt_fp already takes a double, so the long double was pure overhead. Use double for the field; %L float conversions are treated as double (never used by OCaml unikernels). aarch64 cross unikernels now link with no libgcc at all (clang already inlines the atomics).
The aarch64 wrapper linked -lgcc for printf's long-double soft-float (now gone: printf formats as double) and for GCC's default outline atomics (-moutline-atomics lowers C11 atomics to __aarch64_* helpers in libgcc, which also pull __getauxval, absent on a freestanding solo5 target). Pass -mno-outline-atomics so atomics inline (LL/SC); the link then needs no compiler runtime, so drop -lgcc and let a pure-LLVM toolchain link aarch64 unikernels.
Accept a macOS/arm64 host. The OCaml cross build uses the llvm- toolprefix, and --toolchain-use-absolute-path pins the keg-only Homebrew llvm tools (off PATH when the cross compiler is later used) to absolute paths; other hosts keep bare, relocatable tool names. Build the nolibc/openlibm archives with the toolprefix ar/ranlib (Apple's cannot index ELF), and suppress -Wasm-operand-widths in nolibc (openlibm's aarch64 fenv asm trips clang under -Werror). Patch Makefile.cross so crossopt does not pass -function-sections to the host .opt tools (the macOS host ocamlopt is Mach-O and rejects it), keeping it for the target library so the linker can still garbage-collect unused code. Add a macOS CI job building the cross-compiler.
Add a macOS/arm64 host case: configure.sh accepts a clang / ld.lld / llvm-objcopy ELF cross toolchain and resolves the keg-only Homebrew llvm-objcopy to an absolute path. solo5-cross-aarch64 cross-compiles with those tools, declares the llvm + lld depexts, and a CI job builds it on macos-latest. The toolchain is pure LLVM: no libgcc is bundled. The downstream link needs none: ocaml-solo5's nolibc no longer pulls long double soft-float and its wrapper does not pass -lgcc (mirage/ocaml-solo5#171).
Add a macOS/arm64 host case: configure.sh accepts a clang / ld.lld / llvm-objcopy ELF cross toolchain and resolves the keg-only Homebrew llvm-objcopy to an absolute path. solo5-cross-aarch64 cross-compiles with those tools, declares the llvm + lld depexts, and a CI job builds it on macos-latest. The toolchain is pure LLVM: no libgcc is bundled. The downstream link needs none: ocaml-solo5's nolibc no longer pulls long double soft-float and its wrapper does not pass -lgcc (mirage/ocaml-solo5#171).
|
I'm moving this to draft as @shym as kindly taken over this. |
I'd like to cross-compile aarch64 Solo5/MirageOS unikernels on an Apple Silicon Mac.
This adds a macos/arm64 target to
ocaml-solo5-cross-aarch64. The OCaml cross build runs through thellvm-toolprefix; a new--toolchain-use-absolute-pathconfigure option pins the keg-only Homebrew llvm tools (off PATH when the cross compiler is later used) to absolute paths, while every other host keeps bare, relocatable tool names. The nolibc/openlibm archives are built with the toolprefixar/ranlib(Apple's cannot index ELF), andsolo5is dropped from the macOS dependencies (only the cross toolchain and headers fromsolo5-cross-aarch64are needed there). A CI job builds the cross-compiler on macos-latest.The first two commits are #177 (printf as
double+ drop-lgcc), the libgcc-free change this builds on; they fall out once #177 merges. Per @shym's review I also dropped the-Wno-asm-operand-widthsworkaround, which #179 (openlibm v0.8.7) makes unnecessary — so the macOS CI job here stays red until #179 lands, then it is clean.Companion: Solo5/solo5#641 builds
solo5-cross-aarch64on macOS.Supersedes #168.