Psellos
Contemporary Development With Functional Programming

Compile OCaml for iOS Simulator

October 20, 2012

OCamlXSim is a version of OCaml that compiles apps for the iOS Simulator, an iPhone and iPad simulator available from Apple as part of Xcode. The current version of OCamlXSim is 3.1, based on OCaml 4.00.0.

If you’re not familiar with OCaml, it’s a functional language in the same family as Haskell, Scala, and (especially) Standard ML. It’s powerful, flexible, and rigorous. I’ve found programming in OCaml for iOS to be productive and even delightful.

You can download a prebuilt OCamlXSim package for Lion (OS X 10.7) or Mountain Lion (OS X 10.8) as follows:

Both of these packages install OCamlXSim under /usr/local/ocamlxsim and build against SDKs in the standard location of Xcode in /Applications. The first was built under Lion using Xcode 4.3.3. The second was built under Mountain Lion using Xcode 4.5.1. The only other difference is that 3.1.6 builds against the iOS 5.1 SDK by default, and 3.1.7 builds against iOS 6.0. You can use either compiler with a different SDK version (or location) by specifying the proper -ccopt flags, explained below under Test.

If you want more control over the installation and the default SDK, you can build OCamlXSim 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 OCamlXSim from our public Subversion repository.

The OCamlXSim compiler can be used to develop real-world iOS apps. I did almost all the development of the GUI for our released app Master Schnapsen/66 in the iOS Simulator. (The Schnapsen game engine was developed under Linux.)

I’ve also put together a compiler named OCamlXARM that builds apps for iOS devices—iPhone, iPad, and iPod Touch. This lets you release your apps in the iTunes App Store after developing them in the iOS Simulator. OCamlXARM is described in Compile OCaml for iOS.

 

Our OCaml Programming page has many more resources for doing OCaml programming for iOS. For example, I’ve released sources for five example apps (shown in miniature at left) that you can compile and run on an iOS device or in the iOS Simulator.

OCamlXSim 3.1 is based on OCaml 4.00.0, with some bug fixes merged from OCaml 4.00.1. I modified the compiler to cross compile from OS X to the iOS Simulator environment, which is similar to but not identical to OS X. The iOS Simulator environment runs on the i386 architecture, and OCaml’s i386 code generator works in it without any modifications.

Early testers of OCamlXARM 3.1 uncovered a problem in the OCaml 4.00.0 base release, which was recently fixed in OCaml 4.00.1. To make OCamlXSim as useful as possible, I merged in the fix from 4.00.1. So you might say that OCamlXSim 3.1 is based on a prerelease of OCaml 4.00.1. You can read about the problem and the fix in the OCaml bug tracking system, problem report 5757.

As I mentioned above, this version of OCamlXSim was built and tested under OS X 10.7 (Lion) using Xcode 4.3.3 and under OS X 10.8 (Mountain Lion) using Xcode 4.5.1. If you build it yourself, it should work with these or any later versions. If you want to use a prebuilt package with a different version of the iOS SDK, you’ll need to specify the desired iOS SDK as described below under Test.

Previous versions of OCamlXSim, for earlier versions of OS X and Xcode, can be found in the OCaml Programming Archives.

Overview

An app running natively on an iOS device is an ARM program. However, an app running in the iOS Simulator runs as a 32-bit (i386 architecture) Mac OS X program. In other words, the Simulator doesn’t simulate an iOS device down to the hardware level. It provides a faithful copy of the iOS environment, reimplemented to run natively on the Mac.

This means that OCamlXSim needs to be a 32-bit compiler for the i386 architecture, much like the stock 32-bit OCaml compiler for OS X. In fact, the stock compiler very nearly works. The difficulty is that the stock OCaml compiler is a native compiler, i.e., it runs in the same environment as the programs that it compiles. The Simulator environment is different enough from the standard OS X environment that a native compiler doesn’t work correctly. So OCamlXSim needs to be built as a cross compiler. (I’ve written a blog post iOS Simulator Vs. OS X that gives a simple demonstration of the issues.)

The standard OCaml release isn’t designed to run as a cross compiler, so it takes a little extra work to build it as one. In essence, the OCaml build system doesn’t ordinarily need to distinguish between generating parts of the compiler itself, which we run on OS X, and generating the runtime, which we want to run in the iOS Simulator.

The trick I’ve used in OCamlXSim is to build two distinct copies of the OCaml runtime. The first copy is targeted at OS X, and powers the cross compiler itself. The second copy is targeted at the iOS Simulator, and powers the apps running in the iOS Simulator. By lucky chance, there are no parts of the runtime that absolutely need to work independently in both environments. As a result, the two runtimes can coexist inside a single OCaml release. (This would not be the case if, for example, I wanted to support the bytecode interpreter in Simulator apps. For now, I’m sticking with native code apps.)

Please note that a few of the command lines of the following discussion are too long to fit on a single line of a typical browser window. In a lot of cases there is no good place to split them into smaller lines, usually because of a long filename or URL. Take care that you enter them as a single line if you are typing them in by hand.

Preliminaries

To develop and run code on the iOS Simulator, you need an installation of Apple’s Xcode programming environment, which contains the iOS Simulator as one part. You can download Xcode (for free) from the Mac App Store. See Apple’s Xcode page for more details. After installing Xcode, go to the Downloads page of its Preferences, and also download the “Command Line Tools.”

The OCaml native code compiler (ocamlopt) uses an external assembler to produce its final object files. In the same way, OCamlXSim uses the assembler of the iOS Simulator platform to produce object files. After you’ve installed Xcode, you should find an assembler for the iOS Simulator platform:

$ PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform
$ (cd $PLT/Developer/usr/bin; ls -lL as)
-rwxr-xr-x 1 root wheel 23648 Jun 12 13:19 as

This is the assembler OCamlXSim will use, so it must be present. If it isn’t, check that you’ve installed Xcode (version 4.2 or later). If you’ve installed it in a non-standard location (other than /Applications), you’ll need to modify paths accordingly in the following discussion.

The simplest way to get OCamlXSim is to download and install one of the previously mentioned prebuilt packages from Psellos. They install OCamlXSim 3.1.6 or 3.1.7 in /usr/local/ocamlxsim. In that case, you can skip down to the Test section below to verify that your copy of OCamlXSim is installed correctly. The intervening sections describe how to build the OCamlXSim compiler yourself.

If you want to build OCamlXSim from sources, you should find C compilers for OS X and for the iOS Simulator platform 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/iPhoneSimulator.platform
$ (cd $PLT/Developer/usr/bin; ls -lL gcc)
-rwxr-xr-x 1 root wheel 117152 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 the patches, first 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 20 15:41 ocaml-4.00.0.tar.gz

Then download patches from Psellos:

$ curl -O -s http://psellos.com/pub/ocamlxsim/ocamlxsim-3.1.6.diff
$ ls -l ocamlxsim-3.1.6.diff
-rw-r--r-- 1 psellos staff 24946 Sep 20 15:42 ocamlxsim-3.1.6.diff

You can also download a patch named ocamlxsim-3.1.7.diff. It’s identical to the 3.1.6 patch except for a line in the build script, which specifies the iOS 6.0 Simulator SDK rather than iOS 5.1.

To save typing, you can download 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 < ../ocamlxsim-3.1.6.diff
patching file VERSION
patching file asmcomp/schedgen.ml
patching file asmcomp/i386/emit.mlp
patching file tools/make-package-macosx
patching file xsim-build
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 asmrun/signals_osdep.h

Check Out Sources from Repository

You can also check out the sources for OCamlXSim 3.1.6 or 3.1.7 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 OCamlXSim 3.1.6:

$ svn co svn://svn.psellos.com/tags/ocamlxsim-3.1.6 ocamlxsim-3.1
$ cd ocamlxsim-3.1

These sources are identical to what you get if you apply the 3.1.6 patches to the INRIA 4.00.0 release, as above. You can also check out the 3.1.7 sources; just replace 3.1.6 with 3.1.7.

Build OCamlXSim

Once you have the sources, you’re ready to build OCamlXSim. The file xsim-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 (these are from the 3.1.6 sources):

export PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform
export SDK=/Developer/SDKs/iPhoneSimulator5.1.sdk
export XSIMTARGET=/usr/local/ocamlxsim
export OSXARCH=i386

In the 3.1.7 sources, the version 5.1 above is 6.0 instead. In fact (as I mentioned) this is the only difference between the sources of the two OCamlXSim releases.

The meanings are as follows:

PLT Location of iOS Simulator platform directory (inside the Xcode app)
SDK Desired iOS SDK version (a subdirectory of PLT—normally, the most recent available).
XSIMTARGET Where OCamlXSim should be installed.
OSXARCH Architecture for OS X executables (i386 or x86_64).

The PLT line gives the location of the Xcode iOS Simulator platform directory. Under OS X 10.7 (Lion) and later, Xcode is installed as an ordinary application, and the platform directory is inside it. If you have a customized Xcode installation, you may need to change this line.

The SDK line gives the location of the iOS Simulator SDK, the name of a directory within the platform directory. In Xcode 4.3.3, the SDK version is 5.1. You should probably set this to the most recent SDK that you see in your platform directory.

The value of XSIMTARGET is a directory where OCamlXSim should be installed. This location is compiled into the OCamlXSim 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, xsim-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 9%. Note: support for 64-bit executables is a recent addition to OCamlXSim. If you discover any problems, please let me know.

To build OCamlXSim all in one step:

$ sh xsim-build all > xsim-build.log 2>&1

If things go well, xsim-build.log will contain around 2926 lines of output, ending with something like this:

../../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 xsim-build.log. It’s also possible to build OCamlXSim in smaller stages—see the script for details.

Now install the compiler.

$ sudo -s
Password:
# make install
    . . .
  install /usr/local/ocamlxsim/lib/ocaml/ocamlbuild/ocamlbuild.o
  install /usr/local/ocamlxsim/man/man1/ocamlbuild.1
# exit
$

The installation process produces around 278 lines of output.

Test

To verify the installation, compile a test program. For convenience I start by defining the variable BIN, used throughout this section.

$ BIN=/usr/local/ocamlxsim/bin
$ cat > statdo.ml
let main () =
    Printf.printf "%o\n" Unix.((stat "/bin/sh").st_perm)

let () = main ()
^D
$ $BIN/ocamlopt -o statdo unix.cmxa statdo.ml
$ file statdo
statdo: Mach-O executable i386

To run the program in the iOS Simulator environment, first set the variables PLT and SDK. You can cut and paste these values from the xsim-build script.

$ PLT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform
$ SDK=/Developer/SDKs/iPhoneSimulator5.1.sdk

In Mountain Lion, SDK should contain 6.0 instead of 5.1.

Set DYLD_ROOT_PATH to the SDK location, and run the program.

$ DYLD_ROOT_PATH=$PLT$SDK statdo
555

The program correctly shows the mode (permission settings) of the standard shell /bin/sh. If you run the program in the usual OS X environment, you’ll see that it behaves differently:

$ statdo
6236

In the OS X environment, the program runs but gets the wrong answer! As mentioned above, the iOS Simulator environment is not the same as OS X.

To test the camlp4 family of processors, try compiling with camlp4o.

$ $BIN/ocamlopt -pp $BIN/camlp4o -o statdo unix.cmxa statdo.ml
$ file statdo
statdo: Mach-O executable i386

If all these tests behave as shown here, you can be pretty sure your OCamlXSim installation is working correctly.

You might instead see the first test above fail as follows:

$ $BIN/ocamlopt -o statdo unix.cmxa statdo.ml
ld: library not found for -lcrt1.10.6.o
collect2: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking

This most likely indicates that OCamlXSim was built using an iOS SDK version that is not currently present on your system. This doesn’t necessarily indicate a problem. For example, the prebuilt OCamlXSim 3.1.6 compiler from Psellos is built using the iPhoneOS 5.1 SDK, but you may well be using a later Xcode version with a later SDK.

The solution is to specify explicit options to ocamlopt telling it which SDK version to use. Assuming you’ve set PLT and BIN as above, you can use the pre-built OCamlXSim 3.1.6 with iPhoneOS Simulator 6.0 SDK as follows:

$ SDK=/Developer/SDKs/iPhoneSimulator6.0.sdk
$ OCOPTS="-ccopt -isysroot -ccopt $PLT$SDK"
$ $BIN/ocamlopt $OCOPTS -o statdo unix.cmxa statdo.ml
$ file statdo
statdo: Mach-O executable arm

Although the SDK options are somewhat painful to specify, it’s probably best to think of them as part of using OCamlXSim with Apple’s ever-evolving iOS SDK. A solution that may be better in some cases is to rebuild OCamlXSim from sources, specifying the new SDK values in xsim-build.

Extra Options for iOS C libraries

The OCaml native compiler (ocamlopt) is willing to compile C programs by passing them along to the system’s C compiler. OCamlXSim does this also, but when compiling C code that uses iOS libraries, you need to specify the minimum iOS version that you’re targeting. It looks like this:

$ ocamlopt -ccopt -D__IPHONE_OS_VERSION_MIN_REQUIRED=50100 x.c

The value 50100 specifies that the minimum iOS version is 5.1. To target version 4.2.1 (say) you would specify the value as 40201.

For more information on compiling and linking iOS apps with OCamlXSim, see the example apps described in the next section.

Further Information

To run a program that actually does something interesting, you need the richer environment provided by the actual iOS Simulator. The pages linked here show how to build three different OCaml example apps and run them in the iOS Simulator:

Gamut: Explore Colors in iOS Simulator
Voronoi: Touchable Diagrams in iOS Simulator
IcosaBlue: OpenGL ES App for iOS

Gamut is a simple app that displays a small animation in all possible colors. Voronoi is a more complex app that displays dynamic colored Voronoi diagrams that you can manipulate through the touch interface. IcosaBlue shows how to use OpenGL ES—it is packaged to work both in the simulator and on real iOS devices.

If you’re interested in running OCaml apps on real iOS devices, see the accompanying note Compile OCaml for iOS. This note has links to two other sample apps 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, please leave them below, or email me at jeffsco@psellos.com.

Comments

blog comments powered by Disqus