I came across a weird error while building recently that seemed to result in a linker error (only using ocamlopt, of course). I’ve put the code here (reproduced inline).
module type Int = sig
val one : int
val (+) : int -> int -> int
end
module Make (Int : Int) = struct
(* this assertion must fail in order to make the linker command fail *)
let () = assert false
(* this assertion doesn't matter *)
let () =
let falsy () = [1] == [1] in
assert (falsy ())
(* both the list and the + are needed to get the linker command to fail *)
let two () = [ Int.(one + one) ]
end
module M = Make(struct
let one = 1
let (+) = (+)
end)
(* This programs fails with a linker error on OCaml version 4.04.2 but not 4.05.0
{[
% jbuilder build @install
ocamldep src/main.depends.ocamldep-output
ocamlc src/main.{cmi,cmo,cmt}
ocamlopt src/main.{cmx,o}
ocamlopt src/main.exe (exit 2)
(cd _build/default && ~/.opam/4.04.2/bin/ocamlopt.opt -w -40 -g -o src/main.exe src/main.cmx)
src/main.o: In function `camlMain__entry':
~/.../_build/default/src/main.ml:24: undefined reference to `camlMain__two_1207'
collect2: error: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking
]}
*)
let _ = M.two ()
(the bug manifests when building with, e.g., ocamlbuild, so jbuilder isn’t the culprit AFAICT)
Basically, under certain circumstances, a constant false assertion in the body of a functor seems to trigger “undefined reference” linker errors for values defined after that assertion.
Some weird things about this bug: I think the definition after the assertion needs to be sufficiently complex, or else it probably just gets inlined. Also, simply raising an exception without using assert
doesn’t trigger the linker error.
It doesn’t really matter so much, since this is fixed in 4.05.0, but I read through the release notes and didn’t see anything obviously related to this. Thought somebody here might be more familiar with either what fixed it in 4.05.0 or what was causing this problem in the first place.