Expected Behavior
dune to correctly rebuild artifacts with different ocaml versions (more general : when anything affecting compilation changes in outside environment, not sure how feasible)
Actual Behavior
dune doesn't rebuild object files when compiler version changes provided that all paths remain the same (which is achievable with local opam switch or with the same named switch)
Reproduction
# make sure cache is enabled
$ cat ~/.config/dune/config
(lang dune 2.0)
(cache enabled)
(cache-trim-period 1h)
(cache-trim-size 20GB)
$ rm -rf _build/ _opam ~/.cache/dune
$ opam sw create . 4.09.0
$ dune build
$ ls -hlA _build/default/stubs.o
-r--r--r-- 2 user user 5.1K May 12 15:28 _build/default/stubs.o
$ mv _opam _opam_09
# NB keeping cache and build dir intact
$ opam sw create . 4.11.2
$ dune build
ocamlopt test.exe (exit 2)
(cd _build/default && /home/user/dune_cache/_opam/bin/ocamlopt.opt -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -o test.exe stubs.cmxa -I . .test.eobjs/native/dune__exe__Test.cmx)
/usr/bin/ld: ./libstubs_stubs.a(stubs.o): in function `ml_test':
/home/user/dune_cache/_build/default/stubs.c:6: undefined reference to `caml_local_roots'
/usr/bin/ld: /home/user/dune_cache/_build/default/stubs.c:6: undefined reference to `caml_local_roots'
/usr/bin/ld: /home/user/dune_cache/_build/default/stubs.c:6: undefined reference to `caml_local_roots'
/usr/bin/ld: /home/user/dune_cache/_build/default/stubs.c:7: undefined reference to `caml_local_roots'
/usr/bin/ld: /home/user/dune_cache/_build/default/stubs.c:7: undefined reference to `caml_local_roots'
/usr/bin/ld: ./libstubs_stubs.a(stubs.o):/home/user/dune_cache/_build/default/stubs.c:9: more undefined references to `caml_local_roots' follow
collect2: error: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking (exit code 1)
$ ls -hlA _build/default/stubs.o
-r--r--r-- 2 user user 5.1K May 12 15:28 _build/default/stubs.o # NB stubs.o is same size as with 4.09.0
$ rm -rf _build # cleaning build dir
$ dune build
# same error as above
[..]
/home/user/dune_cache/_build/default/stubs.c:6: undefined reference to `caml_local_roots'
[..]
$ ls -hlA _build/default/stubs.o
-r--r--r-- 2 user user 5.1K May 12 15:28 _build/default/stubs.o # still same
$ rm -rf _build/ ~/.cache/dune/ # cleaning build dir and cache dir
$ dune build # build successful
$ ls -hlA _build/default/stubs.o
-r--r--r-- 2 user user 12K May 12 15:29 _build/default/stubs.o # stubs.o changed
My interpretation:
dune caches stuff by path. In this case installation changes from 4.09 to 4.11 with paths remaining unchanged. This makes dune think that stubs.o file doesn't need to be rebuilt and it fails (because e.g. 4.11.2 doesn't have caml_local_roots symbol, it is only present in 4.09.0, among other possible reasons). I understand dune uses hash of binary running the command as a key in hash so this issue doesn't affect ocaml compiler invocations, only affects C stubs (gcc indeed remains the same), because from the stubs.o compilation pov only include headers change, which are not tracked by dune.
NB this issue affects both dune cache and regular build
re importance: in our usecase it makes dune cache unusable when switching between compiler versions (or having branches with different versions of ocaml on the same CI), the only workaround we have in such situation is dune clean and remove dune cache before every build (which obv defeats the purpose of cache)
Specifications
- Version of
dune (output of dune --version): 2.8.5
- Version of
ocaml (output of ocamlc --version): 4.09.0 and 4.11.2
- Operating system (distribution and version): debian 10.8
Additional information
dune
(library
(name stubs)
(modules ())
(foreign_stubs
(language c)
(names stubs)
(flags -g -fPIC -O0 -Wextra -Wstrict-overflow=5 -Wno-implicit-fallthrough) # -O0 is important otherwise in this synthetic example caml_local_roots usage gets optimized out
)
)
(executable (name test) (libraries stubs))
dune-project
(lang dune 2.8)
(use_standard_c_and_cxx_flags true) # this is important for this reproduce case because otherwise a set of C compiler invocation flags changes slightly between chosen ocaml versions
stubs.c
#include <caml/memory.h>
#include <caml/mlvalues.h>
value ml_test(value v)
{
CAMLparam1(v);
CAMLlocal1(res);
res = v;
CAMLreturn(res);
}
test.ml
external test : unit -> unit = "ml_test"
let () = test ()
Expected Behavior
dune to correctly rebuild artifacts with different ocaml versions (more general : when anything affecting compilation changes in outside environment, not sure how feasible)
Actual Behavior
dune doesn't rebuild object files when compiler version changes provided that all paths remain the same (which is achievable with local opam switch or with the same named switch)
Reproduction
My interpretation:
dune caches stuff by path. In this case installation changes from 4.09 to 4.11 with paths remaining unchanged. This makes dune think that stubs.o file doesn't need to be rebuilt and it fails (because e.g. 4.11.2 doesn't have caml_local_roots symbol, it is only present in 4.09.0, among other possible reasons). I understand dune uses hash of binary running the command as a key in hash so this issue doesn't affect ocaml compiler invocations, only affects C stubs (gcc indeed remains the same), because from the stubs.o compilation pov only include headers change, which are not tracked by dune.
NB this issue affects both dune cache and regular build
re importance: in our usecase it makes dune cache unusable when switching between compiler versions (or having branches with different versions of ocaml on the same CI), the only workaround we have in such situation is dune clean and remove dune cache before every build (which obv defeats the purpose of cache)
Specifications
dune(output ofdune --version): 2.8.5ocaml(output ofocamlc --version): 4.09.0 and 4.11.2Additional information
dune
dune-project
stubs.c
test.ml