Dune builds C stubs with `bytecode_cflags` and never `native_cflags`
Expected Behavior
Among the default flags for building C stubs, Dune should use OCaml’s bytecode_cflags for stubs destined to bytecode and native_cflags for stubs destined to native executables.
Actual Behavior
Dune always uses bytecode_cflags. This can cause crashes when using ThreadSanitizer ^1—and probably has ^2 ^3.
Reproduction
On a switch with ThreadSanitizer enabled (opam switch create test-switch --packages=ocaml-variants.5.3.0+options,ocaml-option-tsan), bytecode and native cflags differ, and it is easy to see that Dune only uses bytecode cflags:
$ ocamlc -config
version: 5.3.0
standard_library_default: /home/olivier/.opam/5.3.0+tsan/lib/ocaml
standard_library: /home/olivier/.opam/5.3.0+tsan/lib/ocaml
ccomp_type: cc
c_compiler: gcc
bytecode_cflags: -O2 -fno-strict-aliasing -fwrapv -fPIC -pthread
ocamlc_cflags: -O2 -fno-strict-aliasing -fwrapv -fPIC -pthread
bytecode_cppflags: -D_FILE_OFFSET_BITS=64
ocamlc_cppflags: -D_FILE_OFFSET_BITS=64
native_cflags: -O2 -fno-strict-aliasing -fwrapv -fsanitize=thread -Wno-tsan --param=tsan-distinguish-volatile=1 -pthread
ocamlopt_cflags: -O2 -fno-strict-aliasing -fwrapv -fsanitize=thread -Wno-tsan --param=tsan-distinguish-volatile=1 -pthread
...
$ cat dune
(library
(name test)
(foreign_stubs
(language c)
(flags (:standard))
(names stubs))
)
$ dune build --verbose
...
Running[6]: (cd _build/default/lib && /nix/store/f0m6caffiykyvsjim9376a3hx2yj2ghj-gcc-wrapper-14.2.1.20250322/bin/gcc -O2 -fno-strict-aliasing -fwrapv -fPIC -pthread -D_FILE_OFFSET_BITS=64 -Wall -fdiagnostics-color=always -g -I /home/olivier/.opam/5.3.0+tsan/lib/ocaml -o stubs.o -c stubs.c)
...
Specifications
- Version of
dune(output ofdune --version): 3.19.0 - Version of
ocaml(output ofocamlc --version): 5.3.0 - Operating system (distribution and version): NixOS 25.05
As a temporary workaround for TSan users, is there a way to alter the CFLAGS used by Dune using an environment variable, or something similar?
Since we don't support foreign stubs with bytecode, we probably should be using OCaml_config.ocamlopt_flags rather than OCaml_config.ocamlc_flags in src/dune_rules/foreign_rules.ml. cc @rgrinberg WDYT?
let default_context_flags (ctx : Build_context.t) ocaml_config ~project =
let cflags = Ocaml_config.ocamlc_cflags ocaml_config in
let c, cxx =
let cxxflags =
Since we don't support foreign stubs with bytecode
What do you mean by that? I think C stubs work just fine in bytecode; they are built into a shared library.
@nojb I may be mistaken. That was the impression I got from trying to reproduce https://github.com/ocaml/dune/issues/108. I don't know much about bytecode executables however.
That was the impression I got from trying to reproduce #108.
There are recurring issues that users report regarding bytecode + C stubs which are due to the fact that one needs to tell the OCaml runtime where to find the shared library containing the stubs (typically by setting CAML_LD_LIBRARY_PATH) when runningthe bytecode executable, but that is a different question. Otherwise, C stubs in bytecode work just fine.
On the other hand, and more relevant to this issue, I believe to do what is being asked for here we would need to build C stubs twice (once for bytecode, once for native-code). There is already support for doing so (cf #5649), but it is opt-in; by default the same C stubs are shared between bytecode and native-code.
Ah, that’s good to know; then it shouldn’t be too much work to always build them separately, and use ocamlopt_cflags for the native version.