diff --git a/src/kernel_services/ast_queries/file.ml b/src/kernel_services/ast_queries/file.ml
index 0d0b2949cf04b95003c0fd38891e45d4e700d069..30ebd9bdf6278c11feb8177967ff91a742801a0a 100644
--- a/src/kernel_services/ast_queries/file.ml
+++ b/src/kernel_services/ast_queries/file.ml
@@ -119,7 +119,7 @@ let from_filename ?cpp f =
         | None -> get_preprocessor_command ()
         | Some cpp -> cpp, cpp_opt_kind ()
       in
-      (if flags = "" then cpp else cpp ^ " " ^ flags), gnu
+      (if flags = [] then cpp else cpp ^ " " ^ String.concat " " flags), gnu
   in
   if Filename.check_suffix f ".i" then begin
     NoCPP f
diff --git a/src/kernel_services/ast_queries/json_compilation_database.ko.ml b/src/kernel_services/ast_queries/json_compilation_database.ko.ml
index 414499c6ddacb0ff22e34a9c94ccf0f4aff3d762..646e41872a63bee993e9bb52fe70bfed2e46124c 100644
--- a/src/kernel_services/ast_queries/json_compilation_database.ko.ml
+++ b/src/kernel_services/ast_queries/json_compilation_database.ko.ml
@@ -31,4 +31,4 @@ let get_flags _ =
       "Attempt to parse json compilation database %s \
        with a Frama-C compiled without Yojson support." db
   end;
-  ""
+  []
diff --git a/src/kernel_services/ast_queries/json_compilation_database.mli b/src/kernel_services/ast_queries/json_compilation_database.mli
index f343d4a1f4cc8aed52019ce213ee41ca5b8e0b40..dcb18cb059b83c2c32da10c78f34e6081fc3018f 100644
--- a/src/kernel_services/ast_queries/json_compilation_database.mli
+++ b/src/kernel_services/ast_queries/json_compilation_database.mli
@@ -23,4 +23,4 @@
 (** [get_flags f] returns the preprocessing flags associated to file [f]
     in the JSON compilation database (when enabled), or the empty string
     otherwise. If not empty, the flags always start with a space. *)
-val get_flags : Datatype.Filepath.t -> string
+val get_flags : Datatype.Filepath.t -> string list
diff --git a/src/kernel_services/ast_queries/json_compilation_database.ok.ml b/src/kernel_services/ast_queries/json_compilation_database.ok.ml
index 6ae9e02ee25d6cdd5f5b409eebf0acedb0d45063..6409629514e1ef8bc06823880b27aeb49ac5e2a2 100644
--- a/src/kernel_services/ast_queries/json_compilation_database.ok.ml
+++ b/src/kernel_services/ast_queries/json_compilation_database.ok.ml
@@ -20,10 +20,12 @@
 (*                                                                        *)
 (**************************************************************************)
 
+module StringList = Datatype.List(Datatype.String)
+
 module Flags =
   State_builder.Hashtbl
     (Datatype.Filepath.Hashtbl)
-    (Datatype.String)
+    (StringList)
     (struct
       let name ="JsonCompilationDatabase.Flags"
       let dependencies = [Kernel.JsonCompilationDatabase.self]
@@ -205,18 +207,28 @@ let parse_entry ?(cwd=Sys.getcwd()) (r : Yojson.Basic.json) =
   (* Note: the same file may be compiled several times, under different
      (and possibly incompatible) configurations, leading to multiple
      occurrences in the list. Since we cannot infer which of them is the
-     "right" one, we pick the first and warn the user if there are
-     others. *)
-  let flags = String.concat " " (List.rev res) in
+     "right" one, we replace them with the latest ones found, warning the
+     user if previous flags were different. *)
+  let flags = List.rev res in
   try
     let previous_flags = Flags.find path in
     if previous_flags <> flags then
+      let removed_flags = List.filter (fun e -> not (List.mem e previous_flags)) flags in
+      let removed_str =
+        if removed_flags = [] then "" else
+          Format.asprintf "@ Old flags no longer present: %a"
+            (Pretty_utils.pp_list ~sep:" " Format.pp_print_string) removed_flags
+      in
+      let added_flags = List.filter (fun e -> not (List.mem e flags)) previous_flags in
+      let added_str =
+        if added_flags = [] then "" else
+          Format.asprintf "@ New flags not previously present: %a"
+            (Pretty_utils.pp_list ~sep:" " Format.pp_print_string) added_flags
+      in
       Kernel.warning ~wkey:Kernel.wkey_jcdb
-        "@[<v>found duplicate flags for '%a'.\
-         @ Previous flags: %s\
-         @      New flags: %s@]" Datatype.Filepath.pretty path
-        previous_flags flags;
-    Flags.replace path flags
+        "@[<v>found duplicate flags for '%a', replacing old flags.%s%s@]"
+        Datatype.Filepath.pretty path removed_str added_str;
+      Flags.replace path flags
   with
   | Not_found ->
     Flags.add path flags
@@ -250,11 +262,11 @@ let get_flags f =
     try
       let flags = Flags.find f in
       Kernel.feedback ~dkey:Kernel.dkey_compilation_db
-        "flags found for '%a': %s"  Datatype.Filepath.pretty f flags;
+        "flags found for '%a': %a"  Datatype.Filepath.pretty f StringList.pretty flags;
       flags
     with Not_found ->
       Kernel.feedback ~dkey:Kernel.dkey_compilation_db
         "no flags found for '%a'"  Datatype.Filepath.pretty f;
-      ""
+      []
   end
-  else ""
+  else []
diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml
index 4edd4171dfd05aa954861ef917289330a993592b..7d55bd3c1554bb170fd9a12d57f23a406d595a88 100644
--- a/src/kernel_services/plugin_entry_points/kernel.ml
+++ b/src/kernel_services/plugin_entry_points/kernel.ml
@@ -153,6 +153,7 @@ let () = set_warn_status wkey_cert_exp_10 Log.Winactive
 let wkey_check_volatile = register_warn_category "check:volatile"
 
 let wkey_jcdb = register_warn_category "pp:compilation-db"
+let () = set_warn_status wkey_jcdb Log.Wonce
 
 let wkey_implicit_function_declaration = register_warn_category
     "typing:implicit-function-declaration"
diff --git a/tests/jcdb/oracle/jcdb.0.res.oracle b/tests/jcdb/oracle/jcdb.0.res.oracle
index fc6e678e7541aa6336f91a8044e67d6ac8a685c6..1a80090d55b0c602628524a47fa26ba90e0cf493 100644
--- a/tests/jcdb/oracle/jcdb.0.res.oracle
+++ b/tests/jcdb/oracle/jcdb.0.res.oracle
@@ -1,7 +1,8 @@
 [kernel:pp:compilation-db] Warning: 
-  found duplicate flags for 'tests/jcdb/jcdb.c'.
-  Previous flags: -DDUPLICATE_FLAGS_THAT_WILL_BE_OVERWRITTEN
-       New flags: -D'MSG="a \" \"b"' -D'SINGLE_DOUBLE(a)="a \"with spaces and	tab "' -DSOMEDEF="With spaces, quotes and \-es." -D"DOUBLE_SINGLE(a)=a \"macro with spaces and non-escaped \\'\"" -DEMPTY='' -DEMPTY2= -DTEST=42 -D'MACRO_FOR_INCR(s)=s+1' -DTOUNDEF -UTOUNDEF
+  found duplicate flags for 'tests/jcdb/jcdb.c', replacing old flags.
+  Old flags no longer present: -D'MSG="a \" \"b"' -D'SINGLE_DOUBLE(a)="a \"with spaces and	tab "' -DSOMEDEF="With spaces, quotes and \-es." -D"DOUBLE_SINGLE(a)=a \"macro with spaces and non-escaped \\'\"" -DEMPTY='' -DEMPTY2= -DTEST=42 -D'MACRO_FOR_INCR(s)=s+1' -DTOUNDEF -UTOUNDEF
+  New flags not previously present: -DDUPLICATE_FLAGS_THAT_WILL_BE_OVERWRITTEN
+  (warn-once: no further messages from category 'pp:compilation-db' will be emitted)
 [kernel] Parsing tests/jcdb/jcdb.c (with preprocessing)
 /* Generated by Frama-C */
 #include "errno.h"