如何查看Dune调用OCaml工具的方式及复刻其包装模块功能?
问题1:复刻Dune「包装模块指定库接口」到Buck2
Dune里的这个功能是通过(library) stanza的(wrapped)字段实现的——你可以指定一个包装模块,让库对外只暴露这个模块的接口,内部子模块默认隐藏。比如:
(library (name my_lib) (wrapped (my_lib)) (modules my_lib_impl my_lib_aux))
这里my_lib是包装模块,对外只暴露它的接口,my_lib_impl和my_lib_aux作为内部模块不对外可见。
在Buck2里实现类似效果,可以这么做:
- 编写一个顶层包装模块(比如
My_lib.mli),在里面导出需要对外暴露的子模块和接口; - 在
ocaml_library规则中,通过public_modules参数指定仅对外暴露这个包装模块,把其他模块设为私有; - 示例Buck2规则:
ocaml_library( name = "my_lib", srcs = glob(["*.ml", "*.mli"]), public_modules = ["My_lib"], private_modules = ["My_lib_impl", "My_lib_aux"], )
这样外部依赖这个库时,只能访问My_lib模块,内部实现模块被隐藏,达到和Dune包装模块一致的效果。
问题2:查看Dune调用OCaml工具的参数
现有内置方式
Dune本身有类似buck2 what-ran的功能,直接用以下命令即可:
dune build --verbose(或缩写dune build -v):执行构建时会输出所有调用的外部命令,包括ocamlopt.opt的完整参数;dune build --display verbose:和上面效果类似,会详细展示构建过程中执行的每一步命令;- 也可以设置环境变量
DUNE_VERBOSE=1再运行构建,同样会输出详细命令日志。
源码添加打印的位置
如果内置日志不够满足需求,要修改Dune源码加Printf.printf的话,核心逻辑在这些文件:
src/dune_engine/process.ml:Dune执行外部进程的核心模块,Process.run或Process.run_exn函数是调用外部工具的入口,在这些函数执行命令前添加打印代码,就能捕获所有工具调用的参数;src/dune_rules/ocaml/compile.ml:专门处理OCaml编译逻辑的模块,里面调用ocamlopt.opt、ocamlc等工具的逻辑集中在这里,也可以在具体调用点添加打印。
比如在process.ml的run函数里,找到构建命令参数的地方,添加:
Printf.printf "Running command: %s\n" (String.concat " " (prog :: args));
这样每次调用外部工具时,都会在控制台输出完整的命令和参数。
内容的提问来源于stack exchange,提问作者Max Heiber
相关产品推荐
相关产品推荐

