[clang] blacklist some flags at the -### level

Summary: `clang -### ...` is allergic to a few flags.

Reviewed By: mbouaziz

Differential Revision: D6736820

fbshipit-source-id: d9b0e3c
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 26d1bb0ff4
commit 1d4128e0c0

@ -771,18 +771,6 @@ let mk_subcommand command ?on_unknown_arg:(on_unknown = `Reject) ~name ?deprecat
subcommand_actions := (name, switch) :: !subcommand_actions subcommand_actions := (name, switch) :: !subcommand_actions
(* drop well-balanced first and last characters in [s] that satisfy the [drop] predicate; for
instance, [lrstrip ~drop:(function | 'a' | 'x' -> true | _ -> false) "xaabax"] returns "ab" *)
let rec lrstrip ~drop s =
let n = String.length s in
if n < 2 then s
else
let first = String.unsafe_get s 0 in
if Char.equal first (String.unsafe_get s (n - 1)) && drop first then
lrstrip ~drop (String.slice s 1 (n - 1))
else s
let args_from_argfile arg = let args_from_argfile arg =
let abs_fname = let abs_fname =
let fname = String.slice arg 1 (String.length arg) in let fname = String.slice arg 1 (String.length arg) in
@ -790,7 +778,7 @@ let args_from_argfile arg =
in in
match In_channel.read_lines abs_fname with match In_channel.read_lines abs_fname with
| lines -> | lines ->
let strip = lrstrip ~drop:(function '"' | '\'' -> true | _ -> false) in let strip = Utils.strip_balanced_once ~drop:(function '"' | '\'' -> true | _ -> false) in
List.map ~f:strip lines List.map ~f:strip lines
| exception e -> | exception e ->
raise (Arg.Bad ("Error reading argument file '" ^ abs_fname ^ "': " ^ Exn.to_string e)) raise (Arg.Bad ("Error reading argument file '" ^ abs_fname ^ "': " ^ Exn.to_string e))

@ -364,3 +364,15 @@ let better_hash x = Marshal.to_string x [Marshal.No_sharing] |> Caml.Digest.stri
let unlink_file_on_exit temp_file = let unlink_file_on_exit temp_file =
"Cleaning temporary file " ^ temp_file "Cleaning temporary file " ^ temp_file
|> Epilogues.register ~f:(fun () -> try Unix.unlink temp_file with _ -> ()) |> Epilogues.register ~f:(fun () -> try Unix.unlink temp_file with _ -> ())
(** drop at most one layer of well-balanced first and last characters satisfying [drop] from the
string; for instance, [strip_balanced ~drop:(function | 'a' | 'x' -> true | _ -> false) "xaabax"]
returns "aaba" *)
let strip_balanced_once ~drop s =
let n = String.length s in
if n < 2 then s
else
let first = String.unsafe_get s 0 in
if Char.equal first (String.unsafe_get s (n - 1)) && drop first then String.slice s 1 (n - 1)
else s

@ -110,3 +110,8 @@ val better_hash : 'a -> Caml.Digest.t
val unlink_file_on_exit : string -> unit val unlink_file_on_exit : string -> unit
(** delete [temporary] file on exit *) (** delete [temporary] file on exit *)
val strip_balanced_once : drop:(char -> bool) -> string -> string
(** drop at most one layer of well-balanced first and last characters satisfying [drop] from the
string; for instance, [strip_balanced ~drop:(function | 'a' | 'x' -> true | _ -> false) "xaabax"]
returns "aaba" *)

@ -12,6 +12,9 @@ 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}
(** bad for every clang invocation *)
let clang_blacklisted_flags = ["-fembed-bitcode-marker"; "-fno-canonical-system-headers"]
let fcp_dir = let fcp_dir =
Config.bin_dir ^/ Filename.parent_dir_name ^/ Filename.parent_dir_name Config.bin_dir ^/ Filename.parent_dir_name ^/ Filename.parent_dir_name
^/ "facebook-clang-plugins" ^/ "facebook-clang-plugins"
@ -67,22 +70,54 @@ let file_arg_cmd_sanitizer cmd =
let include_override_regex = Option.map ~f:Str.regexp Config.clang_include_to_override_regex let include_override_regex = Option.map ~f:Str.regexp Config.clang_include_to_override_regex
let filter_and_replace_unsupported_args ?(replace_option_arg= fun _ s -> s) (** Filter arguments from [args], looking into argfiles too. [replace_options_arg prev arg] returns
[arg'], where [arg'] is the new version of [arg] given the preceding arguments (in reverse order) [prev]. *)
let filter_and_replace_unsupported_args ?(replace_options_arg= fun _ s -> s)
?(blacklisted_flags= []) ?(blacklisted_flags_with_arg= []) ?(post_args= []) args = ?(blacklisted_flags= []) ?(blacklisted_flags_with_arg= []) ?(post_args= []) args =
let rec aux (prev, res_rev) args = (* [prev] is the previously seen argument, [res_rev] is the reversed result, [changed] is true if
some change has been performed *)
let rec aux (prev_is_blacklisted_with_arg, res_rev, changed) args =
match args with match args with
| [] -> | [] ->
(* return non-reversed list *) (prev_is_blacklisted_with_arg, res_rev, changed)
List.rev_append res_rev post_args | _ :: tl when prev_is_blacklisted_with_arg ->
(* in the unlikely event that a blacklisted flag with arg sits as the last option in some
arg file, we need to remove its argument now *)
aux (false, res_rev, true) tl
| at_argfile :: tl when String.is_prefix at_argfile ~prefix:"@"
-> (
let argfile = String.slice at_argfile 1 (String.length at_argfile) in
match In_channel.read_lines argfile with
| lines ->
(* poor parsing of arguments with some stripping supported; hope that tools generating
argfiles more or less put one argument per line *)
let strip s =
String.strip s
|> Utils.strip_balanced_once ~drop:(function '"' | '\'' -> true | _ -> false)
in
let last_in_file_is_blacklisted, rev_res_with_file_args, changed_file =
List.map ~f:strip lines |> aux (prev_is_blacklisted_with_arg, res_rev, false)
in
if changed_file then aux (last_in_file_is_blacklisted, rev_res_with_file_args, true) tl
else
(* keep the same argfile if we haven't needed to change anything in it *)
aux (last_in_file_is_blacklisted, at_argfile :: res_rev, changed) tl
| exception e ->
L.external_warning "Error reading argument file '%s': %s@\n" at_argfile
(Exn.to_string e) ;
aux (false, at_argfile :: res_rev, changed) tl )
| flag :: tl when List.mem ~equal:String.equal blacklisted_flags flag -> | flag :: tl when List.mem ~equal:String.equal blacklisted_flags flag ->
aux (flag, res_rev) tl aux (false, res_rev, true) tl
| flag1 :: flag2 :: tl when List.mem ~equal:String.equal blacklisted_flags_with_arg flag1 -> | flag :: tl when List.mem ~equal:String.equal blacklisted_flags_with_arg flag ->
aux (flag2, res_rev) tl (* remove the flag and its arg separately in case we are at the end of an argfile *)
aux (true, res_rev, true) tl
| arg :: tl -> | arg :: tl ->
let res_rev' = replace_option_arg prev arg :: res_rev in let arg' = replace_options_arg res_rev arg in
aux (arg, res_rev') tl aux (false, arg' :: res_rev, changed || not (phys_equal arg arg')) tl
in in
aux ("", []) args match aux (false, [], false) args with _, res_rev, _ ->
(* return non-reversed list *)
List.rev_append res_rev post_args
(* Work around various path or library issues occurring when one tries to substitute Apple's version (* Work around various path or library issues occurring when one tries to substitute Apple's version
@ -90,26 +125,29 @@ let filter_and_replace_unsupported_args ?(replace_option_arg= fun _ s -> s)
fatal warnings. *) fatal warnings. *)
let clang_cc1_cmd_sanitizer cmd = let clang_cc1_cmd_sanitizer cmd =
(* command line options not supported by the opensource compiler or the plugins *) (* command line options not supported by the opensource compiler or the plugins *)
let blacklisted_flags = ["-fembed-bitcode-marker"; "-fno-canonical-system-headers"] in
let blacklisted_flags_with_arg = ["-mllvm"] in let blacklisted_flags_with_arg = ["-mllvm"] in
let replace_option_arg option arg = let replace_options_arg options arg =
if String.equal option "-arch" && String.equal arg "armv7k" then "armv7" match options with
(* replace armv7k arch with armv7 *) | option :: _ ->
else if String.is_suffix arg ~suffix:"dep.tmp" then ( if String.equal option "-arch" && String.equal arg "armv7k" then "armv7"
(* compilation-database Buck integration produces path to `dep.tmp` file that doesn't exist. Create it *) (* replace armv7k arch with armv7 *)
Unix.mkdir_p (Filename.dirname arg) ; else if String.is_suffix arg ~suffix:"dep.tmp" then (
arg ) (* compilation-database Buck integration produces path to `dep.tmp` file that doesn't exist. Create it *)
else if String.equal option "-dependency-file" Unix.mkdir_p (Filename.dirname arg) ;
&& Option.is_some Config.buck_compilation_database arg )
(* In compilation database mode, dependency files are not assumed to exist *) else if String.equal option "-dependency-file"
then "/dev/null" && Option.is_some Config.buck_compilation_database
else if String.equal option "-isystem" then (* In compilation database mode, dependency files are not assumed to exist *)
match include_override_regex with then "/dev/null"
| Some regexp when Str.string_match regexp arg 0 -> else if String.equal option "-isystem" then
fcp_dir ^/ "clang" ^/ "install" ^/ "lib" ^/ "clang" ^/ "5.0.0" ^/ "include" match include_override_regex with
| _ -> | Some regexp when Str.string_match regexp arg 0 ->
arg fcp_dir ^/ "clang" ^/ "install" ^/ "lib" ^/ "clang" ^/ "5.0.0" ^/ "include"
else arg | _ ->
arg
else arg
| [] ->
arg
in in
let args_defines = let args_defines =
if Config.bufferoverrun && not Config.biabduction then ["-D__INFER_BUFFEROVERRUN"] else [] if Config.bufferoverrun && not Config.biabduction then ["-D__INFER_BUFFEROVERRUN"] else []
@ -124,8 +162,8 @@ let clang_cc1_cmd_sanitizer cmd =
argv_cons "-Wno-everything" argv_cons "-Wno-everything"
in in
let clang_arguments = let clang_arguments =
filter_and_replace_unsupported_args ~blacklisted_flags ~blacklisted_flags_with_arg filter_and_replace_unsupported_args ~blacklisted_flags:clang_blacklisted_flags
~replace_option_arg ~post_args:(List.rev post_args_rev) cmd.argv ~blacklisted_flags_with_arg ~replace_options_arg ~post_args:(List.rev post_args_rev) cmd.argv
in in
file_arg_cmd_sanitizer {cmd with argv= clang_arguments} file_arg_cmd_sanitizer {cmd with argv= clang_arguments}
@ -133,7 +171,10 @@ let clang_cc1_cmd_sanitizer cmd =
let mk quoting_style ~prog ~args = let mk 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 = filter_and_replace_unsupported_args ~blacklisted_flags_with_arg args 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}

Loading…
Cancel
Save