How to build an OCaml cross compiler

After finding a way to generate the fitting configuration files for the target machine, the cross compiler itself must still be built. The approach using the 1 1/2 build described here (and, with more details, here) does not seem to work if the host and target systems differ too much. Here is the changed part of the build script (which can be obtained with $ svn cat svn://svn.psellos.com/trunk/ocamlxarm/3.1/xarm-build)

# Small steps
config1 () {
    # Configure for building bytecode interpreter to run on Intel OS X.
    # But specify * architecture for assembly and partial link.
    echo 'xarm-build: ----- configure phase 1 -----'
    ./configure \
            -prefix "" \
            -no-curses \
            -no-tk \
            -no-graph \
            -as "" \
            -aspp ""\
            -partialld ""
    # Post-modify config/Makefile to select the * back end for
    # ocamlopt (to generate * assembly code).
    $SED -i'.bak'\
        -e '1i\# modified by xarm-build for OCamlXARM' \
        -e 's/^ARCH[    ]*=.*/ARCH=/' \
        -e 's/^MODEL[    ]*=.*/MODEL=/' \
        config/Makefile
        #-e 's/^SYSTEM[      ]*=.*/SYSTEM=/' \
    $SED -i'.bak'\
        -e '1i\/* modified by xarm-build for OCamlXARM*/' \
        -e 's/^#define[     ][  ]*HAS_STACK_OVERFLOW_DETECTION.*$//' \
        config/s.h

    # Post-modify utils/config.ml to tell ocamlopt to create *
    # binaries for itself.  Also tell ocamlc and ocamlopt to use *
    # architecture when compiling C files.
    make utils/config.ml 
    $SED -i'.bak'\
        -e 's#let[  ][  ]*mkexe[    ]*=.*#let mkexe ="'"$CC"'"#' \
        -e 's#let[  ][  ]*bytecomp_c_compiler[  ]*=.*#let bytecomp_c_compiler ="'"$CC"'"#' \
        -e 's#let[  ][  ]*native_c_compiler[    ]*=.*#let native_c_compiler ="'"$CC"'"#' \
        utils/config.ml
}

build1 () {
    # Don't assemble asmrun/*.S for Phase 1 build.  Modify Makefile
    # temporarily to disable.  Be really sure to put back for Phase 2.
    echo 'xarm-build: ----- build phase 1 -----'
    trap 'mv -f asmrun/Makefile.aside asmrun/Makefile' EXIT
    mv -f asmrun/Makefile asmrun/Makefile.aside
    $SED -e '/^[    ]*ASMOBJS[  ]*=/s/^/#/' \
        -e 's#^include[     ][  ]*../config/Makefile#include ../config/Target/Makefile#' \
        asmrun/Makefile.aside > asmrun/Makefile
    make world && make opt
    mv -f asmrun/Makefile.aside asmrun/Makefile
    trap - EXIT
}

The compilation gets stuck in the stdlib subfolder, where an assertion on calling conventions fails.

let loc_external_arguments =
  match Config.system with
  | "rhapsody" -> poweropen_external_conventions 0 7 100 112
  | "elf" | "bsd" -> calling_conventions 0 7 100 107 outgoing 8
  | _ -> assert false 

To even get to this point, amsrun/Makefile had to be modified to use the cross compile toolchain, and the HAS_STACK_OVERFLOW_DETECTION had to be removed from config/s.h since amsrun/signals_asm.c could not be compiled otherwise.

So is there a way to make this work, or are other approaches in this manner better suited (and work with the 4.00.0 release of OCaml)?


Solution 1:

The question has answered itself... in a rather weird way. What it was really asking for (in 2012) was a cross-compiler targeting (an unspecified version of) iOS for version 4.x of Ocaml. And the code dump in the question was trying to use Jeffrey Scofield's cross-compiling instructions and script (ocamlxarm/3.1) for Ocaml 3.1.x, which didn't quite work for Ocaml 4.0. But Scofield's web page, which the question links to, has been updated in the meantime (last in Dec 2014) to actually provide a solution for Ocaml 4.0 (currently ocaml-4.01.0+xarm-4.0.2-v7), thus making the question as asked here ("is there a way to make this work") moot or fairly trivial. Either:

  • Download the pre-built ocaml-4.01.0+xarm-4.0.2-v7.dmg package currently provided on that web page. Make sure to read the usage instruction too, and make your life easier by using his cross-compiling wrapper script which lets you switch between iOS 7 and 8 targets. Or if you somehow still need to build the Ocaml cross-compiler from sources...
  • Follow the instructions in the "Appendix: Building from Sources" section of the page (there doesn't seem to an HTML anchor for it, sorry). These instructions are unfortunately about twelve paragraphs (9KB of text) long, so I'm not going to copy them here. They include a link to the necessary patches for cross-compiling OCaml 4.0.1 to iOS. Hopefully, what's written on that web page are exactly the steps used to build the aforementioned ocaml-4.01.0+xarm-4.0.2-v7.dmg. However, since there isn't something like an Apple-equivalent of RedHat-style SRPM for that dmg package (does Apple even have an equivalent technology?), it's not possible be totally certain that the steps used to generate the aforementioned dmg are entirely reproduced on that web page. I have not tried myself to follow those steps to see if they work.

But I think nevertheless that the question asked here is basically resolved in the general sense of "is there a way to make this work" by downloading the pre-built 4.0.1 binaries from Scofield's webpage... linked right in the question. Problems with Scofield's ocamlxarm build system version 3.1 not being able to cross-compile Ocaml 4.0 should be the proverbial stuff nobody cares about at this point. If there are problems with Scofield's instructions or patches for 4.0 not working, they should be asked separately, I think, because the nitty gritty errors from the question here seem irrelevant for that scenario.

(And if the above seems overly pedantic, it was mostly by mods' request that I've expanded my answer to its present state.)

Although the OP probably doesn't care about what I'm going to say in this paragraph, given how generic his question title is, I'll point out there's also exists a fairly recent project maintaining an OCaml cross-compiler targeting Android, called opam-android. And this one has all its building bits as scripts in a git repo, so it may be easier to steal-how-it's-done from. Comparing the patches of these two cross-compilers, there's not much that can be said in general how to make OCaml work as cross-compiler other than: you need to hack it for the specific target platform. One thing I will say is that Scofield's iOS patch is a lot more invasive (and far longer) than the Android patches. A lot of Scofield's patch has to do with register-level code generation. I don't know enough about iOS internals to say why those changes were needed for iOS but not for Android, even they basically employ the same ARM CPU family. Maybe someone should ask this as an actually interesting/non-trivial question that Jeffrey Scofield himself would probably be happy to answer.