diff --git a/src/kernel_services/ast_queries/file.ml b/src/kernel_services/ast_queries/file.ml index b64a9a308b067bf8ccb10ac22b1d455375f58d22..70ef66d61040e8a0dba60b655ac82f492b051f4a 100644 --- a/src/kernel_services/ast_queries/file.ml +++ b/src/kernel_services/ast_queries/file.ml @@ -38,9 +38,10 @@ type file = Filepath.Normalized.t (* Filename of the [.c] to preprocess. *) * string (* Preprocessing command, as given by -cpp-command, or the default value, but without extra arguments. *) - * string list (* Extra arguments (already included in the command) - which must also be given to the logic preprocessor - (since Frama-C may preprocess twice each source). *) + * string list (* Extra arguments, specific to this file (that is, + obtained via a JCDB, or -cpp-extra-args-per-file, + but _not_ those via -cpp-extra-args), to be given + to the C preprocessor. *) * cpp_opt_kind (* Whether the preprocessor is known to be compatible with GCC-style options (mostly, -D and -I). *) | NoCPP of Filepath.Normalized.t (** filename of a preprocessed [.c] *) @@ -126,7 +127,7 @@ let from_filename ?cpp f = else if cpp = None then get_preprocessor_command () else Option.get cpp in - let extra = + let extra_for_this_file = let extra_by_file = try Kernel.CppExtraArgsPerFile.find f with Not_found -> "" @@ -156,7 +157,7 @@ let from_filename ?cpp f = Kernel.warning ~once:true "Default pre-processor does not keep comments. Any ACSL annotation \ on non-pre-processed file will be discarded."; - NeedCPP (f, cpp, extra, is_cpp_gnu_like ()) + NeedCPP (f, cpp, extra_for_this_file, is_cpp_gnu_like ()) end else Kernel.abort "No working pre-processor found. You can only analyze \ pre-processed .i files." @@ -467,7 +468,7 @@ let adjust_pwd fp cpp_command = let build_cpp_cmd = function | NoCPP _ | External _ -> None - | NeedCPP (f, cmdl, extra, is_gnu_like) -> + | NeedCPP (f, cmdl, extra_for_this_file, is_gnu_like) -> if not (Sys.file_exists (f :> string)) then Kernel.abort "source file %a does not exist" Filepath.Normalized.pretty f; @@ -490,16 +491,16 @@ let build_cpp_cmd = function let ppf = create_temp_file ~debug (Filename.basename (f :> string)) ".i" in (* Hypothesis: the preprocessor is POSIX compliant, hence understands -I and -D. *) - let include_args = + let fc_include_args = if Kernel.FramaCStdLib.get () then [(Fc_config.framac_libc:>string)] else [] in - let define_args = + let fc_define_args = if not (existing_machdep_macro ()) then [machdep_macro (Kernel.Machdep.get ())] else [] in - let define_args = "__FRAMAC__" :: define_args in + let fc_define_args = "__FRAMAC__" :: fc_define_args in (* Hypothesis: the preprocessor does support the arch-related options tested when 'configure' was run. *) let required_cpp_arch_args = (get_machdep ()).cpp_arch_flags in @@ -539,10 +540,13 @@ let build_cpp_cmd = function in let supp_args = string_of_supp_args - (Kernel.CppExtraArgs.get () @ gnu_implicit_args @ supported_cpp_arch_args @ extra) - include_args define_args + (gnu_implicit_args @ supported_cpp_arch_args @ + extra_for_this_file @ (Kernel.CppExtraArgs.get ())) + fc_include_args fc_define_args + in + let cpp_command = + replace_in_cpp_cmd cmdl supp_args (f:>string) (ppf:>string) in - let cpp_command = replace_in_cpp_cmd cmdl supp_args (f:>string) (ppf:>string) in let workdir, cpp_command_with_chdir = adjust_pwd f cpp_command in if workdir <> None then Parse_env.set_workdir ppf (Option.get workdir); @@ -551,6 +555,33 @@ let build_cpp_cmd = function cpp_command_with_chdir; Some (cpp_command_with_chdir, ppf, supported_cpp_arch_args) +let abort_with_detailed_pp_message f cpp_command = + let possible_cause = + if Kernel.JsonCompilationDatabase.is_set () then + if not (Json_compilation_database.has_entry f) then + Format.asprintf "note: %s is set but \ + contains no entries for '%a'.@ " + Kernel.JsonCompilationDatabase.option_name + Datatype.Filepath.pretty f + else "" + else + if not (Kernel.CppExtraArgs.is_set ()) && + not (Kernel.CppExtraArgsPerFile.is_set ()) && + not (Kernel.CppCommand.is_set ()) then + Format.asprintf + "this is possibly due to missing preprocessor flags;@ \ + consider options %s, %s or %s.@ " + Kernel.CppExtraArgs.option_name + Kernel.JsonCompilationDatabase.option_name + Kernel.CppCommand.option_name + else "" + in + Kernel.abort + "failed to run: %s@\n\ + %sSee chapter \"Preparing the Sources\" in the Frama-C user manual \ + for more details." + cpp_command possible_cause + let parse_cabs cpp_command = function | NoCPP f -> if not (Sys.file_exists (f:>string)) then @@ -559,37 +590,13 @@ let parse_cabs cpp_command = function Kernel.feedback "Parsing %a (no preprocessing)" Datatype.Filepath.pretty f; Frontc.parse f () - | NeedCPP (f, cmdl, _extra, is_gnu_like) -> + | NeedCPP (f, cmdl, _extra_for_this_file, is_gnu_like) -> let cpp_command, ppf, logic_pp_args = Option.get cpp_command in Kernel.feedback "Parsing %a (with preprocessing)" Datatype.Filepath.pretty f; if Sys.command cpp_command <> 0 then begin safe_remove_file ppf; - let possible_cause = - if Kernel.JsonCompilationDatabase.is_set () then - if not (Json_compilation_database.has_entry f) then - Format.asprintf "note: %s is set but \ - contains no entries for '%a'.@ " - Kernel.JsonCompilationDatabase.option_name - Datatype.Filepath.pretty f - else "" - else - if not (Kernel.CppExtraArgs.is_set ()) && - not (Kernel.CppExtraArgsPerFile.is_set ()) && - not (Kernel.CppCommand.is_set ()) then - Format.asprintf - "this is possibly due to missing preprocessor flags;@ \ - consider options %s, %s or %s.@ " - Kernel.CppExtraArgs.option_name - Kernel.JsonCompilationDatabase.option_name - Kernel.CppCommand.option_name - else "" - in - Kernel.abort - "failed to run: %s@\n\ - %sSee chapter \"Preparing the Sources\" in the Frama-C user manual \ - for more details." - cpp_command possible_cause + abort_with_detailed_pp_message f cpp_command end; let ppf = if Kernel.ReadAnnot.get() && diff --git a/tests/syntax/cpp-command.c b/tests/syntax/cpp-command.c index 2510c0664e13ed50791184392085a1abf20a793e..dc71436e8b0da41c34da48c7f39c1559f580a5dc 100644 --- a/tests/syntax/cpp-command.c +++ b/tests/syntax/cpp-command.c @@ -5,9 +5,9 @@ OPT: -machdep x86_32 -cpp-frama-c-compliant -cpp-command "printf \"%s\n\" \"using \\% has no effect : \$(basename \"\%input\")\"" OPT: -machdep x86_32 -cpp-frama-c-compliant -cpp-command "echo %var is not an interpreted placeholder" OPT: -machdep x86_32 -print-cpp-commands - OPT: -cpp-extra-args-per-file=@PTEST_FILE@:"-DPF=\\\"cp%02d_3f\\\"" @PTEST_FILE@ -print + OPT: -cpp-extra-args-per-file=@PTEST_FILE@:"-DPF=\\\"cp%02d_%.3f\\\"" -cpp-extra-args="-DPF2=\\\"cp%02d_%.3f\\\"" -no-autoload-plugins @PTEST_FILE@ -print + OPT: -cpp-extra-args-per-file=@PTEST_FILE@:"file_extra" -cpp-extra-args="global_extra" -cpp-command "echo 'extra_args: %args'" -no-autoload-plugins @PTEST_FILE@ -print */ - #include <stdio.h> void printer(int i, float f) { printf(PF, i, f); diff --git a/tests/syntax/oracle/cpp-command.5.res.oracle b/tests/syntax/oracle/cpp-command.5.res.oracle index 48860bc0cfb1ba8cc3b430b41b1659291445c0a6..1c90e0192879b68cdefbcfae1eac5a6b7564a5b1 100644 --- a/tests/syntax/oracle/cpp-command.5.res.oracle +++ b/tests/syntax/oracle/cpp-command.5.res.oracle @@ -6,7 +6,7 @@ #include "stdio.h" void printer(int i, float f) { - printf("cp%02d_3f",i,(double)f); + printf("cp%02d_%.3f",i,(double)f); return; } diff --git a/tests/syntax/oracle/cpp-command.6.res.oracle b/tests/syntax/oracle/cpp-command.6.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..cd4b804010bbc298960b786eedcdb421bf3772ee --- /dev/null +++ b/tests/syntax/oracle/cpp-command.6.res.oracle @@ -0,0 +1,7 @@ +[kernel] Warning: your preprocessor is not known to handle option `-nostdinc'. If pre-processing fails because of it, please add -no-cpp-frama-c-compliant option to Frama-C's command-line. If you do not want to see this warning again, explicitly use option -cpp-frama-c-compliant. +[kernel] Warning: your preprocessor is not known to handle option `-dD'. If pre-processing fails because of it, please add -no-cpp-frama-c-compliant option to Frama-C's command-line. If you do not want to see this warning again, explicitly use option -cpp-frama-c-compliant. +[kernel] Parsing cpp-command.c (with preprocessing) +extra_args: -IFRAMAC_SHARE/libc -D__FRAMAC__ -D__FC_MACHDEP_X86_64 -dD -nostdinc -m64 file_extra global_extra +[kernel] Warning: trying to preprocess annotation with an unknown preprocessor. +/* Generated by Frama-C */ +