On Friday morning I discovered a Raspberry Pi on my desk. The Raspberry Pi is a small single-board computer powered by a 700MHz ARM CPU. You can pick them up for as little as $25 and boot ready-made full-featured Linux images off of SD. Out of the box, however, the Raspberry Pi includes no cables, instructions, or boot media. Fortunately the office community quickly came together and delivered an HDMI-to-DVI cable, an SD card, and a mini-USB charger. Ready to roll!

We followed the Quick Start Guide, opting for the Soft-float Debian “wheezy” image to play it safe.

Power on! Lacking any real BIOS, the Raspberry Pi booted to Linux almost instantly and after choosing some yes/nos from an ncurses setup menu (the only way to GUI) it rendered the standard soothing Linux gray-on-black console with bash prompt, cursor blinking expectantly. It even went ahead and requested an IP address from our DHCP server once I connected ethernet.

Cool.

Since this is Jane Street it wasn’t long before someone popped the question:

Can the Raspberry Pi run OCaml?

Can it build and run Async!?

It sure can! It’s a snap with opam:

sudo apt-get install ocaml git m4
git clone https://github.com/OCamlPro/opam.git
cd opam
./configure && make install
opam init

Update your shell environment as per opam init’s instructions. I threw this into my ~/.profile and re-logged in:

which opam && eval $(opam config --env)

Next I used opam to install async and all of its dependencies: opam install async.

If you have trouble building opam from the github tip try updating to the revision we used, cdc6decbf. The entire process takes about 2-3 hours as opam builds everything from source.

Here’s how we pulled together a simple async echo server:

mkdir echo_server
cd echo_server
cat > hello_async.ml
open Core.Std
open Async.Std

let port = 10007

let handler _addr reader writer =
  let rec echo_loop () =
    Reader.read_line reader
    >>= function
      | Eof -> return ()
      | Ok line ->
        let s = line ^ "\n" in
        Writer.write writer s;
        echo_loop ()
      in
      echo_loop ()

let () =
  let d =
    Tcp.Server.create (Tcp.on_port port) ~on_handler_error:`Ignore handler
    >>| fun _server ->
    printf "Echo server started on port %d\n%!" port
  in
  don't_wait_for d;
  never_returns (Scheduler.go ())

cat > Makefile

OCAMLMAKEFILE = OCamlMakefile

RESULT = hello_async

SOURCES = hello_async.ml
PACKS = async
THREADS = true
ANNOTATE = true

-include $(OCAMLMAKEFILE)

For simple projects OCamlMakefile is hard to beat. Grab it here

wget https://bitbucket.org/mmottl/ocaml-makefile/raw/a50165b23fb73c66716777d778c4c84ec2aa7183/OCamlMakefile

You should now have a file called OCamlMakefile. make ./hello_async &

Now for the moment of truth, let’s connect to the echo server with netcat.

nc localhost 10007
hello async!
hello async!

Awesome!