[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 open! IStd
val run_clang : ClangCommand.t -> (In_channel.t -> 'a) -> 'a
val capture : ClangCommand.t -> unit val capture : ClangCommand.t -> unit

@ -10,7 +10,12 @@
open! IStd open! IStd
module L = Logging 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 *) (** bad for every clang invocation *)
let clang_blacklisted_flags = let clang_blacklisted_flags =
@ -49,7 +54,11 @@ let can_attach_ast_exporter cmd =
let is_supported_language cmd = let is_supported_language cmd =
match value_of_option cmd "-x" with match value_of_option cmd "-x" with
| None -> | 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 false
| Some lang when String.is_prefix ~prefix:"assembler" lang -> | Some lang when String.is_prefix ~prefix:"assembler" lang ->
false false
@ -58,9 +67,12 @@ let can_attach_ast_exporter cmd =
in in
(* -Eonly is -cc1 flag that gets produced by 'clang -M -### ...' *) (* -Eonly is -cc1 flag that gets produced by 'clang -M -### ...' *)
let is_preprocessor_only cmd = has_flag cmd "-E" || has_flag cmd "-Eonly" in 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_cons a b = a :: b
let argv_do_if cond action x = if cond then action x else x 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} 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 *) (* 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 blacklisted_flags_with_arg = ["-index-store-path"] in
let sanitized_args = let sanitized_args =
filter_and_replace_unsupported_args ~blacklisted_flags:clang_blacklisted_flags filter_and_replace_unsupported_args ~blacklisted_flags:clang_blacklisted_flags
~blacklisted_flags_with_arg args ~blacklisted_flags_with_arg args
in 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 = let to_unescaped_args cmd =

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

@ -13,7 +13,11 @@
open! IStd open! IStd
module L = Logging 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 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 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 (** Given a clang command, return a list of new commands to run according to the results of `clang
the results of `clang -### [args]`. *) -### [args]`. *)
let normalize ~prog ~args : action_item list = let clang_driver_action_items : ClangCommand.t -> action_item list =
let cmd = ClangCommand.mk ClangQuotes.SingleQuotes ~prog ~args in fun cmd ->
let clang_hashhashhash = let clang_hashhashhash =
Printf.sprintf "%s 2>&1" Printf.sprintf "%s 2>&1"
( ClangCommand.prepend_arg "-###" cmd ( ClangCommand.prepend_arg "-###" cmd
@ -77,14 +81,14 @@ let normalize ~prog ~args : action_item list =
let normalized_commands = ref [] in let normalized_commands = ref [] in
let one_line line = let one_line line =
if String.is_prefix ~prefix:" \"" line then if String.is_prefix ~prefix:" \"" line then
Command CanonicalCommand
( match ( match
(* massage line to remove edge-cases for splitting *) (* massage line to remove edge-cases for splitting *)
"\"" ^ line ^ " \"" |> (* split by whitespace *) "\"" ^ line ^ " \"" |> (* split by whitespace *)
Str.split (Str.regexp_string "\" \"") Str.split (Str.regexp_string "\" \"")
with with
| prog :: args -> | 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" ) L.(die InternalError) "ClangWrapper: argv cannot be empty" )
else if Str.string_match (Str.regexp "clang[^ :]*: warning: ") line 0 then ClangWarning line 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 !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 let exec_action_item ~prog ~args = function
| ClangError error -> | ClangError error ->
(* An error in the output of `clang -### ...`. Outputs the error and fail. This is because (* 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 *** Infer needs a working compilation command to run." prog Pp.cli_args args error
| ClangWarning warning -> | ClangWarning warning ->
L.external_warning "%s@\n" warning L.external_warning "%s@\n" warning
| Command clang_cmd -> | CanonicalCommand clang_cmd ->
Capture.capture 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 = let exe ~prog ~args =

Loading…
Cancel
Save