问题描述
为了使我们的代码适用于多个 ocamlgraph 版本,我们在 one of our files
中使用了此代码段#if OCAMLGRAPH_VERSION >= (2,0)
let module Dom = Dominator.Make_graph(struct
include G
let empty () = create ()
let add_edge g v1 v2 = add_edge g v1 v2; g
end) in
#elif OCAMLGRAPH_VERSION >= (1,8,6)
let module Dom = Dominator.Make_graph(G) in
#else
let module Dom = Dominator.Make(G) in
#endif
在我们的 dune
文件中,我们像这样使用 cppo 对其进行预处理:
(library
[...]
(preprocess (action (run %{bin:cppo} -V OCAMLGRAPH:%{read:ocamlgraph.version} %{input-file})))
(rule
(target ocamlgraph.version)
(action (with-stdout-to %{target} (run ocamlfind query -format %v ocamlgraph))))
现在我们要使用 dune build @fmt
。问题是,ocamlformat 不理解尚未预处理的文件。一种解决方法是将受影响的文件添加到 .ocamlformat-ignore
,但该文件相当大,因此不对其进行自动格式化会很遗憾。
这个问题有简单的解决方法吗?也许有一个共同的模式如何用沙丘解决这个问题?
解决方法
技术上不是答案,而是几个线索:
-
您可以将预处理过的部分移到另一个文件
dom.ml
中,并放弃此文件的格式,因为该文件会比较小。我知道不理想。 -
也许您可以看看 Dune 的 Alternative dependencies,它允许您根据给定库的存在与否在不同的模块中选择一个模块。但据我所知,你还是不能根据某个库的版本来选择,see this issue。
-
你可以混合使用 Makefile+Dune,预处理部分由 makefile 处理,格式化由 dune 处理。
-
您也可以使用一流的模块,但我想这并不令人满意,因为您希望在编译时而不是在运行时做出选择。