[driver] remove infer-clang fake command

Summary:
"Running as clang" was its own infer subcommand. That's not terribly good
because it makes it hard to specify another subcommand, and in particular it
broke the `compile` subcommand in some integrations because "running as clang"
would always do capture. The cmake tests required to run with `--keep-going`
because of this.

Instead of having its own fake subcommand, simply add a new boolean in the
config for "infer runs as clang", as we do for javac already (used in the mvn
integration).

Also make logging of the environment better.

Reviewed By: jberdine

Differential Revision: D5813986

fbshipit-source-id: 72b96cd
master
Jules Villard 8 years ago committed by Facebook Github Bot
parent bb85b24f0a
commit 0cc371d0a2

@ -62,7 +62,7 @@ let setup_results_dir () =
match Config.command with match Config.command with
| Analyze | Analyze
-> assert_results_dir "have you run capture before?" -> assert_results_dir "have you run capture before?"
| Clang | Report | ReportDiff | Report | ReportDiff
-> create_results_dir () -> create_results_dir ()
| Diff | Diff
-> remove_results_dir () ; create_results_dir () -> remove_results_dir () ; create_results_dir ()
@ -70,12 +70,23 @@ let setup_results_dir () =
-> let driver_mode = Lazy.force Driver.mode_from_command_line in -> let driver_mode = Lazy.force Driver.mode_from_command_line in
if not if not
( Driver.(equal_mode driver_mode Analyze) ( Driver.(equal_mode driver_mode Analyze)
|| Config.(buck || continue_capture || maven || reactive_mode) ) ||
Config.(buck || continue_capture || infer_is_clang || infer_is_javac || reactive_mode) )
then remove_results_dir () ; then remove_results_dir () ;
create_results_dir () create_results_dir ()
| Explore | Explore
-> assert_results_dir "please run an infer analysis first" -> assert_results_dir "please run an infer analysis first"
let log_environment_info () =
L.environment_info "CWD = %s@\n" (Sys.getcwd ()) ;
L.environment_info "Project root = %s@\n" Config.project_root ;
let infer_args =
Sys.getenv CLOpt.args_env_var |> Option.map ~f:(String.split ~on:CLOpt.env_var_sep)
|> Option.value ~default:["<not set>"]
in
L.environment_info "INFER_ARGS = %a" Pp.cli_args infer_args ;
L.environment_info "command line arguments: %a" Pp.cli_args (Array.to_list Sys.argv)
let () = let () =
( if Config.linters_validate_syntax_only then ( if Config.linters_validate_syntax_only then
match CTLParserHelper.validate_al_files () with match CTLParserHelper.validate_al_files () with
@ -85,6 +96,7 @@ let () =
-> print_endline e ; L.exit 3 ) ; -> print_endline e ; L.exit 3 ) ;
if Config.print_builtins then Builtin.print_and_exit () ; if Config.print_builtins then Builtin.print_and_exit () ;
setup_results_dir () ; setup_results_dir () ;
log_environment_info () ;
if Config.debug_mode then L.progress "Logs in %s@." (Config.results_dir ^/ Config.log_file) ; if Config.debug_mode then L.progress "Logs in %s@." (Config.results_dir ^/ Config.log_file) ;
match Config.command with match Config.command with
| Analyze | Analyze
@ -97,12 +109,6 @@ let () =
L.environment_info "Starting analysis %a" pp_cluster_opt Config.cluster_cmdline ; L.environment_info "Starting analysis %a" pp_cluster_opt Config.cluster_cmdline ;
InferAnalyze.register_perf_stats_report () ; InferAnalyze.register_perf_stats_report () ;
Driver.analyze_and_report Analyze ~changed_files:(Driver.read_config_changed_files ()) Driver.analyze_and_report Analyze ~changed_files:(Driver.read_config_changed_files ())
| Clang
-> let prog, args =
match Array.to_list Sys.argv with prog :: args -> (prog, args) | [] -> assert false
(* Sys.argv is never empty *)
in
ClangWrapper.exe ~prog ~args
| Report | Report
-> let report_json = -> let report_json =
match Config.from_json_report with match Config.from_json_report with

@ -197,9 +197,7 @@ $(b,infer) $(i,[options])|}
"cxx": false, "cxx": false,
"infer-blacklist-files-containing": ["@generated","@Generated"] "infer-blacklist-files-containing": ["@generated","@Generated"]
}|} }|}
] ] ~see_also:CLOpt.all_commands "infer"
~see_also:(List.filter ~f:(function CLOpt.Clang -> false | _ -> true) CLOpt.all_commands)
"infer"
let report = let report =
mk_command_doc ~title:"Infer Reporting" ~short_description:"compute and manipulate infer results" mk_command_doc ~title:"Infer Reporting" ~short_description:"compute and manipulate infer results"

@ -88,7 +88,6 @@ let anon_arg_action_of_parse_mode parse_mode =
type command = type command =
| Analyze | Analyze
| Capture | Capture
| Clang
| Compile | Compile
| Diff | Diff
| Explore | Explore
@ -104,7 +103,6 @@ let infer_exe_name = "infer"
let command_to_name = let command_to_name =
[ (Analyze, "analyze") [ (Analyze, "analyze")
; (Capture, "capture") ; (Capture, "capture")
; (Clang, "clang")
; (Compile, "compile") ; (Compile, "compile")
; (Diff, "diff") ; (Diff, "diff")
; (Explore, "explore") ; (Explore, "explore")
@ -925,17 +923,16 @@ let parse ?config_file ~usage action initial_command =
add_parsed_args_to_args_to_export () ; curr_usage add_parsed_args_to_args_to_export () ; curr_usage
in in
let to_export = let to_export =
(* We have to be careful not to add too much data to the environment because the size of the let argv_to_export = decode_env_to_argv !args_to_export in
environment contributes to the length of the command to be run. If the environment + CLI is if argv_to_export <> [] then
too big, running any command will fail with a cryptic "exit code 127" error. Use an argfile (* We have to be careful not to add too much data to the environment because the size of the
to prevent this from happening *) environment contributes to the length of the command to be run. If the environment + CLI is
let file = Filename.temp_file "args_" "" in too big, running any command will fail with a cryptic "exit code 127" error. Use an argfile
let quoted_file_args = to prevent this from happening *)
List.map (decode_env_to_argv !args_to_export) ~f:(fun arg -> let file = Filename.temp_file "args_" "" in
if String.contains arg '\'' then arg else F.sprintf "'%s'" arg ) Out_channel.with_file file ~f:(fun oc -> Out_channel.output_lines oc argv_to_export) ;
in "@" ^ file
Out_channel.with_file file ~f:(fun oc -> Out_channel.output_lines oc quoted_file_args) ; else ""
"@" ^ file
in in
Unix.putenv ~key:args_env_var ~data:to_export ; (!curr_command, curr_usage) Unix.putenv ~key:args_env_var ~data:to_export ; (!curr_command, curr_usage)

@ -26,10 +26,6 @@ type command =
| Capture | Capture
(** capture compilation commands and translate source files into infer's intermediate (** capture compilation commands and translate source files into infer's intermediate
language *) language *)
| Clang
(** run and accept the same arguments as the clang compiler, may also capture the source
files compiled, and may also not actually compile the files depending on other options
*)
| Compile | Compile
(** set up the infer environment then run the compilation commands without capturing the (** set up the infer environment then run the compilation commands without capturing the
source files *) source files *)

@ -355,17 +355,14 @@ let clang_exe_aliases =
; "g++" ; "g++"
; "gcc" ] ; "gcc" ]
let initial_command = let exe_basename =
(* Sys.executable_name tries to do clever things which we must avoid, use argv[0] instead *) (* Sys.executable_name tries to do clever things which we must avoid, use argv[0] instead *)
let exe_basename = Filename.basename Sys.argv.(0) in Filename.basename Sys.argv.(0)
let is_clang = List.mem ~equal:String.equal clang_exe_aliases in
match CLOpt.command_of_exe_name exe_basename with let infer_is_clang = List.mem ~equal:String.equal clang_exe_aliases exe_basename
| Some _ as command
-> command let initial_command =
| None when is_clang exe_basename match CLOpt.command_of_exe_name exe_basename with Some _ as command -> command | None -> None
-> Some CLOpt.Clang
| None
-> None
let bin_dir = let bin_dir =
(* Resolve symlinks to get to the real executable, which is located in [bin_dir]. *) (* Resolve symlinks to get to the real executable, which is located in [bin_dir]. *)
@ -426,18 +423,12 @@ let startup_action =
let open CLOpt in let open CLOpt in
if infer_is_javac then Javac if infer_is_javac then Javac
else if !Sys.interactive then NoParse else if !Sys.interactive then NoParse
else else if infer_is_clang then NoParse
match initial_command with else InferCommand
| Some Clang
-> NoParse
| None | Some (Analyze | Capture | Compile | Diff | Explore | Report | ReportDiff | Run)
-> InferCommand
let exe_usage = let exe_usage =
let exe_command_name = let exe_command_name =
match initial_command with match initial_command with
| Some CLOpt.Clang
-> None (* users cannot see this *)
| Some command | Some command
-> Some (CLOpt.name_of_command command) -> Some (CLOpt.name_of_command command)
| None | None
@ -480,24 +471,17 @@ let anon_args = CLOpt.mk_anon ()
let () = let () =
let on_unknown_arg_from_command (cmd: CLOpt.command) = let on_unknown_arg_from_command (cmd: CLOpt.command) =
match cmd with match cmd with
| Clang
-> assert false (* filtered out *)
| Report | Report
-> `Add -> `Add
| Analyze | Capture | Compile | Diff | Explore | ReportDiff | Run | Analyze | Capture | Compile | Diff | Explore | ReportDiff | Run
-> `Reject -> `Reject
in in
(* make sure we generate doc for all the commands we know about *) (* make sure we generate doc for all the commands we know about *)
List.filter ~f:(Fn.non CLOpt.(equal_command Clang)) CLOpt.all_commands List.iter CLOpt.all_commands ~f:(fun cmd ->
|> List.iter ~f:(fun cmd -> let {CommandDoc.name; command_doc} = CommandDoc.data_of_command cmd in
let {CommandDoc.name; command_doc} = CommandDoc.data_of_command cmd in let on_unknown_arg = on_unknown_arg_from_command cmd in
let on_unknown_arg = on_unknown_arg_from_command cmd in let deprecated_long = if CLOpt.(equal_command ReportDiff) cmd then Some "diff" else None in
let deprecated_long = CLOpt.mk_subcommand cmd ~name ?deprecated_long ~on_unknown_arg (Some command_doc) )
if CLOpt.(equal_command ReportDiff) cmd then Some "diff" else None
in
CLOpt.mk_subcommand cmd ~name ?deprecated_long ~on_unknown_arg (Some command_doc) )
let () = CLOpt.mk_subcommand CLOpt.Clang ~name:"clang" ~on_unknown_arg:`Skip None
let abs_struct = let abs_struct =
CLOpt.mk_int ~deprecated:["absstruct"] ~long:"abs-struct" ~default:1 ~meta:"int" CLOpt.mk_int ~deprecated:["absstruct"] ~long:"abs-struct" ~default:1 ~meta:"int"
@ -877,8 +861,7 @@ and ( bo_debug
, write_dotty ) = , write_dotty ) =
let all_generic_manuals = let all_generic_manuals =
List.filter_map CLOpt.all_commands ~f:(fun cmd -> List.filter_map CLOpt.all_commands ~f:(fun cmd ->
if List.mem ~equal:CLOpt.equal_command CLOpt.([Clang; Explore]) cmd then None if CLOpt.equal_command Explore cmd then None else Some (cmd, manual_generic) )
else Some (cmd, manual_generic) )
in in
let bo_debug = let bo_debug =
CLOpt.mk_int ~default:0 ~long:"bo-debug" CLOpt.mk_int ~default:0 ~long:"bo-debug"

@ -424,6 +424,10 @@ val immutable_cast : bool
val infer_cache : string option val infer_cache : string option
val infer_is_clang : bool
val infer_is_javac : bool
val iphoneos_target_sdk_version : string option val iphoneos_target_sdk_version : string option
type iphoneos_target_sdk_version_path_regex = {path: Str.regexp; version: string} type iphoneos_target_sdk_version_path_regex = {path: Str.regexp; version: string}
@ -491,8 +495,6 @@ val log_file : string
val makefile_cmdline : string val makefile_cmdline : string
val maven : bool
val max_nesting : int option val max_nesting : int option
val merge : bool val merge : bool

@ -12,6 +12,8 @@ module F = Format
(** Pretty Printing} *) (** Pretty Printing} *)
module CLOpt = CommandLineOption
(** Kind of simple printing: default or with full types *) (** Kind of simple printing: default or with full types *)
type simple_kind = SIM_DEFAULT | SIM_WITH_TYP type simple_kind = SIM_DEFAULT | SIM_WITH_TYP
@ -134,4 +136,19 @@ let elapsed_time fmt () =
let elapsed = Unix.gettimeofday () -. Utils.initial_timeofday in let elapsed = Unix.gettimeofday () -. Utils.initial_timeofday in
F.fprintf fmt "%f" elapsed F.fprintf fmt "%f" elapsed
let to_string ~f fmt x = F.fprintf fmt "%s" (f x) let string fmt s = F.fprintf fmt "%s" s
let to_string ~f fmt x = string fmt (f x)
let pp_argfile fmt fname =
try
F.fprintf fmt " Contents of '%s'@\n" fname ;
In_channel.iter_lines ~f:(F.fprintf fmt " %s@\n") (In_channel.create fname) ;
F.fprintf fmt " /Contents of '%s'@\n" fname
with exn -> F.fprintf fmt " Error reading file '%s':@\n %a@\n" fname Exn.pp exn
let cli_args fmt args =
F.fprintf fmt "%a@\n%a"
(seq ~sep:(String.of_char CLOpt.env_var_sep) string)
args (seq ~sep:"\n" pp_argfile)
(List.filter_map ~f:(String.chop_prefix ~prefix:"@") args)

@ -68,6 +68,11 @@ val latex : color -> env
val color_string : color -> string val color_string : color -> string
(** string representation of colors *) (** string representation of colors *)
val string : F.formatter -> string -> unit
val cli_args : F.formatter -> string list -> unit
(** pretty print command line arguments, expanding argument files to print their contents *)
val seq : val seq :
?print_env:env -> ?sep:string -> ?sep_html:string -> ?sep_latex:string ?print_env:env -> ?sep:string -> ?sep_html:string -> ?sep_latex:string
-> (F.formatter -> 'a -> unit) -> F.formatter -> 'a list -> unit -> (F.formatter -> 'a -> unit) -> F.formatter -> 'a list -> unit

@ -83,13 +83,6 @@ type mode =
let equal_mode = [%compare.equal : mode] let equal_mode = [%compare.equal : mode]
let pp_mode fmt mode = let pp_mode fmt mode =
let log_argfile_arg fname =
try
F.fprintf fmt "-- Contents of '%s'@\n" fname ;
In_channel.iter_lines ~f:(F.fprintf fmt "%s@\n") (In_channel.create fname) ;
F.fprintf fmt "-- /Contents of '%s'@." fname
with exn -> F.fprintf fmt " Error reading file '%s':@\n %a@." fname Exn.pp exn
in
match mode with match mode with
| Analyze | Analyze
| BuckGenrule _ | BuckGenrule _
@ -101,23 +94,11 @@ let pp_mode fmt mode =
-> (* these are pretty boring, do not log anything *) -> (* these are pretty boring, do not log anything *)
() ()
| Javac (_, prog, args) | Javac (_, prog, args)
-> F.fprintf fmt "Javac driver mode:@\nprog = %s@\n" prog ; -> F.fprintf fmt "Javac driver mode:@\nprog = %s@\nargs = %a" prog Pp.cli_args args
let log_arg arg =
F.fprintf fmt "Arg: %s@\n" arg ;
(* "@fname" means that fname is an arg file containing additional arguments to pass to
javac. *)
String.chop_prefix ~prefix:"@" arg
|> (* Sometimes these argfiles go away at the end of the build and we cannot inspect them after
the fact, so log them now. *)
Option.iter ~f:log_argfile_arg
in
List.iter ~f:log_arg args
| Maven (prog, args) | Maven (prog, args)
-> F.fprintf fmt "Maven driver mode:@\nprog = %s@\n" prog ; -> F.fprintf fmt "Maven driver mode:@\nprog = %s@\nargs = %a" prog Pp.cli_args args
List.iter ~f:(F.fprintf fmt "Arg: %s@\n") args
| Clang (_, prog, args) | Clang (_, prog, args)
-> F.fprintf fmt "Clang driver mode:@\nprog = %s@\n" prog ; -> F.fprintf fmt "Clang driver mode:@\nprog = %s@\nargs = %a" prog Pp.cli_args args
List.iter ~f:(F.fprintf fmt "Arg: %s@\n") args
(* A clean command for each driver mode to be suggested to the user (* A clean command for each driver mode to be suggested to the user
in case nothing got captured. *) in case nothing got captured. *)
@ -254,7 +235,8 @@ let capture_with_compilation_database db_files =
let compilation_database = CompilationDatabase.from_json_files db_files in let compilation_database = CompilationDatabase.from_json_files db_files in
CaptureCompilationDatabase.capture_files_in_database compilation_database CaptureCompilationDatabase.capture_files_in_database compilation_database
let capture ~changed_files = function let capture ~changed_files mode =
match mode with
| Analyze | Analyze
-> () -> ()
| BuckCompilationDB (prog, args) | BuckCompilationDB (prog, args)
@ -264,12 +246,14 @@ let capture ~changed_files = function
| BuckGenrule path | BuckGenrule path
-> L.progress "Capturing for Buck genrule compatibility...@." ; JMain.from_arguments path -> L.progress "Capturing for Buck genrule compatibility...@." ; JMain.from_arguments path
| Clang (compiler, prog, args) | Clang (compiler, prog, args)
-> L.progress "Capturing in make/cc mode...@." ; Clang.capture compiler ~prog ~args -> if CLOpt.is_originator then L.progress "Capturing in make/cc mode...@." ;
Clang.capture compiler ~prog ~args
| ClangCompilationDB db_files | ClangCompilationDB db_files
-> L.progress "Capturing using compilation database...@." ; -> L.progress "Capturing using compilation database...@." ;
capture_with_compilation_database ~changed_files db_files capture_with_compilation_database ~changed_files db_files
| Javac (compiler, prog, args) | Javac (compiler, prog, args)
-> L.progress "Capturing in javac mode...@." ; Javac.capture compiler ~prog ~args -> if CLOpt.is_originator then L.progress "Capturing in javac mode...@." ;
Javac.capture compiler ~prog ~args
| Maven (prog, args) | Maven (prog, args)
-> L.progress "Capturing in maven mode...@." ; Maven.capture ~prog ~args -> L.progress "Capturing in maven mode...@." ; Maven.capture ~prog ~args
| Python args | Python args
@ -424,8 +408,8 @@ let analyze_and_report ?suppress_console_report ~changed_files mode =
| PythonCapture (BBuck, _), _ when not Config.flavors | PythonCapture (BBuck, _), _ when not Config.flavors
-> (* In Buck mode when compilation db is not used, analysis is invoked from capture if buck flavors are not used *) -> (* In Buck mode when compilation db is not used, analysis is invoked from capture if buck flavors are not used *)
(false, false) (false, false)
| _ when Config.maven | _ when Config.infer_is_clang || Config.infer_is_javac
-> (* Called from Maven, only do capture. *) -> (* Called from another integration to do capture only. *)
(false, false) (false, false)
| _, (CaptureOnly | CompileOnly) | _, (CaptureOnly | CompileOnly)
-> (false, false) -> (false, false)
@ -461,15 +445,6 @@ let fail_on_issue_epilogue () =
| Error error | Error error
-> L.internal_error "Failed to read report file '%s': %s@." issues_json error ; () -> L.internal_error "Failed to read report file '%s': %s@." issues_json error ; ()
let log_infer_args mode =
L.environment_info "INFER_ARGS = %s@\n"
(Option.value (Sys.getenv CLOpt.args_env_var) ~default:"<not found>") ;
List.iter ~f:(L.environment_info "anon arg: %s@\n") Config.anon_args ;
List.iter ~f:(L.environment_info "rest arg: %s@\n") Config.rest ;
L.environment_info "Project root = %s@\n" Config.project_root ;
L.environment_info "CWD = %s@\n" (Sys.getcwd ()) ;
L.environment_info "Driver mode:@\n%a@." pp_mode mode
let assert_supported_mode required_analyzer requested_mode_string = let assert_supported_mode required_analyzer requested_mode_string =
let analyzer_enabled = let analyzer_enabled =
match required_analyzer with match required_analyzer with
@ -560,9 +535,14 @@ let mode_of_build_command build_cmd =
let mode_from_command_line = let mode_from_command_line =
( lazy ( lazy
( match Config.generated_classes with ( match Config.generated_classes with
| _ when Config.maven | _ when Config.infer_is_clang
-> (* infer is pretending to be javac in the Maven integration *) -> let prog, args =
let build_args = match Array.to_list Sys.argv with _ :: args -> args | [] -> [] in match Array.to_list Sys.argv with prog :: args -> (prog, args) | [] -> assert false
(* Sys.argv is never empty *)
in
Clang (Clang.Clang, prog, args)
| _ when Config.infer_is_javac
-> let build_args = match Array.to_list Sys.argv with _ :: args -> args | [] -> [] in
Javac (Javac.Javac, "javac", build_args) Javac (Javac.Javac, "javac", build_args)
| Some path | Some path
-> assert_supported_mode `Java "Buck genrule" ; -> assert_supported_mode `Java "Buck genrule" ;
@ -572,7 +552,8 @@ let mode_from_command_line =
let run_prologue mode = let run_prologue mode =
if CLOpt.is_originator then L.environment_info "%a@\n" Config.pp_version () ; if CLOpt.is_originator then L.environment_info "%a@\n" Config.pp_version () ;
if Config.debug_mode || Config.stats_mode then log_infer_args mode ; if Config.debug_mode || Config.stats_mode then
L.environment_info "Driver mode:@\n%a@." pp_mode mode ;
if Config.dump_duplicate_symbols then reset_duplicates_file () ; if Config.dump_duplicate_symbols then reset_duplicates_file () ;
(* infer might be called from a Makefile and itself uses `make` to run the analysis in parallel, (* infer might be called from a Makefile and itself uses `make` to run the analysis in parallel,
but cannot communicate with the parent make command. Since infer won't interfere with them but cannot communicate with the parent make command. Since infer won't interfere with them
@ -580,7 +561,8 @@ let run_prologue mode =
mono-threaded execution. *) mono-threaded execution. *)
Unix.unsetenv "MAKEFLAGS" ; Unix.unsetenv "MAKEFLAGS" ;
register_perf_stats_report () ; register_perf_stats_report () ;
if not Config.buck_cache_mode then touch_start_file_unless_continue () ; if not Config.buck_cache_mode && not Config.infer_is_clang && not Config.infer_is_javac then
touch_start_file_unless_continue () ;
() ()
let run_epilogue mode = let run_epilogue mode =

Loading…
Cancel
Save