Running code only once in the OCaml library

I am writing an OCaml library that has some initialization code that needs to be run only once during the life of the program using the library (and store some state that will be maintained throughout the life of the program, but will be used only inside the library itself) and some cleanup code that should only run as a program that uses the exit from the library.

If relevant, my library consists of two parts: an interface with a low-level C library and some higher-level materials to simplify programming. Can I do what I need somewhere in C? Ideally, my users would not care how it was implemented, they never saw the C bit.

In Python, I would do this by running the import code, but OCaml open doesn't actually run anything, it just lands the module namespace and then Python atexit , but I can't find the Ocaml equivalent.

One approach that I have considered is structuring my library as a “framework,” but I don't think it's important enough to justify such a redesigned approach. Thanks!

UPDATE : OK it turned out - I think. I use C code to handle cleanup on exit, and I have worked a bit with the code, so there is a pointer to the global state on the C side

It looks like there is now in my library

 let global_env = env_create () 

And when it is open 'd main program, it starts ... But how?

+4
source share
2 answers

Please note that this can be done on the OCaml side with Pervasives.at_exit and top-level instructions for creating the environment and setting the cleanup code.

 let env = init () let cleanup () = do_clean env let () = at_exit cleanup let fx = f_stub env x 

Toplevel statements are executed when the module is loaded (regardless of whether you use it ultimately or not), and the modules are loaded in the order you specified them during the link (while the modules, depending on others, guarantee that their dependencies initialized when their turn), see "Arguments ending in .cmo" in the ocamlc manual . This implies that toplevel statements will be executed before you try to access the module. It's not a matter of opening a module, open is just (bad) syntactic convenience.

If you want the initialization code to be executed if and only if the function of the called module is ultimately called, use the lazy value:

 let env = lazy (init ()) let cleanup () = if Lazy.lazy_is_val env then (do_clean env) else () let () = at_exit cleanup let fx = f_stub (Lazy.force env) x 

Btw. Remember to document thread safety issues ...

+7
source

Just as let x = function ... defines the function x available from this point and then let global_env = ... defines the value of global_env . If you don't need to return the env_create value because you only run it for its side effects, you could just mention env_create () at the end (honestly, anywhere) of the ml file. In this case, I would do let _ = env_create () , although I think it is more explicit.

EDIT : R pointed out that the following is false: "To do this purely in C, I think _init and _fini are what you need to look for." As explained in this HOWTO , this is really deprecated and should now be done using attributes.

+1
source

All Articles