# Module linking in OCaml

**URL:** <https://discuss.ocaml.org/t/module-linking-in-ocaml/8362>\
**Category:** Learning\
**Tags:** ocaml\
**Created:** [August 26, 2021, 6:38am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362 "2021-08-26T06:38:07Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![zhtprog](https://avatars.discourse-cdn.com/v4/letter/z/58f4c7/32.png) [@zhtprog](https://discuss.ocaml.org/u/zhtprog)\
**Post date:** [August 26, 2021, 6:38am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/1 "2021-08-26T06:38:07Z")

</div>

I noticed that if a module exists solely for side effect such that it does not have a top level value defined, then it does not always get executed (native code from ocamlopt). Not even when it is forcefully opened in another module (with `[@warning "-33"] `). My guess is code generation simply skips it. When I stripped down the code to the following:

```auto
file A:

let a = ref ""

file B:

open A
;;
a := "assigned or not?"

file C:

let [@warning "-33"] () = let open B in ()
;;
print_endline !A.a

```

It actually works as expected (`B` did load). But in a much larger codebase I am working on this did not work. What worked for me is to have a value in `B`:

```auto
file B:

let a = A.a
;;
a := "assigned or not?"

file C:

print_endline !B.a

```

Is this a bug or a feature? I am on OCaml 4.10.2. Both the toy model above and my project were built with `dune`.

---

<div class="post-metadata">

**Author:** ![zhtprog](https://avatars.discourse-cdn.com/v4/letter/z/58f4c7/32.png) [@zhtprog](https://discuss.ocaml.org/u/zhtprog)\
**Post date:** [August 26, 2021, 7:30am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/2 "2021-08-26T07:30:39Z")

</div>

Just realized more likely than not that this may be `dune` related. I am on version 2.9.0. Maybe it is not calculating the dependency correctly sometimes. What I don’t know is what the canonical semantics says about this (if there is a canonical expected behavior here). Or this is undefined behavior?

Another observation is for the particular module I am having trouble with my `lsp-server` seems to have trouble with getting anything through as well. So another oddity. This is [the file](https://github.com/htzh/holnat/blob/master/hol/database.ml) if anyone is curious about it.

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [August 26, 2021, 7:37am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/3 "2021-08-26T07:37:21Z")

</div>

The order of the execution of toplevel modules depends on the linking order of modules in the final executable. Creating a fictitious dependency with an `open` is only an indirect way to enforce an order in the list of linked modules. The issue might be related to dependency computation. Which module is not executed in time in your linked example?

---

<div class="post-metadata">

**Author:** ![vlaviron](https://avatars.discourse-cdn.com/v4/letter/v/ec9cab/32.png) [@vlaviron](https://discuss.ocaml.org/u/vlaviron)\
**Post date:** [August 26, 2021, 7:55am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/4 "2021-08-26T07:55:35Z")

</div>

When you link with a library, then only the modules from the library that are actually used by the rest of the program get included in the final executable.  
So if a module has an empty signature, by definition no other module can actually use it (`open` doesn’t count as an use as it only creates a dependency on the interface, not on the implementation).  
The normal way to deal with it is to use the `-linkall` flag. You can either pass it when compiling the file that has side-effects, or when building the library (in which case it will apply to all units in the library).  
I don’t know how to do the former with dune, but the latter can be done with `(library_flags -linkall)`.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [August 26, 2021, 7:56am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/5 "2021-08-26T07:56:39Z")

</div>

> [@zhtprog](#):
>
> Just realized more likely than not that this may be `dune` related.

Note that if a module is not listed as a dependency by `ocamldep` of the main file of the executable it won’t get linked by `dune`. You can add a dependency simply by doing `module B = B` at the top of the main file of the executable.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [August 26, 2021, 8:06am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/6 "2021-08-26T08:06:52Z")

</div>

> [@nojb](#):
>
> You can add a dependency simply by doing `module B = B` at the top of the main file of the executable.

Since `dune` use `-no-alias-deps` by default, a module alias doesn’t count as a dependency.

Overall, I personally often find it simpler to have a `register ()` function that either evaluates the relevant side effect, or manifests the dependencies on the effectful module.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [August 26, 2021, 8:10am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/7 "2021-08-26T08:10:27Z")

</div>

> [@octachron](#):
>
> Since `dune` use `-no-alias-deps` by default, a module alias doesn’t count as a dependency.

`-no-alias-deps` is used when compiling but as far as what to link `dune` uses the dependencies returned by `ocamldep` and `ocamldep` _will_ return a dependency for module aliases.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [August 26, 2021, 8:22am UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/8 "2021-08-26T08:22:21Z")

</div>

Ah yes, `dune` is not running `ocamldep` with `-as-map` thus `ocamldep` does approximate the module alias as a false dependency on the aliased module. Anyway, relying on this approximation seems quite brittle.

---

<div class="post-metadata">

**Author:** ![zhtprog](https://avatars.discourse-cdn.com/v4/letter/z/58f4c7/32.png) [@zhtprog](https://discuss.ocaml.org/u/zhtprog)\
**Post date:** [August 26, 2021, 3:21pm UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/9 "2021-08-26T15:21:34Z")

</div>

> [@octachron](#):
>
> The order of the execution of toplevel modules depends on the linking order of modules in the final executable. Creating a fictitious dependency with an `open` is only an indirect way to enforce an order in the list of linked modules. The issue might be related to dependency computation. Which module is not executed in time in your linked example?

The file I linked to `database.ml`([holnat/hol/database.ml at master · htzh/holnat · GitHub](https://github.com/htzh/holnat/blob/master/hol/database.ml)) is the one I had trouble with. It works now with the workaround of forcing a top level value.

However I can’t reproduce this with the toy model summarizing the same issue. That is the module `B` did get linked in both examples shown above, so there is some inconsistency I don’t yet understand. After some fiddling I believe it is because the toy model files are all in the same directory (library), while in my codebase module `A` and `B` are in the same library while `C` is from outside. So after the modification as below:

```auto
dune for lib:
(library
 (name lib)
)

dune for module C:
(executable
 (name c)
 (libraries lib)
)

c.ml:
let [@warning "-33"] () = let open Lib.B in ()
;;
print_endline !Lib.A.a

```

Now the executable `c.exe` skips module `B` and prints empty string.

---

<div class="post-metadata">

**Author:** ![zhtprog](https://avatars.discourse-cdn.com/v4/letter/z/58f4c7/32.png) [@zhtprog](https://discuss.ocaml.org/u/zhtprog)\
**Post date:** [August 26, 2021, 3:25pm UTC](https://discuss.ocaml.org/t/module-linking-in-ocaml/8362/10 "2021-08-26T15:25:33Z")

</div>

> [@vlaviron](#):
>
> When you link with a library, then only the modules from the library that are actually used by the rest of the program get included in the final executable.  
> So if a module has an empty signature, by definition no other module can actually use it (`open` doesn’t count as an use as it only creates a dependency on the interface, not on the implementation).  
> The normal way to deal with it is to use the `-linkall` flag. You can either pass it when compiling the file that has side-effects, or when building the library (in which case it will apply to all units in the library).  
> I don’t know how to do the former with dune, but the latter can be done with `(library_flags -linkall)`.

Thanks I believe my problem was with linking with a library.
