Ocsigen and statically linking

I am trying to make a statically linked executable of an ocsigen server.
The code for the service looks like this:

module Stat_test_app =
  Eliom_registration.App (
  struct
    let application_name = "stat_test"
    let global_data_path = None
  end)

let f = lazy begin
  let main_service =
    Eliom_service.create
      ~path:(Eliom_service.Path [])
      ~meth:(Eliom_service.Get Eliom_parameter.unit)
      ()
  in

  Stat_test_app.register
    ~service:main_service
    (fun () () ->
       Lwt.return
         (Eliom_tools.F.html
            ~title:"stat_test"
            ~css:[["css";"stat_test.css"]]
            Html.F.(body [
              h1 [txt "Welcome from Eliom's distillery!"];
            ])))
end

let () = Eliom_service.register_eliom_module "stat_test" (fun () -> ignore (Lazy.force f))

I use this command to make the statically linked file (not sure if all package are needed):

ocamlfind ocamlopt -package lwt.unix,lwt_log,ocsigenserver.ext.userconf,eliom,ocsigenserver.ext.ocsipersist-dbm,ocsigenserver.ext.extendconfiguration,eliom.server,ocsigenserver.ext.staticmod,lwt_ppx,js_of_ocaml-ppx.deriving _server/stat_test.cmx server_main.cmx -thread -linkpkg -o myserver

config file:

<ocsigen>
  <server>
    <port>8080</port>
    <logdir>local/var/log/stat_test</logdir>
    <datadir>local/var/data/stat_test</datadir>
    <charset>utf-8</charset>
    <debugmode/>
    <commandpipe>local/var/run/stat_test-cmd</commandpipe>
    <extension name="stat_test" />
    <host hostfilter="*">
      <!-- <static dir="static" /> -->
      <!-- <static dir="local/var/www/stat_test/eliom" /> -->
      <!-- <eliommodule module="local/lib/stat_test/stat_test.cma" /> -->
      <!-- <eliom name="stat_test" /> -->
      <!-- <eliom/> -->
    </host>
  </server>
</ocsigen>

When I try to run it complains about the configuration file. With the extension ‘stat_test’ in the configuration file it comes with: Eliom_common_base.Eliom_site_information_not_available(“service”), but the service is first added in the register_eliom_module. It also complains about the tags in the host tag.

1 Like

Sorry for the late answer. I just saw your message …
I hope you found your answers.

Eliom registers the services for each site, while reading the configuration file.
The reason is that it must know where (on what URL) to register the service.
For that reason it is not possible to call register in a module called from .
You must find a way to delay service registration.

See how to do that here:
https://ocsigen.org/eliom/6.6/manual/config.html#static_linking

Static linking of Eliom apps has probably not been used very often. We are interested by experience reports on that matter. We are also interested by reports of any errors or mistakes in the documentation. Open issues or pull requests on Github.

Vincent

Thanks for getting back on this.

No, I have not spend time on this issue. I was mostly looking for ways to reduce the size of a docker image. Is this the way to do that or are there other ways to get a lighter docker image (or are people just living without a big image)?

Ok. The first step to get a lighter docker image is not to include the full .opam directory.
At Be Sport, we are using the following script to detect all dependencies of our Eliom program to be included in the docker image:

(* cmxs and META files we depend on *)

let line_from_process p =
  let ch = Unix.open_process_in p in
  let l = input_line ch in
  close_in ch;
  l

let ch = open_in "../local/etc/bs/bs-test.conf"
let i = Xml.parse_in ch
let _ =
  let packages = ref [] in
  let rec traverse n =
    match n with
    | Xml.PCData _ -> ()
    | Xml.Element (_, attrs, children) ->
        List.iter
          (fun (k, v) ->
             if k = "findlib-package" then packages := v :: !packages)
          attrs;
        List.iter traverse children
  in
  traverse i;
  let l =
    line_from_process
      (Printf.sprintf
         "ocamlfind query -predicates native,plugin,mt -r \
            -format %%m -separator ';' %s"
         (String.concat " " !packages))
    |> Str.split (Str.regexp_string ";")
    |> (fun l -> List.fold_right Ocsigen_lib.String.Set.add l
           Ocsigen_lib.String.Set.empty)
    |> Ocsigen_lib.String.Set.elements
  in
  List.iter (fun x -> Format.printf "%s@." x) l;
  let l =
    line_from_process
      (Printf.sprintf
         "ocamlfind query -predicates native,plugin,mt -r \
            -format %%p,%%+a -separator ';' %s"
         (String.concat " " !packages))
    |> Str.split (Str.regexp_string ";")
    |> List.map (Str.split (Str.regexp_string ","))
    |> List.filter
         (fun l ->
            match l with
            | p :: _ -> not (Ocsigen_lib.String.Set.mem p
                               Ocsigen_config.builtin_packages)
            | _      -> false)
    |> List.map List.tl |> List.flatten
    |> List.map (fun x -> String.sub x 0 (String.rindex x '.') ^ ".cmxs")
  in
  List.iter (fun x -> Format.printf "%s@." x) l