Jayesh Bhoot's Ghost Town

Spoonfeeding machine architecture to OCaml toolchain on Apple Silicon§

Post author's photo Written by Jayesh Bhoot Published on

  1. Spoonfeeding machine architecture to OCaml toolchain on Apple Silicon
    1. Problem
    2. Hacky solution
    3. Update () : Better solution
    4. Comments

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.

Comments§