[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 7 years ago committed by Facebook Github Bot
parent bb85b24f0a
commit 0cc371d0a2

@ -62,7 +62,7 @@ let setup_results_dir () =
match Config.command with
| Analyze
-> assert_results_dir "have you run capture before?"
| Clang | Report | ReportDiff
| Report | ReportDiff
-> create_results_dir ()
| Diff
-> 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
if not
( 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 () ;
create_results_dir ()
| Explore
-> 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 () =
( if Config.linters_validate_syntax_only then
match CTLParserHelper.validate_al_files () with
@ -85,6 +96,7 @@ let () =
-> print_endline e ; L.exit 3 ) ;
if Config.print_builtins then Builtin.print_and_exit () ;
setup_results_dir () ;
log_environment_info () ;
if Config.debug_mode then L.progress "Logs in %s@." (Config.results_dir ^/ Config.log_file) ;
match Config.command with
| Analyze
@ -97,12 +109,6 @@ let () =
L.environment_info "Starting analysis %a" pp_cluster_opt Config.cluster_cmdline ;
InferAnalyze.register_perf_stats_report () ;
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
-> let report_json =
match Config.from_json_report with

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

@ -26,10 +26,6 @@ type command =
| Capture
(** capture compilation commands and translate source files into infer's intermediate
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
(** set up the infer environment then run the compilation commands without capturing the
source files *)

@ -355,17 +355,14 @@ let clang_exe_aliases =
; "g++"
; "gcc" ]
let initial_command =
let exe_basename =
(* 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
let is_clang = List.mem ~equal:String.equal clang_exe_aliases in
match CLOpt.command_of_exe_name exe_basename with
| Some _ as command
-> command
| None when is_clang exe_basename
-> Some CLOpt.Clang
| None
-> None
Filename.basename Sys.argv.(0)
let infer_is_clang = List.mem ~equal:String.equal clang_exe_aliases exe_basename
let initial_command =
match CLOpt.command_of_exe_name exe_basename with Some _ as command -> command | None -> None
let 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
if infer_is_javac then Javac
else if !Sys.interactive then NoParse
else
match initial_command with
| Some Clang
-> NoParse
| None | Some (Analyze | Capture | Compile | Diff | Explore | Report | ReportDiff | Run)
-> InferCommand
else if infer_is_clang then NoParse
else InferCommand
let exe_usage =
let exe_command_name =
match initial_command with
| Some CLOpt.Clang
-> None (* users cannot see this *)
| Some command
-> Some (CLOpt.name_of_command command)
| None
@ -480,24 +471,17 @@ let anon_args = CLOpt.mk_anon ()
let () =
let on_unknown_arg_from_command (cmd: CLOpt.command) =
match cmd with
| Clang
-> assert false (* filtered out *)
| Report
-> `Add
| Analyze | Capture | Compile | Diff | Explore | ReportDiff | Run
-> `Reject
in
(* 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 ~f:(fun cmd ->
let {CommandDoc.name; command_doc} = CommandDoc.data_of_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
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
List.iter CLOpt.all_commands ~f:(fun cmd ->
let {CommandDoc.name; command_doc} = CommandDoc.data_of_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
CLOpt.mk_subcommand cmd ~name ?deprecated_long ~on_unknown_arg (Some command_doc) )
let abs_struct =
CLOpt.mk_int ~deprecated:["absstruct"] ~long:"abs-struct" ~default:1 ~meta:"int"
@ -877,8 +861,7 @@ and ( bo_debug
, write_dotty ) =
let all_generic_manuals =
List.filter_map CLOpt.all_commands ~f:(fun cmd ->
if List.mem ~equal:CLOpt.equal_command CLOpt.([Clang; Explore]) cmd then None
else Some (cmd, manual_generic) )
if CLOpt.equal_command Explore cmd then None else Some (cmd, manual_generic) )
in
let 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_is_clang : bool
val infer_is_javac : bool
val iphoneos_target_sdk_version : string option
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 maven : bool
val max_nesting : int option
val merge : bool

@ -12,6 +12,8 @@ module F = Format
(** Pretty Printing} *)
module CLOpt = CommandLineOption
(** Kind of simple printing: default or with full types *)
type simple_kind = SIM_DEFAULT | SIM_WITH_TYP
@ -134,4 +136,19 @@ let elapsed_time fmt () =
let elapsed = Unix.gettimeofday () -. Utils.initial_timeofday in
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
(** 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 :
?print_env:env -> ?sep:string -> ?sep_html:string -> ?sep_latex:string
-> (F.formatter -> 'a -> unit) -> F.formatter -> 'a list -> unit

@ -83,13 +83,6 @@ type mode =
let equal_mode = [%compare.equal : 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
| Analyze
| BuckGenrule _
@ -101,23 +94,11 @@ let pp_mode fmt mode =
-> (* these are pretty boring, do not log anything *)
()
| Javac (_, prog, args)
-> F.fprintf fmt "Javac driver mode:@\nprog = %s@\n" prog ;
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
-> F.fprintf fmt "Javac driver mode:@\nprog = %s@\nargs = %a" prog Pp.cli_args args
| Maven (prog, args)
-> F.fprintf fmt "Maven driver mode:@\nprog = %s@\n" prog ;
List.iter ~f:(F.fprintf fmt "Arg: %s@\n") args
-> F.fprintf fmt "Maven driver mode:@\nprog = %s@\nargs = %a" prog Pp.cli_args args
| Clang (_, prog, args)
-> F.fprintf fmt "Clang driver mode:@\nprog = %s@\n" prog ;
List.iter ~f:(F.fprintf fmt "Arg: %s@\n") args
-> F.fprintf fmt "Clang driver mode:@\nprog = %s@\nargs = %a" prog Pp.cli_args args
(* A clean command for each driver mode to be suggested to the user
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
CaptureCompilationDatabase.capture_files_in_database compilation_database
let capture ~changed_files = function
let capture ~changed_files mode =
match mode with
| Analyze
-> ()
| BuckCompilationDB (prog, args)
@ -264,12 +246,14 @@ let capture ~changed_files = function
| BuckGenrule path
-> L.progress "Capturing for Buck genrule compatibility...@." ; JMain.from_arguments path
| 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
-> L.progress "Capturing using compilation database...@." ;
capture_with_compilation_database ~changed_files db_files
| 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)
-> L.progress "Capturing in maven mode...@." ; Maven.capture ~prog ~args
| Python args
@ -424,8 +408,8 @@ let analyze_and_report ?suppress_console_report ~changed_files mode =
| 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 *)
(false, false)
| _ when Config.maven
-> (* Called from Maven, only do capture. *)
| _ when Config.infer_is_clang || Config.infer_is_javac
-> (* Called from another integration to do capture only. *)
(false, false)
| _, (CaptureOnly | CompileOnly)
-> (false, false)
@ -461,15 +445,6 @@ let fail_on_issue_epilogue () =
| Error 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 analyzer_enabled =
match required_analyzer with
@ -560,9 +535,14 @@ let mode_of_build_command build_cmd =
let mode_from_command_line =
( lazy
( match Config.generated_classes with
| _ when Config.maven
-> (* infer is pretending to be javac in the Maven integration *)
let build_args = match Array.to_list Sys.argv with _ :: args -> args | [] -> [] in
| _ when Config.infer_is_clang
-> let prog, args =
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)
| Some path
-> assert_supported_mode `Java "Buck genrule" ;
@ -572,7 +552,8 @@ let mode_from_command_line =
let run_prologue mode =
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 () ;
(* 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
@ -580,7 +561,8 @@ let run_prologue mode =
mono-threaded execution. *)
Unix.unsetenv "MAKEFLAGS" ;
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 =

Loading…
Cancel
Save