Danny Willems -- Work In Progress

Fighting to follow my values. Integrity is key. Reputation is key. Fighting for privacy and security on the Internet. Being respectful is your first duty.

Research Publications Public Talks Open source software contributions CV Education Blog PGP public key Recommended softwares Contact Proton calendar for cryptography and cybersecurity events
14 July 2016

Ocsigen: how to compile an Eliom project - Understand the compilation process in deep

by Danny Willems

It’s time to write my first article on Ocsigen and especially on Eliom. I began a week ago my internship in BeSport, a social network centralized on sports and entirely developed in OCaml using the Ocsigen projects so I needed to learn how Ocsigen works in general.

Ocsigen? What’s that? It’s an atom no?

Yes, oxygen is a chemical element but Ocsigen is also an OCaml web framework began in 2004.

Wait, another web framework? There are plenty of existing web frameworks

Yeah, I agree. But Ocsigen is different in some cases. First, Ocsigen is entirely written in OCaml: no PHP, no JavaScript, no HTML. Second, Ocsigen contains independent «small» projects which, together, form a very elegant framework. Here some of these sub-projects:

Oh great! Can you show me an example?

Yes, of course. I will show a basic Eliom project and how to compile it. In other articles, I will give js_of_ocaml, ocsigenserver and lwt examples. The main goal of this article is to show you the entire process to build an Eliom project, from code to compilation by configuring the ocsigenserver.

This article doesn’t explain how Eliom works and all Eliom modules in details. It’s just a step by step explanation of the compilation process. Other articles are coming for these purpose

How to install Eliom?

First, switch to a stable 4.02.3 OCaml compiler with

opam switch 4.02.3

or if you want to give a name to the compiler, use

opam switch eliom-build-test --alias-of 4.02.3

In this way, dependencies are the same for you and me.

The simplest way to install Eliom is to use OPAM:

opam install eliom

It will install all dependencies such like lwt, js_of_ocaml, ocsigenserver and the last Eliom version (which is currently 5.0). For the dev version (ie by using opam pin to the Github repository), you need to pin the dev version of ocsigenserver.

The build tools

Eliom opam package comes with some tools (binary) you can use to build Eliom projects easier. Most of them are wrappers to common OCaml build tools:

eliomc compiles to bytecode and eliomopt to native code. For the rest of this article, we will use eliomc

Small Eliom code

An Eliom project uses files with extension .eliom and .eliomi (for interface). These filetypes are OCaml common filetypes (ml and mli) and contains OCaml code. It’s just a way to distinguish between common OCaml code and Eliom code (Eliom build tools use these differences for some compilation rules).

This is a code example which defines a website and a page containing a paragraph with «Hello, World!». Paste it in a file hello_world.eliom. We will use this filename for the rest of the article.

[%%shared
    open Eliom_content
    open Html5.D
]

let content =
  fun () () ->
    Lwt.return
      (html
        (head (title (pcdata "Hello, World!")) [])
        (body
          [p [pcdata "Hello, World!"]]
        )
      )

let main_service =
  Eliom_registration.Html5.register_service
    ~path:[]
    ~get_params:Eliom_parameter.unit
    content

Eliom works in term of services and not in term of page or url. The service is defined by

let main_service =
  Eliom_registration.Html5.register_service
    ~path:[]
    ~get_params:Eliom_parameter.unit
    (* content *)

This service (main_service) returns an HTML5 page (because we use the module Eliom_registration.Html5) which has as a content content. The function content defines a typed HTML5 page: head, body, title, pcdata and p are functions defined in the module Eliom_content.Html5.D.

You can find more information about services and Eliom in the official Ocsigen tutorials.

Extract the client and server types information

Even if we don’t have client side code in this example, as I said, Eliom allows you to write the client and service side codes of your web applications in only one file. More information available here.

The first step to compile an Eliom project is to extract client and server type information. eliomc has an option (-infer) to extract these information. eliomc copies all compiled files in a directory called _server. This directory can be changed by modifying the variable ELIOM_SERVER_DIR. It’s the same thing for the client side code which are compiled in _client directory. This directory could be changed by modifying the variable ELIOM_CLIENT_DIR.

In this tutorial, we use the PPX syntax ([%%shared (* code *)] is an example of the PPX extension) so we need to add -ppx to each call to eliomc, eliomopt and js_of_eliom.

Extract type information with

eliomc -ppx -infer hello_world.eliom

Compile server side code

Now we are able to compile the server side code in bytecode. This server side code must be compiled as a library for Ocsigenserver.

eliomc -ppx -c hello_world.eliom # compile in bytecode
eliomc -ppx -a -o hello_world.cma _server/hello_world.cmo # build a library for ocsigenserver

Compile client side code

Client side code are essentially JavaScript code got from OCaml and compiled with js_of_ocaml. We use js_of_eliom to get client side code. We need the client side bytecode and use the resulting bytecode with js_of_eliom (same process with js_of_ocaml) to obtain the corresponding JavaScript. js_of_eliom extracts the client side of the Eliom file and compiles it in JavaScript. The corresponding cmo file is copied in _client directory.

js_of_eliom -ppx -c hello_world.eliom # get bytecode
js_of_eliom -ppx -o hello_world.js _client/hello_world.cmo # compile in JavaScript

Ocsigenserver configuration

Now we have all compiled files we need for ocsigenserver: the hello_world.cma library which will be loaded in ocsigenserver and the client side code hello_world.js. The last thing is to configure the server.

Ocsigenserver has an interesting feature: you can locally run the server on a port > 1024 and the only thing you need to give is a configuration file which is an XML file. All information can be found here. I don’t describe each line because it’s not the goal of this article.

If you have already configured a HTTP server like Apache, you know the main directories are:

We use the same hierarchy for a local configuration of ocsigenserver except than all these directories will be created in a local directory called local. Our site will be named hello_world so we create a sub-directory in each directory. We add a sub-directory to local/var/www/hello_world called eliom to put in compiled Eliom client file ie hello_world.js: it gives the possibility to distinguish with other JavaScript or CSS files (called static).

mkdir -p local/var/www/html/hello_world # Site files
mkdir -p local/var/www/html/hello_world/eliom # Eliom files
mkdir -p local/etc/hello_world # Configuration files
mkdir -p local/lib/hello_world # Library file ie cma file.
mkdir -p local/var/log/hello_world # Log
mkdir -p local/var/data/hello_world # Data
mkdir -p local/var/run # Pipe to send command to ocsigenserver.

I give a simple ocsigenserver configuration file:

<ocsigen>
  <server>
    <charset>utf-8</charset>

    <port>8080</port>

    <logdir>local/var/log/hello_world</logdir>
    <datadir>local/var/data/hello_world</datadir>

    <extension findlib-package="ocsigenserver.ext.staticmod"/>
    <extension findlib-package="ocsigenserver.ext.ocsipersist-dbm"/>
    <extension findlib-package="eliom.server"/>

    <commandpipe>local/var/run/hello_world-run</commandpipe>
    <host hostfilter="*">
      <static dir="local/var/www/hello_world/eliom" />
      <eliommodule module="local/lib/hello_world/hello_world.cma" />
      <eliom/>
    </host>
  </server>
</ocsigen>

Save this content in a file named hello_world.conf

The tags are explicit so I don’t explain it. You can find all significations in the official documentation..

The last thing to do is to copy all our files in the corresponding local ocsigenserver configuration i.e. in the proper sub-directory of the local directory.

cp hello_world.cma local/lib/hello_world
cp hello_world.js local/var/www/html/hello_world/eliom
cp hello_world.conf local/etc/hello_world

Launch ocsigenserver

Now we have a full ocsigenserver configuration and a Eliom website build from scratch with tools given by the Ocsigen team. To run the ocsigenserver with the previous configuration, use

ocsigenserver -c local/etc/hello_world/hello_world.conf

and go to http://localhost:8080: you have a «Hello, World!» web application entirely written in OCaml!

tags: OCaml - Ocsigen - Web development - RSS