From eee940b2a1b2ed269898bf7ee1bae560570f755d Mon Sep 17 00:00:00 2001 From: Josh Berdine Date: Fri, 28 Oct 2016 12:57:56 -0700 Subject: [PATCH] [config] Convert FCP env vars to Config options Reviewed By: jvillard Differential Revision: D4074683 fbshipit-source-id: a3b3703 --- infer/lib/python/inferlib/capture/buck.py | 6 ++++- .../lib/python/inferlib/capture/xcodebuild.py | 6 ++++- infer/src/base/CommandLineOption.ml | 22 +++++++++++-------- infer/src/base/CommandLineOption.mli | 8 ++++++- infer/src/base/Config.ml | 15 ++++++++++--- infer/src/base/Config.mli | 2 ++ infer/src/clang/Capture.re | 7 ++++-- infer/src/clang/ClangCommand.re | 20 ++--------------- infer/src/clang/ClangWrapper.re | 6 ++--- .../integration/BuckCompilationDatabase.ml | 22 ++++++++++++++++--- 10 files changed, 73 insertions(+), 41 deletions(-) diff --git a/infer/lib/python/inferlib/capture/buck.py b/infer/lib/python/inferlib/capture/buck.py index 555dde5ff..62721e9bc 100644 --- a/infer/lib/python/inferlib/capture/buck.py +++ b/infer/lib/python/inferlib/capture/buck.py @@ -177,7 +177,11 @@ class BuckAnalyzer: 'is located') return os.EX_USAGE env_vars = utils.read_env() - env_vars['FCP_RUN_SYNTAX_ONLY'] = '1' + infer_args = env_vars['INFER_ARGS'] + if infer_args != '': + infer_args += '^' # '^' must be CommandLineOption.env_var_sep + infer_args += '--fcp-syntax-only' + env_vars['INFER_ARGS'] = infer_args env = utils.encode_env(env_vars) command = self.cmd command += ['-j', str(self.args.multicore)] diff --git a/infer/lib/python/inferlib/capture/xcodebuild.py b/infer/lib/python/inferlib/capture/xcodebuild.py index c9f2f4824..02fd05981 100644 --- a/infer/lib/python/inferlib/capture/xcodebuild.py +++ b/infer/lib/python/inferlib/capture/xcodebuild.py @@ -51,7 +51,11 @@ class XcodebuildCapture: def get_envvars(self): env_vars = utils.read_env() - env_vars['FCP_APPLE_CLANG'] = self.apple_clang_path + infer_args = env_vars['INFER_ARGS'] + if infer_args != '': + infer_args += '^' # '^' must be CommandLineOption.env_var_sep + infer_args += '--fcp-apple-clang^' + self.apple_clang_path + env_vars['INFER_ARGS'] = infer_args return env_vars def capture(self): diff --git a/infer/src/base/CommandLineOption.ml b/infer/src/base/CommandLineOption.ml index 7b1f85114..a39c7023a 100644 --- a/infer/src/base/CommandLineOption.ml +++ b/infer/src/base/CommandLineOption.ml @@ -439,21 +439,22 @@ let decode_inferconfig_to_argv current_exe path = IList.fold_left one_config_item [] json_config -(** [sep_char] is used to separate elements of argv when encoded into environment variables *) -let sep_char = '^' +(** separator of argv elements when encoded into environment variables *) +let env_var_sep = '^' let encode_argv_to_env argv = - String.concat (String.make 1 sep_char) + String.concat (String.make 1 env_var_sep) (IList.filter (fun arg -> - not (String.contains arg sep_char) + not (String.contains arg env_var_sep) || ( - F.eprintf "Ignoring unsupported option containing '%c' character: %s@\n" sep_char arg ; + F.eprintf "Ignoring unsupported option containing '%c' character: %s@\n" + env_var_sep arg ; false ) ) argv) let decode_env_to_argv env = - Str.split (Str.regexp_string (String.make 1 sep_char)) env + Str.split (Str.regexp_string (String.make 1 env_var_sep)) env let prepend_to_argv args = let cl_args = match Array.to_list Sys.argv with _ :: tl -> tl | [] -> [] in @@ -467,7 +468,10 @@ let prefix_before_rest args = prefix_before_rest_ [] args -let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var current_exe exe_usage = +(** environment variable use to pass arguments from parent to child processes *) +let args_env_var = "INFER_ARGS" + +let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file current_exe exe_usage = let curr_speclist = ref [] and full_speclist = ref [] in @@ -561,7 +565,7 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var curre ; full_speclist := add_or_suppress_help (normalize !full_desc_list) ; - let env_args = decode_env_to_argv (try Unix.getenv env_var with Not_found -> "") in + let env_args = decode_env_to_argv (try Unix.getenv args_env_var with Not_found -> "") in (* begin transitional support for INFERCLANG_ARGS *) let c_args = Str.split (Str.regexp_string (String.make 1 ':')) @@ -601,6 +605,6 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var curre in parse_loop (); if not incomplete then - Unix.putenv env_var + Unix.putenv args_env_var (encode_argv_to_env (prefix_before_rest (IList.tl (Array.to_list !args_to_parse)))) ; curr_usage diff --git a/infer/src/base/CommandLineOption.mli b/infer/src/base/CommandLineOption.mli index 78ffa4743..25c526cff 100644 --- a/infer/src/base/CommandLineOption.mli +++ b/infer/src/base/CommandLineOption.mli @@ -103,6 +103,12 @@ val mk_rest : ?exes:exe list -> string -> string list ref +(** environment variable use to pass arguments from parent to child processes *) +val args_env_var : string + +(** separator of argv elements when encoded into environment variables *) +val env_var_sep : char + (** [parse env_var exe_usage exe] parses command line arguments as specified by preceding calls to the [mk_*] functions, and returns a function that prints the usage message and help text then exits. [exe] is used to construct the help message appropriate for that executable. The decoded @@ -115,4 +121,4 @@ val mk_rest : and [env_var] is not set. If [accept_unknown] is set, unknown options are treated the same as anonymous arguments. *) val parse : ?incomplete:bool -> ?accept_unknown:bool -> ?config_file:string -> - string -> exe -> (exe -> Arg.usage_msg) -> (int -> 'a) + exe -> (exe -> Arg.usage_msg) -> (int -> 'a) diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index e2b7edcd3..c907c61e1 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -438,7 +438,7 @@ and project_root = (* Parse the phase 1 options, ignoring the rest *) -let _ = CLOpt.parse ~incomplete:true "INFER_ARGS" current_exe (fun _ -> "") +let _ = CLOpt.parse ~incomplete:true current_exe (fun _ -> "") (* Define the values that depend on phase 1 options *) @@ -842,6 +842,14 @@ and failures_allowed = CLOpt.mk_bool ~deprecated_no:["-no_failures_allowed"] ~long:"failures-allowed" ~default:true "Fail if at least one of the translations fails (clang only)" +and fcp_apple_clang = + CLOpt.mk_string_opt ~long:"fcp-apple-clang" + ~meta:"path" "Specify the path to Apple Clang" + +and fcp_syntax_only = + CLOpt.mk_bool ~long:"fcp-syntax-only" + "Skip creation of object files" + and filter_paths = CLOpt.mk_bool ~long:"filter-paths" ~default:true "Filters specified in .inferconfig" @@ -1399,8 +1407,7 @@ let post_parsing_initialization () = let parse_args_and_return_usage_exit = let usage_exit = - CLOpt.parse ~accept_unknown:true ~config_file:inferconfig_path - "INFER_ARGS" current_exe exe_usage in + CLOpt.parse ~accept_unknown:true ~config_file:inferconfig_path current_exe exe_usage in post_parsing_initialization () ; usage_exit @@ -1486,6 +1493,8 @@ and eradicate_verbose = !eradicate_verbose and err_file_cmdline = !err_file and fail_on_bug = !fail_on_bug and failures_allowed = !failures_allowed +and fcp_apple_clang = !fcp_apple_clang +and fcp_syntax_only = !fcp_syntax_only and filter_paths = !filter_paths and filtering = !filtering and flavors = !flavors diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index e9de74aaa..8b7962004 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -194,6 +194,8 @@ val eradicate_verbose : bool val err_file_cmdline : string val fail_on_bug : bool val failures_allowed : bool +val fcp_apple_clang : string option +val fcp_syntax_only : bool val filter_paths : bool val filtering : bool val flavors : bool diff --git a/infer/src/clang/Capture.re b/infer/src/clang/Capture.re index 2527ff23e..5bdb49fa2 100644 --- a/infer/src/clang/Capture.re +++ b/infer/src/clang/Capture.re @@ -8,6 +8,8 @@ */ open! Utils; +let module CLOpt = CommandLineOption; + /** this fails the execution of clang if the frontend fails */ let report_frontend_failure = not Config.failures_allowed; @@ -113,7 +115,7 @@ let run_plugin_and_frontend frontend clang_args => { "^" ( ( - try [Unix.getenv "INFER_ARGS"] { + try [Unix.getenv CLOpt.args_env_var] { | Not_found => [] } ) @ [ @@ -123,7 +125,8 @@ let run_plugin_and_frontend frontend clang_args => { ); Format.fprintf debug_script_fmt - "INFER_ARGS=\"%s\" %s@\n" + "%s=\"%s\" %s@\n" + CLOpt.args_env_var infer_clang_options (ClangCommand.with_exec Sys.executable_name clang_args |> ClangCommand.command_to_run); Format.fprintf diff --git a/infer/src/clang/ClangCommand.re b/infer/src/clang/ClangCommand.re index 3dbbc3908..7d1f9c654 100644 --- a/infer/src/clang/ClangCommand.re +++ b/infer/src/clang/ClangCommand.re @@ -31,29 +31,13 @@ let fcp_dir = /** path of the plugin to load in clang */ let plugin_path = fcp_dir /\/ "libtooling" /\/ "build" /\/ "FacebookClangPlugin.dylib"; -let test_env_var var => - switch (Sys.getenv var) { - | "1" => true - | _ => false - | exception Not_found => false - }; - /** name of the plugin to use */ let plugin_name = "BiniouASTExporter"; -/** this skips the creation of .o files */ -let syntax_only = test_env_var "FCP_RUN_SYNTAX_ONLY"; - - /** are we running as Apple's clang? */ -let has_apple_clang = - switch (Sys.getenv "FCP_APPLE_CLANG") { - | bin when bin != "" => true - | _ => false - | exception Not_found => false - }; +let has_apple_clang = Config.fcp_apple_clang != None; /** whether to amend include search path with C++ model headers */ @@ -193,7 +177,7 @@ let with_plugin_args args => { "-plugin-arg-" ^ plugin_name, "PREPEND_CURRENT_DIR=1" ]; - let args_after = [] |> do_if syntax_only (cons "-fsyntax-only"); + let args_after = [] |> do_if Config.fcp_syntax_only (cons "-fsyntax-only"); {...args, argv: IList.rev_append rev_args_before (args.argv @ args_after)} }; diff --git a/infer/src/clang/ClangWrapper.re b/infer/src/clang/ClangWrapper.re index 0a828ba14..8fdbba0e8 100644 --- a/infer/src/clang/ClangWrapper.re +++ b/infer/src/clang/ClangWrapper.re @@ -116,13 +116,13 @@ let exe args xx_suffix => { /* xcodebuild projects may require the object files to be generated by the Apple compiler, eg to generate precompiled headers compatible with Apple's clang. */ let should_run_original_command = - switch (Sys.getenv "FCP_APPLE_CLANG") { - | bin => + switch Config.fcp_apple_clang { + | Some bin => let bin_xx = bin ^ xx_suffix; Logging.out "Will run Apple clang %s" bin_xx; args.(0) = bin_xx; true - | exception Not_found => false + | None => false }; IList.iter execute_clang_command commands; if (commands == [] || should_run_original_command) { diff --git a/infer/src/integration/BuckCompilationDatabase.ml b/infer/src/integration/BuckCompilationDatabase.ml index 37a252a47..8077b0095 100644 --- a/infer/src/integration/BuckCompilationDatabase.ml +++ b/infer/src/integration/BuckCompilationDatabase.ml @@ -9,6 +9,9 @@ open! Utils +module CLOpt = CommandLineOption +module F = Format + let capture_text = if Config.analyzer = Some Config.Linters then "linting" else "translating" @@ -89,9 +92,22 @@ let run_compilation_file compilation_database file = ClangQuotes.mk_arg_file "cdb_clang_args_" ClangQuotes.EscapedNoQuotes [compilation_data.args] in let args = Array.of_list [wrapper_cmd; "@" ^ arg_file] in - let env = Array.append - (Unix.environment()) - (Array.of_list ["FCP_RUN_SYNTAX_ONLY=1"]) in + let env = + let env0 = Unix.environment () in + let found = ref false in + Array.iteri (fun i key_val -> + match string_split_character key_val '=' with + | Some var, args when string_equal var CLOpt.args_env_var -> + found := true ; + env0.(i) <- + F.sprintf "%s=%s%c--fcp-syntax-only" CLOpt.args_env_var args CLOpt.env_var_sep + | _ -> + () + ) env0 ; + if !found then + env0 + else + Array.append env0 [|CLOpt.args_env_var ^ "=--fcp-syntax-only"|] in (Some compilation_data.dir, wrapper_cmd, args, env) with Not_found -> Process.print_error_and_exit "Failed to find compilation data for %s \n%!" file