Spoonfeeding machine architecture to OCaml toolchain on Apple Silicon
Posted on in OCaml
Problem
OCaml compiler failed to build on my M1 Macbook with Apple's Silicon architecture.
$ opam switch create . 4.14.1 -y --deps-only
<><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><> 🐫
Switch invariant: ["ocaml-base-compiler" {= "4.14.1"} | "ocaml-system" {= "4.14.1"}]
[NOTE] External dependency handling not supported for OS family 'macos'.
You can disable this check using 'opam option --global depext=false'
<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><> 🐫
∗ installed base-bigarray.base
∗ installed base-threads.base
∗ installed base-unix.base
∗ installed ocaml-options-vanilla.1
⬇ retrieved ocaml-base-compiler.4.14.1 (cached)
[ERROR] The compilation of ocaml-base-compiler.4.14.1 failed at
"make -j7".
#=== ERROR while compiling ocaml-base-compiler.4.14.1 ===========#
# context 2.1.5 | macos/arm64 | | https://opam.ocaml.org#bc52affc
# path ~/projects/aoc-2023/ocaml/_opam/.opam-switch/build/ocaml-base-compiler.4.14.1
# command ~/.opam/opam-init/hooks/sandbox.sh build make -j7
# exit-code 2
# env-file ~/.opam/log/ocaml-base-compiler-11985-7b627b.env
# output-file ~/.opam/log/ocaml-base-compiler-11985-7b627b.out
### output ###
# [...]
# signals_nat.c:221:5: error: no member named '__pc' in 'struct __darwin_x86_thread_state64'
# CONTEXT_PC = (context_reg) &caml_stack_overflow;
# ^~~~~~~~~~
# ./signals_osdep.h:182:37: note: expanded from macro 'CONTEXT_PC'
# #define CONTEXT_PC (CONTEXT_STATE.__pc)
# ~~~~~~~~~~~~~ ^
# 4 errors generated.
# make[3]: *** [signals_nat.n.o] Error 1
# make[3]: *** Waiting for unfinished jobs....
# make[2]: *** [makeruntimeopt] Error 2
# make[1]: *** [opt.opt] Error 2
# make: *** [world.opt] Error 2
<><> Error report <><><><><><><><><><><><><><><><><><><><><><> 🐫
┌─ The following actions failed
│ λ build ocaml-base-compiler 4.14.1
└─
┌─ The following changes have been performed (the rest was aborted)
│ ∗ install base-bigarray base
│ ∗ install base-threads base
│ ∗ install base-unix base
│ ∗ install ocaml-options-vanilla 1
└─
<><> ocaml-base-compiler.4.14.1 troubleshooting <><><><><><><> 🐫
=> A failure in the middle of the build may be caused by build
parallelism
(enabled by default).
Please file a bug report at
https://github.com/ocaml/opam-repository/issues
=> You can try installing again including --jobs=1
to force a sequential build instead.
Switch initialisation failed: clean up? ('n' will leave the
switch partially installed) [Y/n] y
Hacky solution
If you have the same issue, then try specifying the architecture explicitly.
$ arch -arm64 opam switch create . 4.14.1 -y --deps-only
Apply the same approach to install packages too.
$ arch -arm64 opam install dune
There has to be a better way though.
P.S.: Even dune does not work without it!
$ arch -arm64 dune exec bin/main.exe
Update () : Better solution
JM from OCaml discord helped me to discover the underlying issue - my Terminal.app was running in Rosetta mode. I had configured it to run on Rosetta during the initial Silicon-Rosetta churn, but forgotten all about it.
So, opam, which uses uname -a
to find the
underlying architecture, always got x86_64
.
Once I unchecked the Open using Rosetta option, arch -arm64
was no longer needed.
From what I understand, if any tool or binary across a
toolchain is configured to run through Rosetta - be it the Terminal.app, or the shell, or a helper binary like uname
- then the program using this toolchain could end up using the wrong architecture.