Psellos
Contemporary Development With Functional Programming

Compile OCaml for iOS Simulator

January 18, 2016

This page shows how to compile OCaml code to run in Apple’s iOS Simulator. If you’re not familiar with OCaml, it’s a functional language in the same family as Haskell, Scala, and Standard ML. To me programming in these languages is like having a well lit place to work. Everything just makes a lot more sense.

Recently there has been work (with the kind help of Gerd Stolpmann) to incorporate iOS Simulator support into the official INRIA OCaml release. That will be a glorious day when it comes. In the meantime the iOS support is available in a branch of the OCaml repository. I checked out the branch and made two compilers for the 32-bit and 64-bit variants of the iOS Simulator.

You can download OCamliOSSim compiler packages from these links:

These are builds of OCaml 4.02.3 that run under OS X 10.11 (El Capitan) and generate code to run under the simulated versions of iOS 7.0 or later. The packages install OCamliOSSim under /usr/local/ocamliossim32 and /usr/local/ocamliossim64. They were built under El Capitan using Xcode 7.2.

If you want more control over the installation and iOS versions, you can build OCamliOSSim from sources as described at the end of the page under Building from Sources.

The OCamliOSSim 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.

Previous versions of OCaml compilers for the iOS Simulator, 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.

$ cat > hello.ml
let main () = Printf.printf "Hello, world!\n"

let () = main ()
^D
$ /usr/local/ocamliossim64/bin/ocamlopt -o hello hello.ml
$ file hello
hello: Mach-O 64-bit executable x86_64

If the compiler produces a 64-bit Intel executable as shown here, it is almost certainly working correctly.

To produce a 32-bit executable, use ocamliossim32 in place of ocamliossim64 on the compile line.

This tiny example is not a valid iOS app—for that you need to link in the full Cocoa Touch platform. However, if your code is extremely simple like this you can actually run it from the OS X command line:

$ hello
Hello, world!

This is cool, but keep in mind that the iOS Simulator environment is not the same as OS X. Instead it’s a copy of the environment of an iOS device. So you can’t push things too far. (For an earlier discussion of this point, see iOS Simulator Vs. OS X.)

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—A simple app that displays an animation in all possible colors.
Voronoi: Touchable Diagrams in iOS Simulator—A more complex app that displays dynamic colored Voronoi diagrams that you can manipulate through the touch interface.
IcosaBlue: OpenGL ES App for iOS—A rotating icosahedron using OpenGL ES.

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 OCamliOSSim from sources on an OS X system. This is a little more complicated than a standard OCaml build, but there’s a script named build.sh that handles many of the details.

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. 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 OCamliOSSim.

The commands for building the 32-bit and 64-bit compilers are similar. To simplify the discussion, I’ll use the variable BITS to represent the target width. If you’re following along at the keyboard, you can actually set BITS to 32 or 64, or you can just remember to substitute the right number.

$ BITS=64 # (Or 32)

Create Native Compiler of Proper Width

Recent versions of OCaml have built-in support for cross compilation. One limitation is that the cross compiler must be built using an OCaml compiler of the same width as the target architecture and of the identical version. If you think about it, this makes sense. The runtime of the cross compiler is shared with the compiler used to build it, so they have to match.

You are building OCaml 4.02.3 for iOS, so you need a native OS X OCaml 4.02.3 compiler of target width BITS. In my opinion the best way to make sure of this is to build it yourself.

So, check out the tagged sources of OCaml 4.02.3 from the OCaml repository:

$ git clone -b 4.02.3 https://github.com/ocaml/ocaml ocaml-4.02.3-${BITS}s
(Git will tell you you are in ‘detached HEAD’ state, which sounds gruesome but isn’t a problem.)

$ cd ocaml-4.02.3-${BITS}s

Now modify the file named VERSION, adding +iossim to the end of the first line. When you’re done you should see this:

$ head -1 VERSION
4.02.3+iossim

If you’re making the 32-bit compiler, configure as follows:

$ ./configure -prefix $(pwd)/release -no-shared-libs \
-host i386-apple-darwin$(uname -r) \
-cc 'clang -arch i386' \
-as 'clang -arch i386 -c' \
-aspp 'clang -arch i386 -c' \
-lib -Wl,-no_pie

If you’re making the 64-bit compiler, configure as follows:

$ ./configure -prefix $(pwd)/release

Since your Mac is a 64-bit machine, configuring the 64-bit compiler is much simpler. (If it’s not a 64-bit machine, you’ll need to experiment with the options.)

Now build and install your custom compiler:

$ make world.opt
$ make install

This will install the new compiler to a directory named release in the work tree. For the next build, you want to make this your default OCaml compiler (temporarily):

$ PATH=$(pwd)/release/bin:$PATH

Back to the starting directory:

$ cd ..

Build OCamliOS

Now you can build the cross compiler for iOS of your target width. First check out the modified sources from Gerd Stolpmann’s repository:

$ git clone -b gs-4.02.3+ios https://github.com/gerdstolpmann/ocaml gs-4.02.3+iossim-$BITS
$ cd gs-4.02.3+iossim-$BITS

Make the same modification to VERSION as above (add +iossim at the end of the first line).

$ head -1 VERSION
4.02.3+iossim

Modify the Makefile as follows. If you see this at around line 315:

echo "#!`which ocamlrun`" > boot/camlheader

change it to this instead:

echo "#!$(BINDIR)/ocamlrun" > boot/camlheader

Now you’re going to run the script build.sh, but you need to make some changes first.

Change the platform to iPhoneSimulator:

platform=iPhoneSimulator

If you’re building for 32 bits, the arch line near the beginning of build.sh should say arch=i386. If you’re building for 64 bits, it should say arch=x86_64.

arch=x86_64 # (or i386)

Add a line after the arch line that defines the minimum iOS version that you want to allow for your iOS apps. It makes sense to set it to the earliest version you want to support in your apps. However, simulators for very early iOS versions aren’t readily available in Xcode. My apps don’t depend on any recent features of iOS, so I specify version 7.0.

minver=7.0

Delete or comment out the sdk line:

# sdk=8.4

Modify the SDK line so it looks like this:

SDK=/Developer/SDKs/${platform}.sdk

(This works because the SDK directory name no longer changes with each version. You can find the SDK version in SDKSettings.plist. This is a tremendous simplification.)

Now change all the gcc lines to use minver. All the gcc lines should have this value for the -miphoneos-version-min flag:

-miphoneos-version-min=$minver

In the current build.sh script there are three lines to change.

If building for 32 bits, add -Wl,-no_pie to the -libs line, giving something like this:

-libs "-Wl,-syslibroot,$PLT$SDK -Wl,-no_pie" \

Now choose an install location for the compiler. The binaries that I made use /usr/local/ocamliossim$BITS. Build and install the cross compiler like this:

$ T=/usr/local/ocamliossim$BITS
$ ./build.sh -prefix $T -target-bindir $T/bin
$ sudo make install

Now you’re ready to test the compiler as described above under Test.

Comments

blog comments powered by Disqus