OCaml bytecode - how are interface CRCs calculated when there is no signature file?

I am trying to understand how CRCs for interfaces are generated by OCaml (bytecode, version 4.13.2) when there is no corresponding mli file.
I have:

let t () = print_endline "hello world"
let t2 () = 1

With ocamlc -c a.ml && ocamlobjinfo a.cmo this gives a CRC of A of ec612c3e86eaca57a236b43aa1d6cdb5. If I change a.ml to

let t () = print_endline "hello world!"
let t2 () = 1

The CRC is instead 798a526927928bf5d325066505f0fada. Is this CRC not supposed to be based on the interface of the module A and not the implementation?

The following seems to indicate so: If I make a.mli with

val t : unit -> unit
val t2 : unit -> int

Then both versions of a.ml give the same CRC (a24d0e4920a01947b196e8ce82cc79fd).

The reason I am curious about this is that it’s preventing us from reloading modules as cmos in the toplevel if they have no mli file: Almost any change to the ml file causes CRC mismatches.

The cmi files contain locations by default, so anything that can change the locations associated to the exported items will change the CRC of the cmi.

You can use the -no-keep-locs flag to make the CRCs independent of the locations.

Thank you!

Can you explain why locations seems to not be used if there is an mli file? You say ‘locations by default’ - is this because there are several schemes for what to use in a cmi file?

“By default” means you can turn them off with -no-keep-locs (in practice, when the flag is used all locations are replaced with a dummy location).
If there is an mli file, the locations of the interface are the ones of the mli file. You can check that adding whitespace in the mli file changes the CRC, unless you use -no-keep-locs.
If you’re curious, you can check that in the case without a mli file, only the locations for exported items are relevant by adding whitespace, comments, or code which doesn’t bind anything (such as let _ = ...) at the end of the file, and these additions will likely not change the CRC.

Thank you again. I now understand what location means in this context - I thought it was location in the compiled code and not in the source file. This makes things clear.