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.
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 4.0, based on OCaml 4.01.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 Mavericks (OS X 10.9) from this link:
The package installs OCamlXSim under /usr/local/ocamlxsim
. It was
built under Mavericks using Xcode 5.1.1, and builds against the iOS 7.1
SDK by default. You can use the compiler with a different SDK version by
specifying the proper -ccopt
flags, explained just below under
Test.
If you want more control over the installation and the default SDK, you can build OCamlXSim from sources as described at the end of the page under Building from Sources.
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.)
Our OCaml Programming page has more resources for doing OCaml programming for iOS. For example, I’ve released sources for five illustrative apps (shown in miniature at left) that you can compile and run on an iOS device or in the iOS Simulator.
Previous versions of OCamlXSim, for earlier versions of OS X, iOS, and Xcode, can be found in the OCaml Programming Archives.
Test
After installing, you might want to compile a tiny test program as
follows. 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
If your Simulator program is simple enough, you can actually run it from
the OS X command line by controlling the set of dynamically loaded
libraries. First, set shell variables PLT
and SDK
. You can cut and
paste the definitions from the xsim-build
script.
$ HIDEOUT=/Applications/Xcode.app/Contents/Developer
$ PLT=$HIDEOUT/Platforms/iPhoneSimulator.platform
$ SDK=/Developer/SDKs/iPhoneSimulator7.1.sdk
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
5555
In the OS X environment, the program runs but gets the wrong answer! The iOS Simulator environment is a copy of the environment of an iOS device, and thus is not exactly 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.9.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 4.0.1 compiler from Psellos is built using the iPhoneOS 7.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 4.0.1 with iPhoneOS Simulator 8.0 SDK as
follows:
$ SDK=/Developer/SDKs/iPhoneSimulator8.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
.
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.
Appendix: Building from Sources
For maximum flexibility, you can build OCamlXSim from sources. This is a little more complicated than a standard OCaml build, but I’ve created a shell script that does it for you.
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. (The simple test statdo
, above, shows the basic
problem. I’ve written a blog post iOS Simulator Vs. OS X
that discusses the issue a little more.)
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. Recent versions of Xcode contain the traditional Unix command-line tools, which you will also need to build OCamlXSim. (In earlier versions of Xcode, the command-line tools were downloaded separately.)
To simplify the command lines below, I’ll define some shell variables as abbreviations for some of the key paths of development tools. If you’re following along at the keyboard, you should define them yourself for later use:
$ HIDEOUT=/Applications/Xcode.app/Contents/Developer
$ TOOLDIR=$HIDEOUT/Toolchains/Xcodedefault.xctoolchain/usr/bin
$ PLT=$HIDEOUT/Platforms/iPhoneSimulator.platform
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:
$ (cd $TOOLDIR; ls -l as)
-rwxr-xr-x 1 root wheel 27808 Mar 11 04:37 as
This is the assembler OCamlXSim will use, so it must be present. If it
isn’t, check that you’ve installed Xcode (version 5.1 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.
In recent years, Apple has switched from the GNU C compiler gcc to a new compiler clang, based on LLVM. If you want to build OCamlXSim from sources, you should have a native C compiler and a C cross compiler for the Simulator as follows:
$ (cd /usr/bin; ls -l clang)
-rwxr-xr-x 1 root wheel 14224 Oct 30 2013 clang
$ (cd $TOOLDIR; ls -l clang)
-rwxr-xr-x 1 root wheel 36874304 May 9 21:09 clang
If these compilers aren’t present, make sure you have installed Xcode as described above, and that your version of Xcode includes the command-line tools.
Create Sources from Patches
To create sources from the patches, you need to download the OCaml 4.01.0 release from INRIA and the patches from Psellos and then apply the patches.
Download the sources for the OCaml 4.01.0 release from INRIA:
$ curl -O -s http://caml.inria.fr/pub/distrib/ocaml-4.01/ocaml-4.01.0.tar.gz
$ ls -l ocaml-4.01.0.tar.gz
-rw-r--r-- 1 psellos staff 4397871 Sep 7 23:05 ocaml-4.01.0.tar.gz
Then download patches from Psellos:
$ curl -O -s http://psellos.com/pub/ocamlxsim/ocamlxsim-4.0.1.diff
$ ls -l ocamlxsim-4.0.1.diff
-rw-r--r-- 1 psellos staff 13711 Sep 7 21:09 ocamlxsim-4.0.1.diff
To save typing, you can download directly from your browser:
Unpack the OCaml sources and apply the patches.
$ tar -xf ocaml-4.01.0.tar.gz
$ cd ocaml-4.01.0
$ patch -p0 < ../ocamlxsim-4.0.1.diff
patching file configure
patching file VERSION
patching file asmcomp/i386/emit.mlp
patching file tools/make-package-macosx
patching file xsim-build
patching file Makefile
patching file asmrun/signals_osdep.h
Check Out Sources from Repository
You can also check out the sources for OCamlXSim 4.0.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 OCamlXSim 4.0.1:
$ svn co svn://svn.psellos.com/tags/ocamlxsim-4.0.1 ocamlxsim-4.0
$ cd ocamlxsim-4.0
These sources are identical to what you get if you apply the 4.0.1 patches to the INRIA 4.01.0 release, as above.
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:
export HIDEOUT=/Applications/Xcode.app/Contents/Developer
export TOOLDIR=$HIDEOUT/Toolchains/XcodeDefault.xctoolchain/usr/bin
export PLT=$HIDEOUT/Platforms/iPhoneSimulator.platform
export SDK=/Developer/SDKs/iPhoneSimulator7.1.sdk
export XSIMTARGET=/usr/local/ocamlxsim
export OSXARCH=i386
The meanings are as follows:
HIDEOUT |
Secret hideout of Apple developer files (inside the Xcode app). |
TOOLDIR |
Location of developer tools. |
PLT |
Location of iOS Simulator platform directory. |
SDK |
Desired iOS Simulator 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 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
for finding libraries and such, 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%.
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 2424 lines of
output, ending with something like this:
../../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 cross compiler.
# sudo make install
Password:
. . .
install /usr/local/ocamlxsim/lib/ocaml/ocamlbuild/ocamlbuild.o
install /usr/local/ocamlxsim/man/man1/ocamlbuild.1
$
The installation process produces around 278 lines of output.
Now you’re ready to test the compiler as described above under Test.