Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/changes/changed/15423.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Align dune's C compiler vendor detection with the OCaml compiler's own
identifiers (`msvc`, `icc`, `mingw`, `clang`, `gcc`, `xlc`, `sunc`), so more C
compilers are recognized without emitting a spurious warning. (#15423,
fixes #14870, @chizy7)
41 changes: 28 additions & 13 deletions src/dune_rules/cc_flags.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,61 @@ open Memo.O

type cc_vendor =
| Gcc
| Msvc
| Clang
| Msvc
| Mingw
| Intel
| Xlc
| Sun
| Other of string

type phase =
| Compile of Ocaml.Version.t
| Link

let base_cxx_compile_flags version = function
| Gcc | Clang ->
| Gcc | Clang | Mingw | Intel ->
"-x"
:: "c++"
:: (if Ocaml.Version.add_std_cxx_flag version then [ "-std=gnu++11" ] else [])
| Msvc -> [ "/TP" ]
| Other _ -> []
| Xlc | Sun | Other _ -> []
;;

let base_cxx_link_flags = function
| Gcc -> [ "-lstdc++"; "-shared-libgcc" ]
| Gcc | Mingw | Intel -> [ "-lstdc++"; "-shared-libgcc" ]
| Clang -> [ "-lc++" ]
| Msvc -> []
| Other _ -> []
| Msvc | Xlc | Sun | Other _ -> []
;;

let fdiagnostics_color = function
| Gcc | Clang -> [ "-fdiagnostics-color=always" ]
| Gcc | Clang | Mingw | Intel -> [ "-fdiagnostics-color=always" ]
| _ -> []
;;

let warnings = function
| Gcc | Clang -> [ "-Wall" ]
| Gcc | Clang | Mingw | Intel -> [ "-Wall" ]
| Msvc -> [ "-W2" ]
| _ -> []
;;

let header_file_content =
{|#if defined( _MSC_VER )
{|#if defined(_MSC_VER)
msvc
#elif defined( __clang__ )
#elif defined(__INTEL_COMPILER)
icc
#elif defined(__MINGW32__)
mingw
#elif defined(__clang_major__) && defined(__clang_minor__)
clang
#elif defined( __GNUC__ )
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
gcc
#elif defined(__xlc__) && defined(__xlC__)
xlc
#elif defined(__SUNPRO_C)
sunc
#else
other
unknown
#endif
|}
;;
Expand Down Expand Up @@ -107,9 +118,13 @@ end

let parse_cc_vendor cc_vendor =
match String.trim cc_vendor with
| "msvc" -> Msvc
| "icc" -> Intel
| "mingw" -> Mingw
| "clang" -> Clang
| "gcc" -> Gcc
| "msvc" -> Msvc
| "xlc" -> Xlc
| "sunc" -> Sun
| s -> Other s
;;

Expand Down
21 changes: 19 additions & 2 deletions src/dune_rules/cc_flags.mli
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,37 @@ type phase =
| Compile of Ocaml.Version.t
| Link

(** The detected compiler *)
(** The detected compiler. These identifiers are aligned with the OCaml
compiler's own [OCAML_CC_VENDOR] detection macro. *)
type cc_vendor =
| Gcc
| Msvc
| Clang
| Msvc
| Mingw
| Intel
| Xlc
| Sun
| Other of string

(** [cc_vendor ctx] returns the C/C++ compiler vendor. *)
val cc_vendor : Build_context.t -> cc_vendor Action_builder.t

(** [parse_cc_vendor s] maps the vendor word emitted by the detection probe to a
{!cc_vendor}. Exposed for testing. *)
val parse_cc_vendor : string -> cc_vendor

(** [get_flags for_:phase ctx] returns the necessary flags to turn this compiler
into a c++ compiler for some of the most common compilers *)
val get_flags : for_:phase -> Build_context.t -> string list Action_builder.t

(** [base_cxx_compile_flags version cc] returns the flags that turn the C
compiler into a C++ compiler at compile time. Exposed for testing. *)
val base_cxx_compile_flags : Ocaml.Version.t -> cc_vendor -> string list

(** [base_cxx_link_flags cc] returns the flags needed to link C++ stubs. Exposed
for testing. *)
val base_cxx_link_flags : cc_vendor -> string list

(** [fdiagnostics_color cc] returns the flags activating color diagnostics for
the C/C++ compiler, if supported. *)
val fdiagnostics_color : cc_vendor -> string list
Expand Down
1 change: 1 addition & 0 deletions src/dune_rules/dune_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ module For_tests = struct
module Action_unexpanded = Action_unexpanded
module Cram_exec = Cram_exec
module Which = Which
module Cc_flags = Cc_flags
end

module Rocq = struct
Expand Down
52 changes: 52 additions & 0 deletions test/expect-tests/cc_flags_tests.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
open Dune_tests_common
open Stdune
module Cc_flags = Dune_rules.For_tests.Cc_flags

let () = init ()

(* Use a modern OCaml version so the C++ [-std] flag is included. *)
let version = Ocaml.Version.make (5, 0, 0)

let show = function
| [] -> "(none)"
| flags -> String.concat ~sep:" " flags
;;

let flags_of word =
let vendor = Cc_flags.parse_cc_vendor word in
Printf.sprintf
"compile=[%s] link=[%s] warnings=[%s] color=[%s]"
(show (Cc_flags.base_cxx_compile_flags version vendor))
(show (Cc_flags.base_cxx_link_flags vendor))
(show (Cc_flags.warnings vendor))
(show (Cc_flags.fdiagnostics_color vendor))
;;

let%expect_test "vendor identifiers route to the right flag families" =
List.iter
[ "msvc"; "icc"; "mingw"; "clang"; "gcc"; "xlc"; "sunc"; "unknown" ]
~f:(fun word -> Printf.printf "%-8s %s\n" word (flags_of word));
[%expect
{|
msvc compile=[/TP] link=[(none)] warnings=[-W2] color=[(none)]
icc compile=[-x c++ -std=gnu++11] link=[-lstdc++ -shared-libgcc] warnings=[-Wall] color=[-fdiagnostics-color=always]
mingw compile=[-x c++ -std=gnu++11] link=[-lstdc++ -shared-libgcc] warnings=[-Wall] color=[-fdiagnostics-color=always]
clang compile=[-x c++ -std=gnu++11] link=[-lc++] warnings=[-Wall] color=[-fdiagnostics-color=always]
gcc compile=[-x c++ -std=gnu++11] link=[-lstdc++ -shared-libgcc] warnings=[-Wall] color=[-fdiagnostics-color=always]
xlc compile=[(none)] link=[(none)] warnings=[(none)] color=[(none)]
sunc compile=[(none)] link=[(none)] warnings=[(none)] color=[(none)]
unknown compile=[(none)] link=[(none)] warnings=[(none)] color=[(none)]
|}]
;;

let%expect_test "unrecognized words and surrounding whitespace are handled" =
(* Leading/trailing whitespace from the probe output is trimmed. *)
Printf.printf "whitespace: %s\n" (flags_of " gcc\n");
(* An unknown word falls through to the neutral family (and would warn). *)
Printf.printf "unknown: %s\n" (flags_of "borland");
[%expect
{|
whitespace: compile=[-x c++ -std=gnu++11] link=[-lstdc++ -shared-libgcc] warnings=[-Wall] color=[-fdiagnostics-color=always]
unknown: compile=[(none)] link=[(none)] warnings=[(none)] color=[(none)]
|}]
;;
1 change: 1 addition & 0 deletions test/expect-tests/dune
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
dune_rules
fiber
dune_lang
ocaml
memo
unix
threads.posix
Expand Down
Loading