diff --git a/doc/changes/changed/15423.md b/doc/changes/changed/15423.md new file mode 100644 index 00000000000..f09fa711fd1 --- /dev/null +++ b/doc/changes/changed/15423.md @@ -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) diff --git a/src/dune_rules/cc_flags.ml b/src/dune_rules/cc_flags.ml index 093566d4be5..1334887d8bb 100644 --- a/src/dune_rules/cc_flags.ml +++ b/src/dune_rules/cc_flags.ml @@ -3,8 +3,12 @@ open Memo.O type cc_vendor = | Gcc - | Msvc | Clang + | Msvc + | Mingw + | Intel + | Xlc + | Sun | Other of string type phase = @@ -12,41 +16,48 @@ type phase = | 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 |} ;; @@ -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 ;; diff --git a/src/dune_rules/cc_flags.mli b/src/dune_rules/cc_flags.mli index 3e4438933ff..8a493c6ac28 100644 --- a/src/dune_rules/cc_flags.mli +++ b/src/dune_rules/cc_flags.mli @@ -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 diff --git a/src/dune_rules/dune_rules.ml b/src/dune_rules/dune_rules.ml index 1fbfc936a0a..a065a29f12e 100644 --- a/src/dune_rules/dune_rules.ml +++ b/src/dune_rules/dune_rules.ml @@ -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 diff --git a/test/expect-tests/cc_flags_tests.ml b/test/expect-tests/cc_flags_tests.ml new file mode 100644 index 00000000000..5582132ceb9 --- /dev/null +++ b/test/expect-tests/cc_flags_tests.ml @@ -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)] + |}] +;; diff --git a/test/expect-tests/dune b/test/expect-tests/dune index 2c206ebe9bb..6259c9d818d 100644 --- a/test/expect-tests/dune +++ b/test/expect-tests/dune @@ -12,6 +12,7 @@ dune_rules fiber dune_lang + ocaml memo unix threads.posix