ldionne created this revision.
ldionne added a reviewer: arphaman.
ldionne requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

On Apple platforms, the base system does not contain headers (e.g. in 
/usr/include).
As a result, one needs to point Clang to those headers manually when running it,
which can be cumbersome. Instead, if the SDK root can't be inferred with the
usual logic (using the SDKROOT env var), try to guess it by running 'xcrun'.

This should provide a default that's sane most of the time when running clang
without impeding the ability for users to select the SDK of their choice with
the usual means.

http://llvm.org/PR45880


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D109460

Files:
  clang/lib/Driver/ToolChains/Darwin.cpp
  clang/test/Driver/darwin-sdkroot.c

Index: clang/test/Driver/darwin-sdkroot.c
===================================================================
--- clang/test/Driver/darwin-sdkroot.c
+++ clang/test/Driver/darwin-sdkroot.c
@@ -1,4 +1,5 @@
-// Check that SDKROOT is used to define the default for -isysroot on Darwin.
+// Check that SDKROOT is used to define the default for -isysroot on Darwin,
+// or that we call `xcrun --show-sdk-path` if SDKROOT is not in the environment.
 //
 // RUN: rm -rf %t.tmpdir
 // RUN: mkdir -p %t.tmpdir
@@ -39,6 +40,16 @@
 //
 // This test do pass using GnuWin32 env.exe.
 
+// Check that we default to running `xcrun --show-sdk-path` if there is no
+// SDKROOT defined in the environment.
+//
+// RUN: env -i %clang -target x86_64-apple-darwin -c %s -### 2> %t.log
+// RUN: FileCheck --check-prefix=CHECK-XCRUN < %t.log %s
+//
+// CHECK-XCRUN: clang
+// CHECK-XCRUN: "-cc1"
+// CHECK-XCRUN: "-isysroot" "TODO"
+
 // Check if clang set the correct deployment target from -sysroot
 //
 // RUN: rm -rf %t/SDKs/iPhoneOS8.0.0.sdk
Index: clang/lib/Driver/ToolChains/Darwin.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Darwin.cpp
+++ clang/lib/Driver/ToolChains/Darwin.cpp
@@ -18,15 +18,22 @@
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/SanitizerArgs.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/TargetParser.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include <cstdlib> // ::getenv
+#include <memory> // std::unique_ptr
 
 using namespace clang::driver;
 using namespace clang::driver::tools;
@@ -1885,21 +1892,54 @@
 void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
   const OptTable &Opts = getDriver().getOpts();
 
-  // Support allowing the SDKROOT environment variable used by xcrun and other
-  // Xcode tools to define the default sysroot, by making it the default for
-  // isysroot.
+  // On Apple platforms, C and C++ Standard Library headers are not provided
+  // with the base system. Instead, they are provided in various SDKs for the
+  // different Apple platforms. Clang needs to know where that SDK lives, and
+  // there are a couple ways this can be achieved:
+  //
+  // (1) If `-isysroot <path-to-SDK>` is passed explicitly, use that.
   if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
     // Warn if the path does not exist.
     if (!getVFS().exists(A->getValue()))
       getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue();
-  } else {
-    if (char *env = ::getenv("SDKROOT")) {
-      // We only use this value as the default if it is an absolute path,
-      // exists, and it is not the root path.
-      if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) &&
-          StringRef(env) != "/") {
-        Args.append(Args.MakeSeparateArg(
-            nullptr, Opts.getOption(options::OPT_isysroot), env));
+  }
+
+  // (2) If the SDKROOT environment variable is defined and points to a valid
+  //     path, use that. $SDKROOT is set by `xcrun` and other Xcode tools, so
+  //     running `xcrun clang` will work by going through this path.
+  else if (char *env = ::getenv("SDKROOT")) {
+    // We only use this value as the default if it is an absolute path,
+    // exists, and it is not the root path.
+    if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) &&
+        StringRef(env) != "/") {
+      Args.append(Args.MakeSeparateArg(
+          nullptr, Opts.getOption(options::OPT_isysroot), env));
+    }
+  }
+
+  // (3) Otherwise, we try to guess the path of the default SDK by running
+  //     `xcrun --show-sdk-path`. This won't always be correct, but if the
+  //      user wants to use the non-default SDK, they should specify it
+  //      explicitly with methods (1) or (2) above.
+  else {
+    llvm::SmallString<64> OutputFile;
+    llvm::sys::fs::createTemporaryFile("print-sdk-path", "" /* No Suffix */, OutputFile);
+    llvm::FileRemover OutputRemover(OutputFile.c_str());
+    llvm::Optional<llvm::StringRef> Redirects[] = {{""}, OutputFile.str(), {""}};
+    int Result = llvm::sys::ExecuteAndWait(
+        "/usr/bin/xcrun",
+        {"/usr/bin/xcrun", "--show-sdk-path"},
+        /* Inherit environment from parent process */ llvm::None, Redirects,
+        /* SecondsToWait */ 0, /*MemoryLimit*/ 0);
+    if (Result == 0) {
+      llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
+          llvm::MemoryBuffer::getFile(OutputFile.c_str(), /* IsText */ true);
+      if (OutputBuf) {
+        llvm::StringRef SdkPath = (*OutputBuf)->getBuffer().trim();
+        if (getVFS().exists(SdkPath)) {
+          Args.append(Args.MakeSeparateArg(
+              nullptr, Opts.getOption(options::OPT_isysroot), SdkPath));
+        }
       }
     }
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to