我正在编写一个OCaml库,它有一些初始化代码,在程序的生命周期内只需要运行一次(并存储一些在程序生命周期内会持续存在的状态,但只能在库本身),以及一些清理代码,只有在使用库的程序退出时才需要运行。
如果它是相关的,我的库是两部分:一个低级C库的接口,以及一些更高级的东西,使它更容易编程。我可以在C中的某个地方做我需要的吗?理想情况下,我的用户不会关心如何实现,他们永远不会看到C位。
在Python中我会通过在import
上运行代码来实现这一点,但是OCaml的open
实际上并没有运行任何东西,它只是模拟了模块命名空间,然后是Python的atexit
,但我找不到Ocaml的等价物。
我考虑过的一种方法是将我的库构建为“框架”,但我认为保证这种过度设计的方法并不重要。谢谢!
更新:好的,我想。我正在使用C代码来处理退出时的清理,并且我已经对代码进行了一些处理,因此在C端有一个指向全局状态的指针
出现在我的图书馆中我现在有
let global_env = env_create ()
当主程序为open
时,此会运行......但是如何运行?
答案 0 :(得分:7)
请注意,这可以在OCaml端使用Pervasives.at_exit
和顶级语句来创建环境并安装清理代码:
let env = init ()
let cleanup () = do_clean env
let () = at_exit cleanup
let f x = f_stub env x
当加载模块时(不管你最终是否使用它)执行toplevel语句,并且按照你在链接时指定的顺序加载模块(因此,依赖于其他模块的模块保证它们的依赖关系在它们的初始化时被初始化转过来),参见manual of ocamlc中的“以.cmo结尾的参数”。这需要在尝试访问模块之前执行顶级语句。这不是打开模块的问题,open
只是一个(坏的)语法方便。
如果您希望在且仅当最终调用模块的函数时才执行init代码,请使用惰性值:
let env = lazy (init ())
let cleanup () = if Lazy.lazy_is_val env then (do_clean env) else ()
let () = at_exit cleanup
let f x = f_stub (Lazy.force env) x
顺便说一下。不要忘记用线程安全来记录产生的问题...
答案 1 :(得分:1)
正如let x = function ...
定义了从该点可用的函数x
之后,您的let global_env = ...
定义了值global_env
。如果你不这样做
需要env_create
的返回值,因为只运行它的副作用,
你也可以在最后提到env_create ()
(说实话,任何地方)
ml文件。
在这种情况下,我会做let _ = env_create ()
,但我认为这更明确。
编辑:R指出以下错误:
“要纯粹用C做,我认为_init
和_fini
是需要寻找的东西。”
正如本HOWTO中所解释的那样,它确实已被弃用,现在应该通过属性来完成。