From 343556e0b25c0ad52abfc9432b502a055f32ee95 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Mon, 17 Oct 2016 06:46:17 -0700 Subject: [PATCH] [base] resolve links when guessing which executable we are running, move infer into bin/ Summary: There's no reason for infer to be in lib/ anymore, move it to the same place as the other binaries. Thus all binaries are in the same directory and Config.ml can better know where things are. Reviewed By: jberdine Differential Revision: D4015958 fbshipit-source-id: c5e851f --- .gitignore | 1 - Makefile | 16 +++--------- Makefile.config.in | 4 +-- infer/src/backend/infer.ml | 21 +-------------- infer/src/base/CommandLineOption.ml | 15 +++-------- infer/src/base/CommandLineOption.mli | 28 ++++++++++---------- infer/src/base/Config.ml | 39 +++++++++++++++++++++++----- infer/src/base/Config.mli | 3 ++- infer/src/base/Logging.ml | 4 +-- 9 files changed, 61 insertions(+), 70 deletions(-) diff --git a/.gitignore b/.gitignore index c63b6e86a..b5764daeb 100644 --- a/.gitignore +++ b/.gitignore @@ -71,7 +71,6 @@ buck-out/ /infer/bin/InferUnit /infer/bin/Typeprop /infer/bin/infer -/infer/lib/infer /infer/bin/inferTraceBugs /infer/src/base/Version.ml /infer/models/java/models/ diff --git a/Makefile b/Makefile index 211230826..1d7f14fcb 100644 --- a/Makefile +++ b/Makefile @@ -29,11 +29,6 @@ endif all: infer inferTraceBugs -$(INFER_BIN_SYMLINK): - ($(REMOVE) $@ && \ - cd $(@D) && \ - $(LN_S) ../lib/$(@F) $(@F)) - $(INFERTRACEBUGS_BIN_RELPATH): ($(REMOVE) $@ && \ cd $(@D) && \ @@ -48,7 +43,7 @@ ifeq ($(BUILD_C_ANALYZERS),yes) src_build: clang_plugin endif -infer: $(INFER_BIN_SYMLINK) src_build +infer: src_build ifeq ($(BUILD_JAVA_ANALYZERS),yes) $(MAKE) -C $(ANNOTATIONS_DIR) endif @@ -303,16 +298,13 @@ endif $(DESTDIR)$(libdir)/infer/infer/lib/python/infer.py $(INSTALL_PROGRAM) -C infer/lib/python/inferTraceBugs \ $(DESTDIR)$(libdir)/infer/infer/lib/python/inferTraceBugs - $(INSTALL_PROGRAM) -C $(INFER_BIN) $(DESTDIR)$(libdir)/infer/infer/lib/ + $(INSTALL_PROGRAM) -C $(INFER_BIN) $(DESTDIR)$(libdir)/infer/infer/bin/ $(INSTALL_PROGRAM) -C $(INFERANALYZE_BIN) $(DESTDIR)$(libdir)/infer/infer/bin/ $(INSTALL_PROGRAM) -C $(INFERPRINT_BIN) $(DESTDIR)$(libdir)/infer/infer/bin/ $(INSTALL_PROGRAM) -C $(INFERSTATS_BIN) $(DESTDIR)$(libdir)/infer/infer/bin/ - (cd $(DESTDIR)$(libdir)/infer/infer/bin/ && \ - $(REMOVE) infer && \ - $(LN_S) $(libdir)/infer/infer/lib/infer infer) (cd $(DESTDIR)$(bindir)/ && \ $(REMOVE) infer && \ - $(LN_S) $(libdir)/infer/infer/lib/infer infer) + $(LN_S) $(libdir)/infer/infer/bin/infer infer) (cd $(DESTDIR)$(bindir)/ && \ $(REMOVE) inferTraceBugs && \ $(LN_S) $(libdir)/infer/infer/lib/python/inferTraceBugs inferTraceBugs) @@ -332,7 +324,7 @@ endif $(MAKE) -C $(SRC_DIR) clean $(MAKE) -C $(ANNOTATIONS_DIR) clean $(MAKE) -C $(MODELS_DIR) clean - $(REMOVE) $(INFER_BIN_SYMLINK) $(INFERTRACEBUGS_BIN_RELPATH) + $(REMOVE) $(INFERTRACEBUGS_BIN_RELPATH) ifeq ($(IS_FACEBOOK_TREE),yes) $(MAKE) -C facebook clean endif diff --git a/Makefile.config.in b/Makefile.config.in index 2df66d433..4974a98ee 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -99,10 +99,8 @@ INFERSTATS_BIN = $(BIN_DIR)/InferStatsAggregator INFERPRINT_BIN = $(BIN_DIR)/InferPrint INFERUNIT_BIN = $(BIN_DIR)/InferUnit INFER_BUCK_COMPILATION_DATABASE_BIN = $(BIN_DIR)/InferBuckCompilationDatabase -INFER_BIN = $(LIB_DIR)/infer +INFER_BIN = $(BIN_DIR)/infer INFERTRACEBUGS_BIN = $(BIN_DIR)/inferTraceBugs -# paths relative to $(ROOT_DIR) -INFER_BIN_SYMLINK = infer/bin/infer INFERTRACEBUGS_BIN_RELPATH = infer/bin/inferTraceBugs ifeq ($(BUILD_JAVA_ANALYZERS),yes) diff --git a/infer/src/backend/infer.ml b/infer/src/backend/infer.ml index e91c09c8d..c3ed653bf 100644 --- a/infer/src/backend/infer.ml +++ b/infer/src/backend/infer.ml @@ -29,26 +29,7 @@ let fail_on_issue_epilogue () = let () = set_env_for_clang_wrapper () ; - (* The infer executable in the bin directory is a symbolic link to the real binary in the lib - directory, so that the python script in the lib directory can be found relative to - it. Packaging may also create longer symlink chains to the real executable, hence the - recursion. *) - let real_exe = - let rec real_path path = - match Unix.readlink path with - | link when Filename.is_relative link -> - (* [path] is a relative symbolic link *) - real_path ((Filename.dirname path) // link) - | link -> - (* [path] is an absolute symbolic link *) - real_path link - | exception Unix.Unix_error(Unix.EINVAL, _, _) -> - (* [path] is not a symbolic link *) - path - in - real_path Sys.executable_name - in - let infer_py = (Filename.dirname real_exe) // "python" // "infer.py" in + let infer_py = Config.lib_dir // "python" // "infer.py" in let build_cmd = IList.rev Config.rest in let in_buck_mode = match build_cmd with "buck" :: _ -> true | _ -> false in let args_py = diff --git a/infer/src/base/CommandLineOption.ml b/infer/src/base/CommandLineOption.ml index 8368cfa82..7b1f85114 100644 --- a/infer/src/base/CommandLineOption.ml +++ b/infer/src/base/CommandLineOption.ml @@ -21,6 +21,7 @@ type exe = Analyze | BuckCompilationDatabase | Clang | Interactive | Java | Prin | Toplevel +(** Association list of executable (base)names to their [exe]s. *) let exes = [ ("InferBuckCompilationDatabase", BuckCompilationDatabase); ("InferAnalyze", Analyze); @@ -32,16 +33,8 @@ let exes = [ ("interactive", Interactive); ] -let all_exes = IList.map snd exes - let frontend_exes = [Clang; Java] -let current_exe = - if !Sys.interactive then Interactive - else - try IList.assoc string_equal (Filename.basename Sys.executable_name) exes - with Not_found -> Toplevel - type desc = { long: string; short: string; meta: string; doc: string; spec: Arg.spec; (** how to go from an option in the json config file to a list of command-line options *) @@ -418,7 +411,7 @@ let mk_rest ?(exes=[]) doc = add exes {long = "--"; short = ""; meta = ""; doc; spec; decode_json = fun _ -> []} ; rest -let decode_inferconfig_to_argv path = +let decode_inferconfig_to_argv current_exe path = let json = match read_optional_json_file path with | Ok json -> json @@ -474,7 +467,7 @@ let prefix_before_rest args = prefix_before_rest_ [] args -let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var exe_usage = +let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var current_exe exe_usage = let curr_speclist = ref [] and full_speclist = ref [] in @@ -585,7 +578,7 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var exe_u let all_args = match config_file with | None -> env_cl_args | Some path -> - let json_args = decode_inferconfig_to_argv path in + let json_args = decode_inferconfig_to_argv current_exe path in (* read .inferconfig first, as both env vars and command-line options overwrite it *) json_args @ env_cl_args in args_to_parse := Array.of_list (exe_name :: all_args); diff --git a/infer/src/base/CommandLineOption.mli b/infer/src/base/CommandLineOption.mli index 5ab265af5..78ffa4743 100644 --- a/infer/src/base/CommandLineOption.mli +++ b/infer/src/base/CommandLineOption.mli @@ -14,9 +14,8 @@ open! Utils type exe = Analyze | BuckCompilationDatabase | Clang | Interactive | Java | Print | StatsAggregator | Toplevel -val current_exe : exe - -val all_exes : exe list +(** Association list of executable (base)names to their [exe]s. *) +val exes : (string * exe) list val frontend_exes: exe list @@ -104,15 +103,16 @@ val mk_rest : ?exes:exe list -> string -> string list ref -(** [parse env_var exe_usage] 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. - The decoded values of the inferconfig file [config_file], if provided, and of the environment - variable [env_var] are prepended to [Sys.argv] before parsing. Therefore arguments passed on - the command line supersede those specified in the environment variable, which themselves - supersede those passed via the config file. WARNING: An argument will be interpreted as many - times as it appears in all of the config file, the environment variable, and the command - line. The [env_var] is set to the full set of options parsed. If [incomplete] is set, unknown - options are ignored, and [env_var] is not set. If [accept_unknown] is set, unknown options are - treated the same as anonymous arguments. *) +(** [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 + values of the inferconfig file [config_file], if provided, and of the environment variable + [env_var] are prepended to [Sys.argv] before parsing. Therefore arguments passed on the command + line supersede those specified in the environment variable, which themselves supersede those + passed via the config file. WARNING: An argument will be interpreted as many times as it + appears in all of the config file, the environment variable, and the command line. The [env_var] + is set to the full set of options parsed. If [incomplete] is set, unknown options are ignored, + 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 -> Arg.usage_msg) -> (int -> 'a) + string -> exe -> (exe -> Arg.usage_msg) -> (int -> 'a) diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index a0d40998a..fe7eabe9f 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -239,8 +239,33 @@ let version_string = Unix.time *) let initial_analysis_time = Unix.time () + +(* Resolve symlinks to get to the real executable. The real executable is located in [bin_dir] + below, which allows us to find [lib_dir], [models_dir], etc., relative to it. *) +let real_exe_name = + (* Recursively resolve symlinks until we get something that is not a link. Executables may be + (multiple levels of) symbolic links to the real binary directory, eg after `make install` or + packaging. *) + let rec real_path path = + match Unix.readlink path with + | link when Filename.is_relative link -> + (* [path] is a relative symbolic link *) + real_path ((Filename.dirname path) // link) + | link -> + (* [path] is an absolute symbolic link *) + real_path link + | exception Unix.Unix_error(Unix.EINVAL, _, _) -> + (* [path] is not a symbolic link *) + path in + real_path Sys.executable_name + +let current_exe = + if !Sys.interactive then CLOpt.Interactive + else try IList.assoc string_equal (Filename.basename real_exe_name) CLOpt.exes + with Not_found -> CLOpt.Toplevel + let bin_dir = - Filename.dirname Sys.executable_name + Filename.dirname real_exe_name let lib_dir = bin_dir // Filename.parent_dir_name // "lib" @@ -407,8 +432,9 @@ let resolve path = (* Declare the phase 1 options *) let inferconfig_home = + let all_exes = IList.map snd CLOpt.exes in CLOpt.mk_string_opt ~deprecated:["inferconfig_home"] ~long:"inferconfig-home" - ~exes:CLOpt.all_exes ~meta:"dir" "Path to the .inferconfig file" + ~exes:all_exes ~meta:"dir" "Path to the .inferconfig file" and project_root = CLOpt.mk_string_opt ~deprecated:["project_root"; "-project_root"] ~long:"project-root" ~short:"pr" @@ -420,7 +446,7 @@ and project_root = (* Parse the phase 1 options, ignoring the rest *) -let _ = CLOpt.parse ~incomplete:true "INFER_ARGS" (fun _ -> "") +let _ = CLOpt.parse ~incomplete:true "INFER_ARGS" current_exe (fun _ -> "") (* Define the values that depend on phase 1 options *) @@ -691,7 +717,7 @@ and cxx_experimental = and debug, print_types, write_dotty = let print_types = CLOpt.mk_bool ~deprecated:["print_types"] ~long:"print-types" - ~default:(CLOpt.current_exe = CLOpt.Clang) + ~default:(current_exe = CLOpt.Clang) "Print types in symbolic heaps" and write_dotty = CLOpt.mk_bool ~deprecated:["dotty"] ~long:"write-dotty" @@ -717,7 +743,7 @@ and dependencies = and developer_mode = CLOpt.mk_bool ~deprecated:["developer_mode"] ~long:"developer-mode" - ~default:(CLOpt.current_exe = CLOpt.Print) + ~default:(current_exe = CLOpt.Print) "Show internal exceptions" and disable_checks = @@ -1351,7 +1377,8 @@ 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" exe_usage in + CLOpt.parse ~accept_unknown:true ~config_file:inferconfig_path + "INFER_ARGS" current_exe exe_usage in post_parsing_initialization () ; usage_exit diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 2a7bba59d..2f1cebec1 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -67,10 +67,10 @@ val buck_generated_folder : string val buck_infer_deps_file_name : string val captured_dir_name : string val checks_disabled_by_default : string list -val report_condition_always_true_in_clang : bool val clang_build_output_dir_name : string val cpp_models_dir : string val csl_analysis : bool +val current_exe : CommandLineOption.exe val default_failure_name : string val default_in_zip_results_dir : string val dotty_output : string @@ -108,6 +108,7 @@ val patterns_suppress_warnings : pattern list val perf_stats_prefix : string val proc_stats_filename : string val property_attributes : string +val report_condition_always_true_in_clang : bool val report_nullable_inconsistency : bool val reporting_stats_dir_name : string val save_compact_summaries : bool diff --git a/infer/src/base/Logging.ml b/infer/src/base/Logging.ml index d021952ad..2791530f0 100644 --- a/infer/src/base/Logging.ml +++ b/infer/src/base/Logging.ml @@ -17,7 +17,7 @@ module F = Format (** Name of dir for logging the output in the specific executable *) let log_dir_of_current_exe = - match CommandLineOption.current_exe with + match Config.current_exe with | Analyze -> "analyze" | BuckCompilationDatabase -> "buck_compilation_database" | Clang -> "clang" @@ -37,7 +37,7 @@ let err_formatter = ref F.err_formatter let set_log_file_identifier string_opt = let should_setup_log_files = - match CommandLineOption.current_exe with + match Config.current_exe with | Analyze | Clang -> Config.debug_mode || Config.stats_mode | BuckCompilationDatabase -> true