Skip to content

Modernize: hierarchical module names + compat package#855

Closed
balat wants to merge 41 commits into
masterfrom
modernize
Closed

Modernize: hierarchical module names + compat package#855
balat wants to merge 41 commits into
masterfrom
modernize

Conversation

@balat

@balat balat commented Mar 27, 2026

Copy link
Copy Markdown
Member

Summary

Migrates the public API of eliom to hierarchical module names
(version 13.0). Pre-existing flat Eliom_xxx names continue to work
via a new eliom-compat package, which makes the upgrade opt-in for
users.

Module name changes

Public modules are now accessed as Eliom.Service, Eliom.Content,
Eliom.Parameter, Eliom.Registration, Eliom.Client, ... instead
of the legacy flat Eliom_xxx prefix. Implemented with
(include_subdirs qualified) + (wrapped false) in dune.

Eliom_common is now Eliom.Common; most internal modules lost
their eliom_ / eliommod_ prefix as well (Content_core,
Mod_main, Mod_pagegen, ...).

A few names are kept as-is for conflict reasons (they remain
accessible at the top level under their original Eliom_xxx
name):

Module Conflict
eliom_form Js_of_ocaml.Form
eliom_lazy Stdlib.Lazy
eliom_react react library
eliom_uri uri library

New eliom-compat package

Provides the legacy Eliom_xxx module names as include-aliases of
the new Eliom.Xxx modules. Users add eliom-compat.server /
eliom-compat.client to their dune (libraries ...) and existing
code keeps compiling.

Breaking changes not covered by compat

  • Eliom.runEliom.App.run (dune's auto-generated wrapper module
    cannot contain val declarations).
  • module type of Eliom_content.Html.F triggers OCaml's
    strengthening bug on wrapped libraries. Use the named module type
    Eliom_content.Html.T instead (also exposed as
    Eliom.Content.Html.T).
    Tools.Make, Ot.Icons.Make, and the os_template Make functor
    all use it.

New: Eliom.Content.Html.T

Named module type for the Tyxml HTML signature shared by F and
D, with Eliom's LINKS_AND_FORMS extensions. Use it as the parameter
signature of functors that need to abstract over the F/D choice,
instead of module type of Content.Html.F (which is broken on
wrapped libraries).

Distillery templates

  • Installed at lib/eliom/templates/<name>/ via the standard dune
    (install (section lib_root) ... (with_prefix ...)) pattern.
  • eliom-distillery discovers templates from the standard
    lib/eliom/templates/ location plus $ELIOM_DISTILLERY_PATH,
    instead of the previous per-package eliom-templates/
    subdirectories.
  • Templates updated to use the new module names + Eliom.App.run.

Build system

  • Migrated to wrapped ocsigenserver module names (Ocsigen.Server,
    Ocsigen.Extensions, Ocsigen.Request, ...).
  • PPX gained -internal and -internal-prefix flags for compiling
    wrapped dependent libraries (e.g. ocsigen-start).
  • Removed the eliom.ocamlbuild plugin and the legacy topkg/pkg
    build artifacts. API doc is now generated by
    build/gen_wikidoc.sh (ocamldoc + wikidoc plugin); run via
    make wikidoc.

Bug fixes

  • Syntax.is_site_available now checks that the sitedata stack is
    actually non-empty during initialisation, instead of just relying
    on Ocsigen.Extensions.during_initialisation. Fixes a crash on
    startup exposed by the new module link order
    (Eliom_site_information_not_available raised by
    PPX-inserted top-level close_server_section calls in
    extension-linked .eliom files).
  • Client PPX uses eliom_expr for get_injection references so
    wrapped modules resolve correctly.

Documentation

  • README has a new "Generating API documentation" section.
  • doc/{server,client}.indexdoc updated to drive a structured
    menu.wiki (grouped by Content / Service creation /
    Client-server communication / etc.).

Test plan

  • dune build @check passes.
  • dune build -p eliom passes.
  • dune build -p eliom-compat passes.
  • make wikidoc regenerates 534 .wiki files (server + client).
  • eliom-distillery -template app.exe generates and builds correctly.
  • eliom-distillery -template app.lib generates a project that builds.
  • Pre-rename os_template builds against eliom-compat (after
    fixing the four module type of and Eliom.run call sites
    documented above).
  • Manual visual inspection of the wiki menu on ocsigen.org after
    the wikidoc branch is merged.

@balat
balat force-pushed the modernize branch 4 times, most recently from efac8a4 to 8fd20d2 Compare March 28, 2026 21:31
@balat
balat marked this pull request as draft April 9, 2026 15:48
@balat
balat force-pushed the modernize branch 3 times, most recently from a5a6354 to 2856d5f Compare April 30, 2026 19:40
@balat balat changed the title Modernize module names: Eliom.Service instead of Eliom_service Modernize: hierarchical module names + compat package May 28, 2026
@balat
balat force-pushed the modernize branch 8 times, most recently from 8ebf215 to ad7723c Compare May 29, 2026 15:16
balat added 12 commits June 22, 2026 14:37
Pure file renames, no content changes. For example:
  eliom_service.server.ml → service.server.ml
  eliom_content.eliom → content.eliom

Files NOT renamed (name conflicts with Stdlib/external libs):
  eliom_form (conflicts with Js_of_ocaml.Form)
  eliom_lazy (conflicts with Stdlib.Lazy)
  eliom_react (conflicts with react library)
  eliom_uri (conflicts with uri library)

Internal modules also kept unchanged:
  eliom_common, eliom_types, eliom_runtime, *_base, *_core, etc.

This commit does not compile: reference updates follow.
Update all internal references from Eliom_xxx to the new short names.
For example:
  Eliom_service.create → Service.create
  Eliom_parameter.int → Parameter.int

References updated in:
  - Renamed source files (74 files)
  - Internal modules (eliom_common, eliommod_*, etc.)
  - PPX code (ppx_eliom_server.ml, ppx_eliom_utils.ml)

References NOT changed (modules not renamed):
  Eliom_form, Eliom_lazy, Eliom_react, Eliom_uri
  Eliom_common, Eliom_runtime, Eliom_types, and all *_base/*_core modules
Create/update the Eliom module as the primary entry point:
  Eliom.Service, Eliom.Registration, Eliom.Content, etc.

Modules with name conflicts use the old names:
  Eliom.Form = Eliom_form  (Js_of_ocaml.Form conflict)
  Eliom.Lazy = Eliom_lazy  (Stdlib.Lazy conflict)
  Eliom.React = Eliom_react (react library conflict)
  Eliom.Uri = Eliom_uri    (uri library conflict)

Create client-side Eliom module (previously server-only).
Update dune: modules_without_implementation for renamed sig modules.
Regenerate dune.server and dune.client.
Provide backward-compatible module names (Eliom_service, etc.) in
separate libraries for existing code that hasn't migrated to the
new Eliom.Service style.

Usage: add eliom.compat.server (or .client) as a library dependency.

These libraries are intended to be deprecated and eventually removed
once downstream code has migrated.

Server: 22 compat modules (16 .ml + 6 sig-only .mli)
Client: 19 compat modules (12 .ml + 7 sig-only .mli)
- Migrate Eliom_X module references to Eliom.X (Eliom_service.create
  → Eliom.Service.create, Eliom_registration.App → Eliom.Registration.App,
  Eliom_content.Html.F → Eliom.Content.Html.F, etc.)
- Rename PROJECT_NAME_main.eliom → PROJECT_NAME_server.eliom
  (executables: testapp_server.bc, testapp_server.exe)
- Update Makefile.app and dune targets accordingly
- Eliom_xxx → Eliom.Xxx in source files
- api.odocl: use new short module names
- indexdoc: update documented module list
- filelist.ml: update module list for packaging
- _tags: disable warning 34 (OCaml 5.4), add logs.browser package
Define a named module type Content.Html.T (built from Tyxml's
Html_sigs.Make(Xml)(Svg.F.Raw').T plus Eliom's LINKS_AND_FORMS) and
use it as the parameter signature of Tools.Make instead of
[module type of Content.Html.F].

Avoids the OCaml strengthening bug that triggers when [module type of]
captures wrapped module paths through an alias.
Use dune's [(wrapped (module_name Eliom))] feature to expose the
public modules as [Eliom.Service], [Eliom.Content], [Eliom.Client],
... instead of the historical flat [Eliom_xxx] names.  Update PPX
client and dune configuration accordingly.
The module was incorrectly left with its old name despite being
visible to users via PPX-generated type annotations.

Also rename the local Client_value module in eliom_client_core.client.ml
to Client_value_registry to avoid shadowing.
Accessible as Eliom.Syntax via wrapping. Used by the PPX in
generated code (Eliom.Syntax.client_value, Eliom.Syntax.to_poly, etc.)

Also adds Syntax.to_poly (previously only in Lib.to_poly) since the
PPX generates Eliom.Syntax.to_poly in user code.
balat added 25 commits June 22, 2026 14:37
Breaking change: Eliom.run is now Eliom.App.run due to module wrapping.
The auto-generated wrapper module cannot contain val declarations,
so this cannot be covered by eliom-compat.
Define eliom-compat as its own (package ...) in dune-project (was
previously an [eliom.compat] sub-library) so that odoc no longer
collides between the modernized [Eliom.Xxx] names exported by [eliom]
and the legacy [Eliom_xxx] aliases exported by the compat lib.

The two libraries are renamed from eliom.compat.{server,client} to
eliom-compat.{server,client}.

Existing dune executables/installs that were implicit when there was
only one package now need an explicit (package eliom) stanza.
The old ocamlbuild-based doc system could not handle wrapped modules.
New build/gen_wikidoc.sh script:
- Uses dune-compiled .cmi files from _build/
- Creates short-name .cmi aliases (Bus.cmi -> include Eliom__Bus)
  so ocamldoc can resolve cross-references
- Gets include paths from dune's merlin config
- Generates wiki docs for both server and client
- Remove src/ocamlbuild/ (eliom.ocamlbuild plugin)
- Remove pkg/ (topkg packaging system)
- Remove build/build.ml, build/doc.ml, build/_tags (ocamlbuild config)
- Remove _tags, src/_tags, src/ppx/_tags, README.build
- Remove js_of_ocaml-ocamlbuild dependency from dune-project/opam
- Clean up ocamlbuild references in comments

The doc generation now uses build/gen_wikidoc.sh (previous commit).
The distillery templates in pkg/distillery/ are preserved.
When -internal-prefix Os is passed, the client PPX strips the Os.
wrapper prefix from type paths read from server .cmo files. This is
needed for compiling wrapped libraries like ocsigen-start that depend
on Eliom.
The eliom.opam.template is consumed by dune to append the
x-ci-accept-failures stanza into the generated eliom.opam.
Accessible as Eliom.Common from user code.
- eliom_content_core -> content_core
- eliom_content_ -> content_functor
- eliom_parameter_base -> parameter_base
- eliom_service_base -> service_base
- eliom_route_base -> route_base
- eliom_comet_base -> comet_base
- eliom_common_base -> common_base
- eliom_cookies_base -> cookies_base
- eliom_lib_base -> lib_base
- eliom_types_base -> types_base
- eliom_types -> types
- eliom_runtime -> runtime
- eliom_error_pages -> error_pages
- eliom_process -> process
- eliom_client_base -> client_base
- eliom_client_main -> client_main
- eliommod -> mod_main
- eliommod_xxx -> mod_xxx

Kept with prefix (name conflicts):
- eliom_react (react package)
- eliom_lazy (Stdlib.Lazy)
- eliom_uri (uri package)
- eliom_form (Js_of_ocaml.Form)
Client_value, Common, Content.Html, Registration.App, etc.
Ocsigen_extensions -> Ocsigen.Extensions
Ocsigen_request -> Ocsigen.Request
Ocsigen_response -> Ocsigen.Response
Ocsigen_lib -> Ocsigen_base.Lib
Ocsigen_cache -> Ocsigen_base.Cache
Ocsigen_header -> Ocsigen_http.Header
etc.
Place all module sources in [src/lib/{server,client}/Eliom/] and
use dune's standard [(include_subdirs qualified)] + [(wrapped false)]
to expose them under the [Eliom.] namespace.  This removes the
dependency on the custom [(wrapped (module_name ...))] dune
extension.

[gen_dune.ml] now passes [-internal] to [--as-pp] PPX invocations
and emits [(subdir Eliom ...)] rules.  Mli-only modules
(*_sigs, wrap) are copied as [.ml] to avoid
[modules_without_implementation].
Use dune's standard install pattern:

    (install
     (package eliom)
     (section lib_root)
     (files
      (glob_files_rec
       (templates/<name>/* with_prefix eliom/templates/<name>))))

so the bundled templates (app.exe, app.lib, basic.ppx) land at
[lib/eliom/templates/<name>/].  Packages that ship their own
templates install them at the same standard location, where
eliom-distillery looks by default.

[ELIOM_DISTILLERY_PATH] is preserved as an extra search path.
[Syntax.is_site_available] was returning [true] as soon as
ocsigenserver reported being in its initialisation phase, regardless
of whether a sitedata had actually been pushed. This is wrong during
cmxs/cma loading: the top-level [close_server_section] calls inserted
by the PPX in modules like [Service_base] try to read
[Reference.Volatile.get site_data], which calls
[Common.get_current_sitedata] and crashes with
[Eliom_site_information_not_available] when the stack is empty.

The default sitedata is pushed by a top-level [let _ =] in
[Mod_main]. With the dunified build + [(include_subdirs qualified)],
modules are linked alphabetically, so [Service_base] is loaded
before [Mod_main] and its top-level [close_server_section] sees an
empty stack.

Add [Common.has_current_sitedata] to expose the stack-emptiness
predicate, and require it in [is_site_available] alongside the
existing [during_initialisation] check.
Module namespace migration to Eliom.Xxx, eliom-compat package,
Eliom.Content.Html.T, distillery template install path,
ocsigen-dune-rules integration, fix for is_site_available.
The Eliom_ prefix on the four legacy exceptions was redundant since
they live under the Eliom.Common namespace
(Eliom.Common.Eliom_site_information_not_available was visibly silly).

- Common_base.Eliom_site_information_not_available → Site_information_not_available
- Common.Eliom_do_redirection → Do_redirection
- Common.Eliom_do_half_xhr_redirection → Do_half_xhr_redirection
- Request_info (client) Eliom_no_raw_post_data_on_client → No_raw_post_data_on_client

The first three are exposed in the mli; their legacy names are kept
as backwards-compatible aliases (exception X = Y) so user code that
catches the old names continues to work. The fourth was internal
(not in any .mli), so the alias was dropped.

Internal references to the legacy names are still in place; they
will be migrated in a follow-up commit.
Update all internal references that previously raised or pattern-matched
[Common.Eliom_X] to use the new short forms
[Common.Site_information_not_available], [Common.Do_redirection],
[Common.Do_half_xhr_redirection]. Behaviour is unchanged because the
legacy names are aliases of the new ones.
Cross-references to {!Common.Eliom_site_information_not_available} in
service.server.mli, state.server.mli, config.server.mli,
request_info.server.mli, reference.server.mli, registration.server.mli
now point to the new {!Common.Site_information_not_available}.
@balat
balat force-pushed the modernize branch 2 times, most recently from 558f5e7 to 4eab42e Compare June 25, 2026 14:57
@balat

balat commented Jun 25, 2026

Copy link
Copy Markdown
Member Author

Superseded by #859, which now targets master directly and contains both the module-namespace modernization and the Deriving_Json migration (the modernize branch is being retired in favour of deriving).

@balat balat closed this Jun 25, 2026
@balat
balat deleted the modernize branch June 25, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant