From 346c89c71748281dd38042226ebb97348516bcf7 Mon Sep 17 00:00:00 2001 From: Artem Pianykh Date: Wed, 24 Jul 2019 07:51:46 -0700 Subject: [PATCH] Make infer binary runnable on Mojave without fiddling with SDKROOT Summary: TL;DR: Until this patch, if you ran infer on MacOS Mojave you most likely would get an error related to missing header files. Now infer tries to automatically locate current MacOS SDK path thus providing a better experience for first time users. Consider helloworld.c ``` #include int main() { return 0; } ``` Invoking the analysis `infer -- cc -c helloworld.c` fails with facebook-clang-plugins/.../include/c++/v1/stdio.h:108:15: fatal error: 'stdio.h' file not found The reason for this is twofold: 1. infer uses its own clang, not Apple's one (thus custom paths are not properly setup). 2. Apple stopped copying standard headers from SDK to /usr/include. Reviewed By: jvillard Differential Revision: D16377866 fbshipit-source-id: c336ad64f --- Makefile.autoconf.in | 1 + configure.ac | 29 ++++++++++++++++++++---- infer/src/Makefile | 1 + infer/src/base/Config.ml | 39 +++++++++++++++++++++++++++++++++ infer/src/base/Config.mli | 2 ++ infer/src/base/Version.ml.in | 4 ++++ infer/src/base/Version.mli | 4 ++++ infer/src/clang/ClangCommand.ml | 17 +++++++++++--- 8 files changed, 90 insertions(+), 7 deletions(-) diff --git a/Makefile.autoconf.in b/Makefile.autoconf.in index ca7eb227e..549a6f9e0 100644 --- a/Makefile.autoconf.in +++ b/Makefile.autoconf.in @@ -11,6 +11,7 @@ bindir = @bindir@ BUCK = @BUCK@ BUILD_C_ANALYZERS = @BUILD_C_ANALYZERS@ BUILD_JAVA_ANALYZERS = @BUILD_JAVA_ANALYZERS@ +BUILD_PLATFORM = @BUILD_PLATFORM@ CAML_LD_LIBRARY_PATH = @CAML_LD_LIBRARY_PATH@ CC = @CC@ CFLAGS = @CFLAGS@ diff --git a/configure.ac b/configure.ac index 80912343b..d6cb32bfa 100644 --- a/configure.ac +++ b/configure.ac @@ -49,16 +49,37 @@ AS_IF([test "x$CLANG_INCLUDES" = "x"], [ CLANG_INCLUDES="$CLANG_PREFIX/include" ]) -windows_build=no -AC_MSG_CHECKING([for Windows build]) +BUILD_PLATFORM=unknown +WINDOWS_BUILD=no +AC_MSG_CHECKING([for build platform]) # see https://stackoverflow.com/questions/714100/os-detecting-makefile # but we do this in the configure for homogeneity case "${OS}" in Windows_NT*) - windows_build=yes + BUILD_PLATFORM=Windows ;; + *) + uname_str=`uname -s` + case "${uname_str}" in + Linux*) + BUILD_PLATFORM=Linux + ;; + Darwin*) + BUILD_PLATFORM=Darwin + ;; + cygwin*|mingw*) + BUILD_PLATFORM=Windows + ;; + *) + AC_MSG_ERROR(["OS $unamestr is not supported"]) + ;; + esac esac -WINDOWS_BUILD=$windows_build +AC_MSG_RESULT([$BUILD_PLATFORM]) +AC_SUBST([BUILD_PLATFORM]) + +AC_MSG_CHECKING([for Windows build]) +AS_IF([test x"$BUILD_PLATFORM" = x"Windows"], [WINDOWS_BUILD=yes]) AC_MSG_RESULT([$WINDOWS_BUILD]) AC_SUBST([WINDOWS_BUILD]) diff --git a/infer/src/Makefile b/infer/src/Makefile index d0b33a084..6506b0f87 100644 --- a/infer/src/Makefile +++ b/infer/src/Makefile @@ -267,6 +267,7 @@ $(GENERATED_FROM_AUTOCONF): $(MAKEFILE_LIST) -e "s|@JDK11_ENABLED[@]|$(JDK11_ENABLED)|g" \ -e "s|@BUILD_C_ANALYZERS[@]|$(BUILD_C_ANALYZERS)|g" \ -e "s|@BUILD_JAVA_ANALYZERS[@]|$(BUILD_JAVA_ANALYZERS)|g" \ + -e "s|@BUILD_PLATFORM[@]|$(BUILD_PLATFORM)|g" \ -e "s|@OPAMSWITCH[@]|$(OPAMSWITCH)|g" \ -e "s|@XCODE_SELECT[@]|$(XCODE_SELECT)|g" \ -e "s|@INFER_MAN_LAST_MODIFIED[@]|$(INFER_MAN_LAST_MODIFIED)|g" \ diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 9cdba2e2d..5b4be3c67 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -448,6 +448,45 @@ let env_inside_maven = `Extend [(infer_inside_maven_env_var, "1")] let infer_is_javac = maven +let locate_sdk_root () = + match Version.build_platform with + | Darwin -> ( + let cmd = "xcrun --show-sdk-path --sdk macosx 2> /dev/null" in + try + let path, _ = Utils.with_process_in cmd In_channel.input_line in + path + with Unix.Unix_error _ -> None ) + | _ -> + None + + +let infer_sdkroot_env_var = "INFER_SDKROOT" + +(** Try to locate current SDK root on MacOS *unless* [SDKROOT] is + explicitly provided. The implicit SDK root is propagated to child + processes using a custom [INFER_SDKROOT] env var. The reason for + this is twofold: + + 1. With make and buck integrations infer is exec'ed by make/buck + for each source file. That's why we propagate the value by using an + env var instead of calling [locate_sdk_root] each time. + + 2. We don't use [SDKROOT] because it can mess up with other parts + of the toolchain not owned by infer. *) +let implicit_sdk_root = + match Sys.getenv "SDKROOT" with + | Some _ -> + None + | None -> ( + match Sys.getenv infer_sdkroot_env_var with + | Some _ as path -> + path + | None -> + let maybe_root = locate_sdk_root () in + let putenv x = Unix.putenv ~key:infer_sdkroot_env_var ~data:x in + Option.iter ~f:putenv maybe_root ; maybe_root ) + + let startup_action = let open CLOpt in if infer_is_javac then Javac diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index fc7ba2449..2f7bbff35 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -411,6 +411,8 @@ val infer_is_clang : bool val infer_is_javac : bool +val implicit_sdk_root : string option + val inferconfig_file : string option val iphoneos_target_sdk_version : string option diff --git a/infer/src/base/Version.ml.in b/infer/src/base/Version.ml.in index 28b824bcd..b3d1fed34 100644 --- a/infer/src/base/Version.ml.in +++ b/infer/src/base/Version.ml.in @@ -22,6 +22,10 @@ let commit = "@INFER_GIT_COMMIT@" let branch = "@INFER_GIT_BRANCH@" +type build_platform = Linux | Darwin | Windows + +let build_platform = @BUILD_PLATFORM@ + let is_release = is_yes "@IS_RELEASE_TREE@" let tag = Printf.sprintf "v%d.%d.%d" major minor patch diff --git a/infer/src/base/Version.mli b/infer/src/base/Version.mli index 46a5ce42a..dca0ba9d3 100644 --- a/infer/src/base/Version.mli +++ b/infer/src/base/Version.mli @@ -15,6 +15,10 @@ val patch : int val commit : string +type build_platform = Linux | Darwin | Windows + +val build_platform : build_platform + val versionString : string val versionJson : string diff --git a/infer/src/clang/ClangCommand.ml b/infer/src/clang/ClangCommand.ml index e2031894b..ab7ff912d 100644 --- a/infer/src/clang/ClangCommand.ml +++ b/infer/src/clang/ClangCommand.ml @@ -85,7 +85,7 @@ let libcxx_include_to_override_regex = (** 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) ?(post_args = []) - args = + ?(pre_args = []) 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 in_argfiles (prev_is_blacklisted_with_arg, res_rev, changed) args = @@ -141,7 +141,7 @@ let filter_and_replace_unsupported_args ?(replace_options_arg = fun _ s -> s) ?( match aux String.Set.empty (false, [], false) args with | _, res_rev, _ -> (* return non-reversed list *) - List.rev_append res_rev post_args + List.append pre_args (List.rev_append res_rev post_args) (** Work around various path or library issues occurring when one tries to substitute Apple's version @@ -181,6 +181,17 @@ let clang_cc1_cmd_sanitizer cmd = let args_defines = if Config.bufferoverrun && not Config.biabduction then ["-D__INFER_BUFFEROVERRUN"] else [] in + let explicit_sysroot_passed = has_flag cmd "-isysroot" in + (* supply isysroot only when SDKROOT is not set up and explicit isysroot is not provided, + cf. https://lists.apple.com/archives/xcode-users/2005/Dec/msg00524.html + for details on the effects of setting SDKROOT *) + let implicit_sysroot = + if not explicit_sysroot_passed then + Option.map Config.implicit_sdk_root ~f:(fun x -> ["-isysroot"; x]) + |> Option.value ~default:[] + else [] + in + let pre_args_rev = [] |> List.rev_append implicit_sysroot in let post_args_rev = [] |> List.rev_append ["-include"; Config.lib_dir ^/ "clang_wrappers" ^/ "global_defines.h"] @@ -193,7 +204,7 @@ let clang_cc1_cmd_sanitizer cmd = in let clang_arguments = filter_and_replace_unsupported_args ~replace_options_arg ~post_args:(List.rev post_args_rev) - cmd.argv + ~pre_args:(List.rev pre_args_rev) cmd.argv in file_arg_cmd_sanitizer {cmd with argv= clang_arguments}