When users specify multiple global ppx transformations via preprocessors in a dune file, the order they apply is alphabetically by library name.
This is problematic because ppx ordering is semantically significant: the output of one ppx often serves as input to another, and many ppxes don't commute. Using the name as a order is problematic since users can't change it (and they make authors responsible for the ppx name)
Current Behavior
Given this dune file:
(library
(name mylib)
(preprocess (pps ppx_jane ppx_deriving ppx_blob)))
Expected: ppxes are applied in the order written: ppx_jane → ppx_deriving → ppx_blob
Actual: Dune sorts them alphabetically and applies them as: ppx_blob → ppx_deriving → ppx_jane
Root Cause
In src/dune_rules/ppx_driver.ml, lines 48-52, Dune explicitly sorts PPX libraries alphabetically:
let of_libs libs =
let pps =
(let compare a b = Lib_name.compare (Lib.name a) (Lib.name b) in
List.sort libs ~compare)
|> List.map ~f:Lib.name
in
(* ... *)
This sorting appears to be for generating a stable cache key, but it also discards user intent regarding execution order.
When users specify multiple global ppx transformations via preprocessors in a
dunefile, the order they apply is alphabetically by library name.This is problematic because ppx ordering is semantically significant: the output of one ppx often serves as input to another, and many ppxes don't commute. Using the name as a order is problematic since users can't change it (and they make authors responsible for the ppx name)
Current Behavior
Given this
dunefile:Expected: ppxes are applied in the order written:
ppx_jane→ppx_deriving→ppx_blobActual: Dune sorts them alphabetically and applies them as:
ppx_blob→ppx_deriving→ppx_janeRoot Cause
In
src/dune_rules/ppx_driver.ml, lines 48-52, Dune explicitly sorts PPX libraries alphabetically:This sorting appears to be for generating a stable cache key, but it also discards user intent regarding execution order.