Compile OCaml for iOS Simulator
Note: This is an archived version of the OCamlXSim page, for those interested in earlier versions. The most recent version is at Compile OCaml for iOS Simulator.
This note describes how to build an OCaml 3.12.1 compiler for the iOS Simulator, an iPhone and iPad simulator available from Apple. The resulting compiler can be used to build iOS applications and run them on the simulator. I’ll call it OCamlXSim for short.
If you don’t want to build the compiler yourself, you can download a prebuilt package from Psellos. The current version is named ocaml-3.12.1+xsim1.
The OCamlXSim compiler is nearly identical to the usual 32-bit OCaml compiler for Mac OS X. Only a few configuration parameters are different.
Overview
An application running natively on an iOS device is an ARM program. However, an application running in the iOS Simulator is an ordinary 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 Mac OS X. In fact, the stock compiler very nearly works. The difficulty is that some Mac OS X system calls aren’t supported under iOS, and (to make the simulation more faithful) the Simulator prevents their use. The reason the stock Mac OS X compiler doesn’t work for the Simulator is that its runtime (linked into all the programs it compiles) uses some of these forbidden system calls.
The OCaml runtime is a library written in C, and when building the OCaml system you can set an environment variable that restricts system calls to a subset that’s compatible with an old version of Mac OS X (version 10.4). This eliminates the forbidden calls, and the runtime works in the iOS Simulator. In some sense this is a coincidence; the flag is asking for compatibility with an old version of Mac OS X, not with iOS. But it works, at least for now. Building the compiler this way is simpler than producing a full-fledged cross compiler.
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 tools, which contain the iOS Simulator as one part. As I write this, the current version is Xcode 4.0.2. However, if you want to build OCamlXSim yourself, you have to use Xcode 3, the previous version. Xcode 4.0.2 can’t be used to build a 32-bit version of OCaml 3.12.1 due to a linker bug in Xcode. This is a known problem, which you can follow on Mantis, the OCaml bug tracker, here.
If you just want to build and test iOS Simulator apps, you can download and install the abovementioned prebuilt OCamlXSim package from Psellos and use any recent version of Xcode (3 or 4) to build your apps. In that case, you can skip down to the Test section below to verify that your copy of OCamlXSim is installed correctly.
Apple has made it pretty easy to develop for the Mac, which means that there are many ways to get Xcode. You may already have a recent Xcode release on your Mac, or you may be able to install it from a DVD that came with your Mac. If not, you can download Xcode 3 and Xcode 4 from Apple for free if you’re a registered Apple developer. (It’s also free to register as an Apple developer.) Or you can buy Xcode 4 from the Mac App Store for a small charge. See Apple’s Xcode page for more details.
After installing Xcode you will have a set of platform directories, under which there are SDK directories for each OS release. We’ll be using the iPhone Simulator platform directory many times, so I’ll use the following shell variable to make things clearer:
$ PLAT=/Developer/Platforms/iPhoneSimulator.platform
(If you use a C Shell variant, use the set
command here.)
You should find a C compiler and an assembler for the Simulator at the following paths in the platform directory:
$PLAT/Developer/usr/bin/gcc-4.2
$PLAT/Developer/usr/bin/as
To verify that the tools are present, ask for their versions:
$ $PLAT/Developer/usr/bin/gcc-4.2 --version | head -1
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
$ $PLAT/Developer/usr/bin/as -arch i386 -v /dev/null
Apple Inc version cctools-782~33, GNU assembler version 1.38
As mentioned above, more recent Xcode releases can’t (yet) be used to build OCaml, so be careful of the version numbers.
Get OCaml Sources
Choose a place to work (an empty directory might be good).
$ cd
<good place to work>
Download the sources for the OCaml 3.12.1 release from INRIA:
$ curl -O -s http://caml.inria.fr/pub/distrib/ocaml-3.12/ocaml-3.12.1.tar.gz
$ ls -l ocaml-3.12.1.tar.gz
-rw-r--r-- 1 psellos staff 3660473 Jul 8 15:41 ocaml-3.12.1.tar.gz
To save typing, you can access this link directly from your browser:
Unpack the OCaml sources.
$ tar -xzf ocaml-3.12.1.tar.gz
$ cd ocaml-3.12.1
Build Compiler
The first trick is to configure the build process using the toolchain from the platform directory. This works because the Simulator environment is almost identical to full Mac OS X. In a sense, we trick the OCaml compiler into being a cross compiler.
(If you set PLAT
above, you don’t need to reassign it here. I repeat
it for those who skipped ahead to this section.)
$ PLAT=/Developer/Platforms/iPhoneSimulator.platform
$ ./configure \
-cc "$PLAT/Developer/usr/bin/gcc-4.2 -arch i386" \
-as "$PLAT/Developer/usr/bin/as -arch i386" \
-aspp "$PLAT/Developer/usr/bin/gcc-4.2 -arch i386 -c" \
-prefix /usr/local/ocamlxsim \
-no-pthread -no-curses -no-tk
. . .
** Objective Caml configuration completed successfully **
If you want to install the compiler somewhere other than under
/usr/local/ocamlxsim
, change the -prefix
line.
Now build the compiler, requesting compatibility with Mac OS X 10.4. This is the second trick.
(If you use a C Shell variant, use the setenv
command to set
MACOSX_DEPLOYMENT_TARGET
before running make world.opt
.)
$ MACOSX_DEPLOYMENT_TARGET=10.4 make world.opt
make coldstart
cd byterun; make all
sed -n -e '/^ /s/ \([A-Z]\)/ \&\&lbl_\1/gp' \
-e '/^}/q' instruct.h > jumptbl.h
/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 -arch i386 -DCAML_NAME_SPACE -O -fno-defer-pop -no-cpp-precomp -Wall -D_FILE_OFFSET_BITS=64 -c -o interp.o interp.c
. . .
This should produce around 2160 lines of output, then stop with no error message.
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 345 lines of output.
Test
To verify the installation, compile a test program.
$ cat > hello.ml
let main () = Printf.printf "Hello, world!\n"; exit 1
let () = main ()
^D
$ /usr/local/ocamlxsim/bin/ocamlopt -o hello hello.ml
$ file hello
hello: Mach-O executable i386
$ hello
Hello, world!
$ nm hello | grep sigaltstack
U _sigaltstack
A more recent variant of the sigaltstack
system call is one of those
that are forbidden in the iOS Simulator. The name should appear as
given here. If it appears as _sigaltstack$UNIX2003
, the compiler was
not built correctly.
As you can see, the test program runs successfully under Mac OS X, because the Simulator environment is nearly the same. You can also run the program in the simulator using an unsupported interface (i.e., one that could disappear in later Xcode releases):
$ /Developer/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone\ Simulator.app/Contents/MacOS/iPhone\ Simulator -SimulateApplication hello
Hello, world!
The simulator window will appear, and you should see the "Hello,
world!"
output in your terminal window. Since the program doesn’t do
anything at all, nothing will be displayed in the simulator window.
Then you should get a notification that the program has exited. From
the Simulator’s point of view this is a failure, since iPhone apps are
supposed to exit only when asked to.
Further Information
The accompanying notes OCaml iPhone Simulator App: Gamut and OCaml iPhone Simulator App: Voronoi show exactly how to build two OCaml apps and run them in the iPhone Simulator. 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.
If you have any questions, comments, or corrections, feel free to email me at jeffsco@psellos.com.