Compile OCaml for Early iOS
OCamlXARMv6 is a version of OCaml 4.00.0 that cross-compiles to the armv6 architecture under iOS. It runs on OS X, and builds apps for iOS devices that support armv6. Right now, in fact, all iOS devices can run armv6 binaries. However, as of Xcode 4.5, creation of armv6 binaries is no longer supported. This means that OCamlXARMv6 is useful only for special purposes. It works only with older versions of Xcode, but can build apps for the earliest (otherwise obsolete) iOS devices.
If you’re looking for a way to build OCaml apps on current iOS devices, you want OCamlXARM, described in Compile OCaml for iOS. OCamlXARMv6 is the same as OCamlXARM, except that it generates armv6 instructions. I added a small modification to the ARM code generator (written by Benedikt Meurer) to support the VFPv2 floating point instruction set of the early iOS devices. (This modification is available as a separate patch—see OCaml 4.00.0 Patches for VFPv2.)
You can download a prebuilt OCamlXARMv6 3.1 package from
Psellos, which installs under /usr/local/ocamlxarm/v6
and builds against the SDK for iOS 5.1 by default.
If you want more control over the installation and the default SDK, you can build OCamlXARMv6 from sources. Below I describe how to download a set of patches to be applied to the official OCaml 4.00.0 release. You can also download sources for OCamlXARMv6 from our public Subversion repository.
I built and tested OCamlXARMv6 under OS X 10.7 (Lion) using the toolchain of Xcode 4.3.3 and the iOS 5.1 SDK. If you build it yourself, it should work with Xcode versions betwen 4.2 and 4.4 (inclusive). If you want to use the prebuilt package with a different version of the iOS SDK, you’ll need to specify the desired iOS SDK as described below under Test.
Preliminaries
To build and run apps with OcamlXARMv6, you need Xcode version 4.2, 4.3, or 4.4, and you need to be registered with Apple as an iOS developer. To get older versions of Xcode, go to Apple’s Developer Downloads page. I was pleasantly surprised to find that many earlier versions of Xcode are still available as of this writing. You’ll also need the associated “Command Line Tools”, which you can download through the Downloads page of Xcode’s Preferences.
The OCaml native code compiler (ocamlopt) uses an external assembler to produce its final object files. In the same way, OCamlXARMv6 uses the cross-assembler of the iOS SDK to produce iOS object files. After you’ve installed Xcode, you should find an assembler for the iOS platform:
$ PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
$ (cd $PLT/Developer/usr/bin; ls -lL as)
-rwxr-xr-x 1 root wheel 55632 Jun 12 13:19 as
This is the assembler OCamlXARMv6 will use, so it must be present. If
it isn’t, check that you’ve installed Xcode (a version between 4.2 and
4.4). If you’ve installed it in a non-standard location (other than
/Applications
), you’ll need to modify paths in the following
discussion accordingly.
The simplest way to get OCamlXARMv6 is to download and install the
previously mentioned prebuilt OCamlXARMv6 3.1.2 package
from Psellos. This installs OCamlXARMv6 3.1.2 in
/usr/local/ocamlxarm/v6
. In that case, you can skip down to the
Test section below to verify that your copy of OCamlXARMv6 is
installed correctly. The intervening sections describe how to build the
OCamlXARMv6 compiler yourself.
If you want to build OCamlXARMv6 from sources, you should have a native C compiler and a C cross compiler for iOS at the following paths:
$ (cd /usr/bin; ls -lL gcc)
-rwxr-xr-x 1 root wheel 117152 Jun 12 13:27 gcc
$ PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
$ (cd $PLT/Developer/usr/bin; ls -lL gcc)
-rwxr-xr-x 1 root wheel 106064 Jun 12 13:19 gcc
If these compilers aren’t present, make sure you have installed the Command Line Tools as described above.
Create Sources from Patches
To create sources from patches, you need to download the OCaml 4.00.0 release from INRIA and the patches from Psellos and then apply the patches.
Download the sources for the OCaml 4.00.0 release from INRIA:
$ curl -O -s http://caml.inria.fr/pub/distrib/ocaml-4.00/ocaml-4.00.0.tar.gz
$ ls -l ocaml-4.00.0.tar.gz
-rw-r--r-- 1 psellos staff 3394054 Sep 22 15:41 ocaml-4.00.0.tar.gz
Download patches from Psellos:
$ curl -O -s http://psellos.com/pub/ocamlxarm/ocamlxarmv6-3.1.2.diff
$ ls -l ocamlxarmv6-3.1.2.diff
-rw-r--r-- 1 psellos staff 71232 Sep 22 15:42 ocamlxarmv6-3.1.2.diff
To save typing, you can access these two links directly from your browser:
Unpack the OCaml sources and apply the patches.
$ tar -xzf ocaml-4.00.0.tar.gz
$ cd ocaml-4.00.0
$ patch -p0 < ../ocamlxarmv6-3.1.2.diff
patching file VERSION
patching file asmcomp/schedgen.ml
patching file asmcomp/arm/arch.ml
patching file asmcomp/arm/emit.mlp
patching file asmcomp/arm/proc.ml
patching file asmcomp/arm/scheduling.ml
patching file asmcomp/arm/selection.ml
patching file tools/make-package-macosx
patching file Makefile
patching file byterun/intern.c
patching file byterun/memory.c
patching file byterun/freelist.c
patching file byterun/freelist.h
patching file byterun/compact.c
patching file byterun/major_gc.c
patching file testsuite/tests/regression/pr5757/pr5757.ml
patching file testsuite/tests/regression/pr5757/pr5757.reference
patching file testsuite/tests/regression/pr5757/Makefile
patching file xarm-build
patching file asmrun/signals_osdep.h
patching file asmrun/arm.S
patching file asmrun/Makefile
$
Check out Sources from Repository
You can also check out the sources for OCamlXARMv6 3.1 from Psellos’s public Subversion repository. This is simpler, but it doesn’t give you the opportunity to examine the patches separately before applying them.
Check out sources for OCamlXARMv6 3.1:
$ svn co svn://svn.psellos.com/trunk/ocamlxarmv6/3.1 ocamlxarmv6-3.1
$ cd ocamlxarmv6-3.1
These sources are identical to what you get if you apply the patches to the INRIA 4.00.0 release, as above.
Build OCamlXARMv6
Once you have the sources, you’re ready to build OCamlXARMv6. The file
xarm-build
is a shell script that does the building. You may want to
modify the script before running it. At the beginning of the script are
the following lines:
export PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
export SDK=/Developer/SDKs/iPhoneOS5.1.sdk
export SIMPLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform
export SIMSDK=/Developer/SDKs/iPhoneSimulator5.1.sdk
export XARMTARGET=/usr/local/ocamlxarm
export OSXARCH=i386
The values are as follows:
PLT |
Location of iOS platform directory (inside the Xcode app) |
SDK |
Desired iOS SDK version (a subdirectory of PLT ). |
SIMPLT |
Location of iOS Simulator platform directory (inside the Xcode app). |
SIMSDK |
Desired iOS Simulator SDK version (a subdirectory of SIMPLT —should be the same version number as SDK ). |
XARMTARGET |
Where OCamlXARMv6 should be installed. |
OSXARCH |
Architecture for OS X executables (i386 or x86_64 ). |
The value of XARMTARGET
is a directory where OCamlXARMv6 should be
installed. It is safe to use the same target as for
OCamlXARM—OCamlXARMv6 will be installed in a subdirectory of
XARMTARGET
named v6
.
As mentioned above, this location is compiled into the OCamlXARMv6 tools; that is, they are aware of their own installation location. This is convenient, but it also means that the tools actually need to be installed in this one specific place. It’s not possible (or at least not convenient at all) to move them somewhere else later on.
Ordinarily, xarm-build
will create 32-bit (i386 architecture) OS X
executables. This is simplest, because they work on all Intel Macs. If
you want to create 64-bit executables, change the value of OSXARCH
to
x86_64
. In my initial testing, I’ve found that the 64-bit executables
make compiles go a little faster—but only around 10%.
To build OCamlXARMv6 all in one step:
$ sh xarm-build all > xarm-build.log 2>&1
If things go well, xarm-build.log
will contain around 2,740 lines of
output, ending with something like this:
ln -s -f ../unix/unix.mli unix.mli
../../ocamlcomp.sh -I ../unix -warn-error A -c unix.ml
../../boot/ocamlrun ../../tools/ocamlmklib -ocamlc '../../ocamlcomp.sh -I ../unix' -o unix -linkall unix.cmo ../unix/unixLabels.cmo
make: Nothing to be done for `allopt'.
If there is a problem, it may be possible to figure out what went wrong
by looking at the error messages in xarm-build.log
. It’s also
possible to build OCamlXARMv6 in smaller stages—see the script for
details.
Now install the cross compiler.
$ sudo -s
Password:
# make install
. . .
install /usr/local/ocamlxarm/v6/lib/ocaml/ocamlbuild/ocamlbuild.cmo
install /usr/local/ocamlxarm/v6/man/man1/ocamlbuild.1
# exit
$
The installation process produces around 280 lines of output.
Test
To verify the installation, compile a test program. For convenience I
start by defining the shell variable BIN
, used throughout this
section.
$ BIN=/usr/local/ocamlxarm/v6/bin
$ cat > hello.ml
let main () = Printf.printf "Hello, world!\n"
let () = main ()
^D
$ $BIN/ocamlopt -o hello hello.ml
$ file hello
hello: Mach-O executable arm
To test the camlp4 family of processors, try preprocessing with camlp4o.
$ $BIN/ocamlopt -pp $BIN/camlp4o -o hello hello.ml
$ file hello
hello: Mach-O executable arm
If the compiler produces ARM executable binaries as shown here, it is almost certainly working correctly.
You might instead see the first test fail as follows:
$ $BIN/ocamlopt -o hello hello.ml
ld: library not found for -lcrt1.o
collect2: ld returned 1 exit status
File "caml_startup", line 1:
Error during linking
This most likely indicates that the iPhoneOS 5.1 SDK isn’t present on
your system. If you want to use a different SDK version, the solution
is to specify explicit options to ocamlopt
telling it which SDK
version to use. To use the (purely hypothetical) iPhoneOS 5.2 SDK, for
example:
$ PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
$ SDK=/Developer/SDKs/iPhoneOS5.2.sdk
$ OCOPTS="-ccopt -isysroot -ccopt $PLT$SDK"
$ $BIN/ocamlopt $OCOPTS -o hello hello.ml
$ file hello
hello: Mach-O executable arm
Further Information
Building the OCaml cross compiler is only the first step. The accompanying notes Portland: Which Way Is Up on iOS? and Slide24: Sliding Tile Puzzle for iOS show how to build simple iOS apps and run them on an iOS device.
If you’re interested in running OCaml apps in the iOS Simulator, see the accompanying note Compile OCaml for iOS Simulator. This note has links to three other sample applications that you can try.
See the OCaml Programming page for a full list of our OCaml resources.
If you have any questions, comments, or corrections, feel free to leave them below, or email me at jeffsco@psellos.com.