How to Flatpak OCaml applications
How to Flatpak an OCaml application
Let’s take a couple OCaml applications to illustrate Flatpak distributing and packaging leveraging the Flatpak SDK Extension for OCaml:
- a hello world CLI application
- a simple GTK program from the Introduction to Gtk OCaml tutorial
The SDK is only needed during the building phase.
Table of contents
- How to Flatpak an OCaml application
Creating a hello world CLI application
Create a hello world example.ml
:
let () = print_endline "hello world"
You can compile your code with the OCaml compiler ocamlopt
(no need to do so at this point):
$ ocamlopt -o example example.ml
$ ./example
hello world
Flatpak manifest
Some things to note in the following manifest:
- The SDK extension pointing to the Flatpak SDK Extension for OCaml ↵
- The build options setting the
PATH
↵ - Build some pre-requisistes using
dune
↵ - Installing the application to
/app/bin
↵
app-id: flatpak.ocaml.example
runtime: org.freedesktop.Sdk
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.ocaml
command: example
build-options:
append-path: /usr/lib/sdk/ocaml/bin
modules:
- name: camlp-streams
buildsystem: simple
sources:
- type: git
url: https://github.com/ocaml/camlp-streams
branch: trunk
build-commands:
- dune build
- name: example
buildsystem: simple
sources:
- type: file
path: example.ml
build-commands:
- ocamlopt -o example example.ml
- install -Dm755 example -t /app/bin/
Install and run the application
Build and install the Flatpak package locally using flatpak-builder
:
$ flatpak-builder --force-clean build-dir flatpak.ocaml.example.yaml
$ flatpak-builder --user --install --force-clean build-dir flatpak.ocaml.example.yaml
Run the application:
$ flatpak run flatpak.ocaml.example
hello world
The application has an installed size of 369.2 kB:
$ flatpak info flatpak.ocaml.example
ID: flatpak.ocaml.example
Ref: app/flatpak.ocaml.example/x86_64/master
Arch: x86_64
Branch: master
Origin: example-origin
Collection:
Installation: user
Installed: 368.3 kB
Runtime: org.freedesktop.Sdk/x86_64/22.08
Sdk: org.freedesktop.Sdk/x86_64/22.08
Commit: 02386f983e23b6d991651e86c1b1a55531fd4fa6504c730c938bc06033c19f40
Subject: Export flatpak.ocaml.example
Date: 2023-10-09 12:34:32 +0000
Creating a simple GTK program
Let’s use the simple lablgtk
program from the Introduction to Gtk OCaml tutorial simple.ml
:
open GMain
open GdkKeysyms
let locale = GtkMain.Main.init ()
let main () =
let window = GWindow.window ~width:320 ~height:240
~title:"Simple lablgtk program" () in
let vbox = GPack.vbox ~packing:window#add () in
window#connect#destroy ~callback:Main.quit;
(* Menu bar *)
let menubar = GMenu.menu_bar ~packing:vbox#pack () in
let factory = new GMenu.factory menubar in
let accel_group = factory#accel_group in
let file_menu = factory#add_submenu "File" in
(* File menu *)
let factory = new GMenu.factory file_menu ~accel_group in
factory#add_item "Quit" ~key:_Q ~callback: Main.quit;
(* Button *)
let button = GButton.button ~label:"Push me!"
~packing:vbox#add () in
button#connect#clicked ~callback: (fun () -> prerr_endline "Ouch!");
(* Display the windows and enter Gtk+ main loop *)
window#add_accel_group accel_group;
window#show ();
Main.main ()
let () = main ()
You can install the dependencies and compile your code (no need to do so at this point):
$ opam install lablgtk
$ ocamlfind ocamlopt -package lablgtk2 -linkpkg simple.ml -o simple
$ ./simple
Ouch!
This is what you should see when you run it:
Preparations
Import GTK2 library
We need the GTK2 library, let’s grab it from Flathub shared-modules repo:
$ git submodule add https://github.com/flathub/shared-modules.git
Wrapper script
LD_LIBRARY_PATH
is empty by default when running Flatpak applications (flatpak/flatpak-builder#474) so we will need a wrapper script simple.sh
around the application:
export LD_LIBRARY_PATH=/app/lib
exec /app/bin/simple
Building from sources
lablgtk
can be built from its sources.
Flatpak manifest
Some things to note in the following manifest:
- The SDK extension pointing to the Flatpak SDK Extension for OCaml ↵
- Permissions for the Flatpak app to access X11 (
--share=ipc
and--socket=fallback-x11
) ↵ - The build options setting the
PATH
and some OCaml related environment variables ↵ - For some reason
debuginfo
was breakingocamlfind
, so it has been disabled ↵ - We are importing GTK2 from the shared modules repository ↵
- Installing some
lablgtk
pre-requisites:ocamlfind
andcamlp-streams
(required only with OCaml>=5) ↵ lablgtk
is build from its sources instead of using opam ↵- Installing the application to
/app/bin
andlablgtk
library to/app/lib
↵ - Removal of the build files at the post-install phase to limit the size of the resulting Flatpak application ↵
- Wrapper setup ↵
app-id: flatpak.ocaml.lablgtk.build
runtime: org.freedesktop.Sdk
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.ocaml
command: simple.sh
finish-args:
- --share=ipc
- --socket=fallback-x11
build-options:
append-path: /usr/lib/sdk/ocaml/bin:/app/share/runtime/ocaml
env:
CAML_LD_LIBRARY_PATH: /app/share/runtime/ocaml/lib:/usr/lib/sdk/ocaml/lib/ocaml:/usr/lib/sdk/ocaml/lib/ocaml/stublibs
OCAMLFIND_CONF: /app/share/runtime/ocaml/findlib.conf
no-debuginfo: true
modules:
- shared-modules/gtk2/gtk2.json
- name: ocamlfind
buildsystem: simple
sources:
- type: git
url: https://github.com/ocaml/ocamlfind
branch: master
build-commands:
- mkdir -p ${FLATPAK_DEST}/share/runtime/ocaml
- ./configure -bindir ${FLATPAK_DEST}/share/runtime/ocaml -config ${FLATPAK_DEST}/share/runtime/ocaml -no-topfind -sitelib ${FLATPAK_DEST}/share/runtime/ocaml/lib
- make all
- make install
post-install:
- ocamlfind printconf
- name: camlp-streams
buildsystem: simple
sources:
- type: git
url: https://github.com/ocaml/camlp-streams
branch: trunk
build-commands:
- dune build
- dune install --prefix /app/share/runtime/ocaml
post-install:
- ocamlfind query camlp-streams
- name: lablgtk
buildsystem: simple
sources:
- type: archive
url: https://github.com/garrigue/lablgtk/archive/refs/tags/2.18.13.tar.gz
sha256: 7b9e680452458fd351cf8622230d62c3078db528446384268cd0dc37be82143c
build-commands:
- ./configure
- make world
- make old-install DESTDIR=/app/share/runtime/ocaml
- name: simple
buildsystem: simple
sources:
- type: file
path: simple.ml
build-commands:
- mv /app/share/runtime/ocaml/usr/lib/sdk/ocaml/lib/ocaml/lablgtk2 /app/share/runtime/ocaml/lib
- ocamlfind ocamlopt -package lablgtk2 -linkpkg simple.ml -o simple
- install -Dm755 simple -t /app/bin/
- mv /app/share/runtime/ocaml/usr/lib/sdk/ocaml/lib/ocaml/stublibs/dlllablgtk2.so /app/lib
post-install:
- rm -rf /app/share/runtime/ocaml
- name: simple-wrapper
buildsystem: simple
sources:
- type: file
path: simple.sh
build-commands:
- cp simple.sh /app/bin
Install and run the application
Build and install the Flatpak package locally using flatpak-builder
:
$ flatpak-builder --force-clean build-dir flatpak.ocaml.lablgtk.build.yaml
$ flatpak-builder --user --install --force-clean build-dir flatpak.ocaml.lablgtk.build.yaml
Run the application:
$ flatpak run flatpak.ocaml.lablgtk.build
Ouch!
This is what you should see when you run it:
The application has an installed size of 34.8 MB:
$ flatpak info flatpak.ocaml.lablgtk.build
ID: flatpak.ocaml.lablgtk.build
Ref: app/flatpak.ocaml.lablgtk.build/x86_64/master
Arch: x86_64
Branch: master
Origin: build-origin
Collection:
Installation: user
Installed: 34.8 MB
Runtime: org.freedesktop.Sdk/x86_64/22.08
Sdk: org.freedesktop.Sdk/x86_64/22.08
Commit: 6acda68f932e9728d942e976b6d6b94cab2929eb4c91b087f58792028f18d536
Subject: Export flatpak.ocaml.lablgtk.build
Date: 2023-12-19 09:29:13 +0000
Building with opam
Source files
We can leverage the OCaml Package Manager (opam) to install lablgtk
into the Flatpak. For that, let’s leverage flatpak-builder-tools, a collection of various scripts to aid in using flatpak-builder
that among other things contains a helper tool to automatically generate flatpak-builder source files from a .json
generated by opam tree
:
$ git clone https://github.com/flatpak/flatpak-builder-tools
$ cd flatpak-builder-tools/opam
$ opam tree --json=lablgtk.json lablgtk
$ ./flatpak-opam-generator.py lablgtk.json > sources/lablgtk.json
The output sources file sources/lablgtk.json
should look something like this:
[
{
"type": "file",
"url": "https://github.com/garrigue/lablgtk/archive/2.18.13.tar.gz",
"name": "lablgtk.2.18.13",
"md5": "d0a326b99475216cc22232e72c89415f",
"dest": "cache/md5/d0",
"dest-filename": "d0a326b99475216cc22232e72c89415f"
},
{
"type": "file",
"url": "https://github.com/ocaml/camlp-streams/archive/v5.0.1.tar.gz",
"name": "camlp-streams.5.0.1",
"md5": "afc874b25f7a1f13e8f5cfc1182b51a7",
"dest": "cache/md5/af",
"dest-filename": "afc874b25f7a1f13e8f5cfc1182b51a7"
},
{
"type": "file",
"url": "https://github.com/ocaml/dune/releases/download/3.10.0/dune-3.10.0.tbz",
"name": "dune.3.10.0",
"sha256": "9ff03384a98a8df79852cc674f0b4738ba8aec17029b6e2eeb514f895e710355",
"dest": "cache/sha256/9f",
"dest-filename": "9ff03384a98a8df79852cc674f0b4738ba8aec17029b6e2eeb514f895e710355"
},
{
"type": "file",
"url": "http://download.camlcity.org/download/findlib-1.9.6.tar.gz",
"name": "ocamlfind.1.9.6",
"md5": "96c6ee50a32cca9ca277321262dbec57",
"dest": "cache/md5/96",
"dest-filename": "96c6ee50a32cca9ca277321262dbec57"
}
]
Generate Flatpak manifest code
Let’s use the helper tool to generate the corresponding Flatpak manifest code:
$ ./flatpak-opam-generator.py --generate lablgtk lablgtk.json
...
# Manifest code generated by flatpak-opam-generator
- name: lablgtk
buildsystem: simple
sources:
- sources/lablgtk.json
- type: git
branch: master
url: https://github.com/ocaml/opam-repository
build-commands:
- ls -A --color=never | grep -Ev "cache|packages|repo" | xargs rm -rf
- opam admin filter -y lablgtk.2.18.13 camlp-streams.5.0.1 dune.3.10.0 ocamlfind.1.9.6
- opam admin cache
- opam repo add lablgtk .
- opam install -y lablgtk.2.18.13 camlp-streams.5.0.1 dune.3.10.0 ocamlfind.1.9.6
- opam repo remove --all lablgtk
post-install:
- opam info --field name,all-installed-versions lablgtk
Flatpak manifest
Some things to note in the following manifest:
- The SDK extension pointing to the Flatpak SDK Extension for OCaml ↵
- Permissions for the Flatpak app to access X11 (
--share=ipc
and--socket=fallback-x11
) ↵ - The build options setting the
PATH
and some OCaml related environment variables ↵ - We are importing GTK2 from the shared modules repository ↵
- Creation of a new switch for installing
lablgtk
↵ - The manifest code generated by flatpak-opam-generator for
lablgtk
↵ - Installing the application to
/app/bin
andlablgtk
library to/app/lib
↵ - Removal of the ocaml switch at the post-install phase to limit the size of the resulting Flatpak application ↵
- Wrapper setup ↵
app-id: flatpak.ocaml.lablgtk.switch
runtime: org.freedesktop.Sdk
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.ocaml
command: simple.sh
finish-args:
- --share=ipc
- --socket=fallback-x11
build-options:
append-path: /app/share/runtime/ocaml/bin:/app/share/runtime/ocaml/switch/_opam/bin:/usr/lib/sdk/ocaml/bin
env:
CAML_LD_LIBRARY_PATH: /app/share/runtime/ocaml/switch/_opam/lib/stublibs:/app/share/runtime/ocaml/switch/_opam/lib/ocaml/stublibs:/app/share/runtime/ocaml/switch/_opam/lib/ocaml
OCAML_TOPLEVEL_PATH: /app/share/runtime/ocaml/switch/_opam/lib/toplevel
OPAMROOT: /app/share/runtime/ocaml
OPAMSWITCH: /app/share/runtime/ocaml/switch
OPAM_SWITCH_PREFIX: /app/share/runtime/ocaml/switch/_opam
modules:
- shared-modules/gtk2/gtk2.json
- name: switch
buildsystem: simple
sources:
- type: git
branch: master
url: https://github.com/ocaml/opam-repository
- type: archive
url: https://github.com/ocaml/ocaml/archive/refs/tags/5.1.0.tar.gz
dest: switch
sha256: 43a3ac7aab7f8880f2bb6221317be55319b356e517622fdc28359fe943e6a450
build-commands:
- mkdir -p ${FLATPAK_DEST}/share/runtime/ocaml
- mv switch ${FLATPAK_DEST}/share/runtime/ocaml
- opam init -y --bare --disable-sandboxing .
- opam switch create -y --deps-only ${FLATPAK_DEST}/share/runtime/ocaml/switch
- opam pin -y ${FLATPAK_DEST}/share/runtime/ocaml/switch
post-install:
- opam switch list
# Manifest code generated by flatpak-opam-generator
- name: lablgtk
buildsystem: simple
sources:
- sources/lablgtk.json
- type: git
branch: master
url: https://github.com/ocaml/opam-repository
build-commands:
- ls -A --color=never | grep -Ev "cache|packages|repo" | xargs rm -rf
- opam admin filter -y lablgtk.2.18.13 camlp-streams.5.0.1 dune.3.10.0 ocamlfind.1.9.6
- opam admin cache
- opam repo add lablgtk .
- opam install -y lablgtk.2.18.13 camlp-streams.5.0.1 dune.3.10.0 ocamlfind.1.9.6
- opam repo remove --all lablgtk
post-install:
- opam info --field name,all-installed-versions lablgtk
- name: simple
buildsystem: simple
sources:
- type: file
path: simple.ml
build-commands:
- ocamlfind ocamlopt -package lablgtk2 -linkpkg simple.ml -o simple
- install -Dm755 simple -t /app/bin/
- cp /app/share/runtime/ocaml/switch/_opam/lib/stublibs/dlllablgtk2.so /app/lib
post-install:
- rm -rf /app/share/runtime/ocaml
- name: simple-wrapper
buildsystem: simple
sources:
- type: file
path: simple.sh
build-commands:
- cp simple.sh /app/bin
Install and run the application
Build and install the Flatpak package locally using flatpak-builder
:
$ flatpak-builder --force-clean build-dir flatpak.ocaml.lablgtk.switch.yaml
$ flatpak-builder --user --install --force-clean build-dir flatpak.ocaml.lablgtk.switch.yaml
Run the application:
$ flatpak run flatpak.ocaml.lablgtk.switch
Ouch!
This is what you should see when you run it:
The application has an installed size of 11.3 MB:
$ flatpak info flatpak.ocaml.lablgtk.switch
ID: flatpak.ocaml.lablgtk.switch
Ref: app/flatpak.ocaml.lablgtk.switch/x86_64/master
Arch: x86_64
Branch: master
Origin: lablgtk-origin
Collection:
Installation: user
Installed: 11.3 MB
Runtime: org.freedesktop.Sdk/x86_64/22.08
Sdk: org.freedesktop.Sdk/x86_64/22.08
Commit: b3159cf05f2d89d7caaae3bc7bc6fd6a2ab70d5195374b4222a3cbedf8f635b0
Parent: 499a0892394a54c93976d422aa533563b6a1b1212fd9036fbc4fcbdd023f87dd
Subject: Export flatpak.ocaml.lablgtk.switch
Date: 2023-10-16 12:01:01 +0000
Publish the application
Info on how to later publish the application on Flathub can be found here.
Comments