[clang] do not run clang on unsupported commands

Summary:
Try to skip running even `clang -###` when we know there's nothing to capture
in the clang command. Do that by recording in the `ClangCommand.t` whether the
command is pre- or post-running `clang -###`, and apply slightly different
filters in each case. In particular, the filter has to let in more commands
than necessary pre-`clang -###` because the flags are not normalised at that
point.

Also regard `-x cuda` commands as unsupported.

Reviewed By: mbouaziz

Differential Revision: D7584934

fbshipit-source-id: c27bb63
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 3f5c161391
commit 7c0bf66794

@ -9,4 +9,6 @@
open! IStd
val run_clang : ClangCommand.t -> (In_channel.t -> 'a) -> 'a
val capture : ClangCommand.t -> unit

@ -10,7 +10,12 @@
open! IStd
module L = Logging
type t = {exec: string; argv: string list; orig_argv: string list; quoting_style: ClangQuotes.style}
type t =
{ exec: string
; argv: string list
; orig_argv: string list
; quoting_style: ClangQuotes.style
; is_driver: bool }
(** bad for every clang invocation *)
let clang_blacklisted_flags =
@ -49,7 +54,11 @@ let can_attach_ast_exporter cmd =
let is_supported_language cmd =
match value_of_option cmd "-x" with
| None ->
L.external_warning "malformed -cc1 command has no \"-x\" flag!" ;
if cmd.is_driver then (* let's continue and ask clang -### *) true
else (
L.external_warning "malformed -cc1 command has no \"-x\" flag!" ;
false )
| Some "cuda" ->
false
| Some lang when String.is_prefix ~prefix:"assembler" lang ->
false
@ -58,9 +67,12 @@ let can_attach_ast_exporter cmd =
in
(* -Eonly is -cc1 flag that gets produced by 'clang -M -### ...' *)
let is_preprocessor_only cmd = has_flag cmd "-E" || has_flag cmd "-Eonly" in
has_flag cmd "-cc1" && is_supported_language cmd && not (is_preprocessor_only cmd)
(cmd.is_driver || has_flag cmd "-cc1") && is_supported_language cmd
&& not (is_preprocessor_only cmd)
let may_capture cmd = can_attach_ast_exporter cmd
let argv_cons a b = a :: b
let argv_do_if cond action x = if cond then action x else x
@ -174,14 +186,14 @@ let clang_cc1_cmd_sanitizer cmd =
file_arg_cmd_sanitizer {cmd with argv= clang_arguments}
let mk quoting_style ~prog ~args =
let mk ~is_driver quoting_style ~prog ~args =
(* Some arguments break the compiler so they need to be removed even before the normalization step *)
let blacklisted_flags_with_arg = ["-index-store-path"] in
let sanitized_args =
filter_and_replace_unsupported_args ~blacklisted_flags:clang_blacklisted_flags
~blacklisted_flags_with_arg args
in
{exec= prog; orig_argv= sanitized_args; argv= sanitized_args; quoting_style}
{exec= prog; orig_argv= sanitized_args; argv= sanitized_args; quoting_style; is_driver}
let to_unescaped_args cmd =

@ -11,12 +11,12 @@ open! IStd
type t
val mk : ClangQuotes.style -> prog:string -> args:string list -> t
(** [mk qs prog args] finds the type of command depending on its arguments [args]. The quoting style
of the arguments have to be provided, so that the command may be run later on. Beware that this
doesn't look inside argument files. This can be used to create a "clang -### ..." command on
which to call [command_to_run], but other functions from the module will not work as expected
unless the command has been normalized by "clang -### ...". *)
val mk : is_driver:bool -> ClangQuotes.style -> prog:string -> args:string list -> t
(** [mk ~is_driver qs prog args] finds the type of command depending on its arguments [args]. The
quoting style of the arguments have to be provided, so that the command may be run later
on. Beware that this doesn't look inside argument files. This can be used to create a "clang -###
..." command on which to call [command_to_run], but other functions from the module will not work
as expected unless the command has been normalized by "clang -### ...". *)
val command_to_run : t -> string
(** Make a command into a string ready to be passed to a shell to be executed. Fine to call with
@ -25,6 +25,9 @@ val command_to_run : t -> string
val can_attach_ast_exporter : t -> bool
(** Whether the command is suitable for attaching the AST exporter. Must be called on normalized commands. *)
val may_capture : t -> bool
(** Whether the command has a chance of triggering compilation steps we can capture. *)
val with_plugin_args : t -> t
(** Add the arguments needed to attach the facebook-clang-plugins plugin. Must be called on normalized commands. *)

@ -13,7 +13,11 @@
open! IStd
module L = Logging
type action_item = Command of ClangCommand.t | ClangError of string | ClangWarning of string
type action_item =
| CanonicalCommand of ClangCommand.t (** commands output by [clang -###] *)
| DriverCommand of ClangCommand.t (** commands prior to [clang -###] treatment *)
| ClangError of string
| ClangWarning of string
let clang_ignore_regex = Option.map ~f:Str.regexp Config.clang_ignore_regex
@ -50,10 +54,10 @@ let check_for_existing_file args =
check_for_existing_file_arg all_args
(** Given a list of arguments for clang [args], return a list of new commands to run according to
the results of `clang -### [args]`. *)
let normalize ~prog ~args : action_item list =
let cmd = ClangCommand.mk ClangQuotes.SingleQuotes ~prog ~args in
(** Given a clang command, return a list of new commands to run according to the results of `clang
-### [args]`. *)
let clang_driver_action_items : ClangCommand.t -> action_item list =
fun cmd ->
let clang_hashhashhash =
Printf.sprintf "%s 2>&1"
( ClangCommand.prepend_arg "-###" cmd
@ -77,14 +81,14 @@ let normalize ~prog ~args : action_item list =
let normalized_commands = ref [] in
let one_line line =
if String.is_prefix ~prefix:" \"" line then
Command
CanonicalCommand
( match
(* massage line to remove edge-cases for splitting *)
"\"" ^ line ^ " \"" |> (* split by whitespace *)
Str.split (Str.regexp_string "\" \"")
with
| prog :: args ->
ClangCommand.mk ClangQuotes.EscapedDoubleQuotes ~prog ~args
ClangCommand.mk ~is_driver:false ClangQuotes.EscapedDoubleQuotes ~prog ~args
| [] ->
L.(die InternalError) "ClangWrapper: argv cannot be empty" )
else if Str.string_match (Str.regexp "clang[^ :]*: warning: ") line 0 then ClangWarning line
@ -114,6 +118,13 @@ let normalize ~prog ~args : action_item list =
!normalized_commands
(** Given a list of arguments for clang [args], return a list of new commands to run according to
the results of `clang -### [args]` if the command can be analysed. *)
let normalize ~prog ~args : action_item list =
let cmd = ClangCommand.mk ~is_driver:true ClangQuotes.SingleQuotes ~prog ~args in
if ClangCommand.may_capture cmd then clang_driver_action_items cmd else [DriverCommand cmd]
let exec_action_item ~prog ~args = function
| ClangError error ->
(* An error in the output of `clang -### ...`. Outputs the error and fail. This is because
@ -128,8 +139,15 @@ let exec_action_item ~prog ~args = function
*** Infer needs a working compilation command to run." prog Pp.cli_args args error
| ClangWarning warning ->
L.external_warning "%s@\n" warning
| Command clang_cmd ->
| CanonicalCommand clang_cmd ->
Capture.capture clang_cmd
| DriverCommand clang_cmd ->
if Option.is_none Config.buck_compilation_database
|| Config.skip_analysis_in_path_skips_compilation
then Capture.run_clang clang_cmd Utils.echo_in
else
L.debug Capture Quiet "Skipping seemingly uninteresting clang driver command %s@\n"
(ClangCommand.command_to_run clang_cmd)
let exe ~prog ~args =

Loading…
Cancel
Save