calebzulawski updated this revision to Diff 506434.
calebzulawski added a comment.

Corrected docs and updated upstream


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136315/new/

https://reviews.llvm.org/D136315

Files:
  clang/docs/UsersManual.rst
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Darwin.cpp
  clang/test/Driver/darwin-sdk-detect.c
  clang/test/Driver/lit.local.cfg

Index: clang/test/Driver/lit.local.cfg
===================================================================
--- clang/test/Driver/lit.local.cfg
+++ clang/test/Driver/lit.local.cfg
@@ -1,4 +1,5 @@
 from lit.llvm import llvm_config
+import subprocess
 
 config.suffixes = ['.c', '.cpp', '.cppm', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95',
                    '.cu', '.rs', '.cl', '.clcpp', '.hip', '.hipi', '.hlsl']
@@ -24,3 +25,9 @@
 
 if config.ppc_linux_default_ieeelongdouble:
   config.available_features.add('ppc_linux_default_ieeelongdouble')
+
+if os.path.exists('/usr/bin/xcrun') and sys.platform == 'darwin':
+    if subprocess.run(['/usr/bin/xcrun', '--sdk', 'macosx', '--show-sdk-path']).returncode == 0:
+        config.available_features.add('macos-sdk')
+    if subprocess.run(['/usr/bin/xcrun', '--sdk', 'iphoneos', '--show-sdk-path']).returncode == 0:
+        config.available_features.add('ios-sdk')
Index: clang/test/Driver/darwin-sdk-detect.c
===================================================================
--- /dev/null
+++ clang/test/Driver/darwin-sdk-detect.c
@@ -0,0 +1,20 @@
+// REQUIRES: system-darwin, ios-sdk, macos-sdk
+
+// Check that we default to running `xcrun --show-sdk-path` if there is no
+// SDKROOT defined in the environment.
+//
+// RUN: env -u SDKROOT %clang --infer-sdkroot-from-xcrun -target x86_64-apple-macos -c %s -### 2> %t.log
+// RUN: FileCheck --check-prefix=CHECK-XC < %t.log %s
+//
+// CHECK-XC: clang
+// CHECK-XC: "-cc1"
+// CHECK-XC: "-isysroot" "{{.*MacOSX[0-9\.]*\.sdk}}"
+
+// Check once again that we default to running `xcrun`, this time with another target.
+//
+// RUN: env -u SDKROOT %clang --infer-sdkroot-from-xcrun -target arm64-apple-ios -c %s -### 2> %t.log
+// RUN: FileCheck --check-prefix=CHECK-XC-IOS < %t.log %s
+//
+// CHECK-XC-IOS: clang
+// CHECK-XC-IOS: "-cc1"
+// CHECK-XC-IOS: "-isysroot" "{{.*iPhoneOS[0-9\.]*\.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/Threading.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/TargetParser.h"
 #include <cstdlib> // ::getenv
+#include <memory>  // std::unique_ptr
 
 using namespace clang::driver;
 using namespace clang::driver::tools;
@@ -2098,21 +2105,89 @@
 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, standard headers and libraries are not provided with
+  // the base system (e.g. in /usr/{include,lib}). 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 if (Args.hasArg(options::OPT_infer_sdkroot_from_xcrun)) {
+    llvm::SmallString<64> OutputFile;
+    llvm::sys::fs::createTemporaryFile("print-sdk-path", "" /* No Suffix */,
+                                       OutputFile);
+    llvm::FileRemover OutputRemover(OutputFile.c_str());
+    std::optional<llvm::StringRef> Redirects[] = {{""}, OutputFile.str(), {""}};
+
+    std::optional<StringRef> SDKName = std::nullopt;
+    switch (getTriple().getOS()) {
+    case llvm::Triple::OSType::WatchOS:
+      if (getTriple().isSimulatorEnvironment())
+        SDKName = "watchsimulator";
+      else
+        SDKName = "watchos";
+      break;
+    case llvm::Triple::OSType::TvOS:
+      if (getTriple().isSimulatorEnvironment())
+        SDKName = "appletvsimulator";
+      else
+        SDKName = "appletvos";
+      break;
+    case llvm::Triple::OSType::IOS:
+      if (getTriple().isSimulatorEnvironment())
+        SDKName = "iphonesimulator";
+      else
+        SDKName = "iphoneos";
+      break;
+    case llvm::Triple::OSType::Darwin:
+    case llvm::Triple::OSType::MacOSX:
+      SDKName = "macosx";
+      break;
+    case llvm::Triple::OSType::DriverKit:
+      SDKName = "driverkit";
+      break;
+    default:
+      llvm_unreachable("unknown kind of Darwin platform");
+    }
+
+    if (SDKName) {
+      int Result = llvm::sys::ExecuteAndWait(
+          "/usr/bin/xcrun",
+          {"/usr/bin/xcrun", "--sdk", *SDKName, "--show-sdk-path"},
+          /* Inherit environment from parent process */ std::nullopt, 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));
+          }
+        }
       }
     }
   }
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -3375,6 +3375,8 @@
   MarshallingInfoFlag<FrontendOpts<"RelocatablePCH">>;
 def verify_pch : Flag<["-"], "verify-pch">, Group<Action_Group>, Flags<[CC1Option]>,
   HelpText<"Load and verify that a pre-compiled header file is not stale">;
+def infer_sdkroot_from_xcrun : Flag<["--"], "infer-sdkroot-from-xcrun">,
+  Flags<[NoXarchOption]>, HelpText<"Detect Xcode SDK path with xcrun">;
 def init : Separate<["-"], "init">;
 def install__name : Separate<["-"], "install_name">;
 def iprefix : JoinedOrSeparate<["-"], "iprefix">, Group<clang_i_Group>, Flags<[CC1Option]>,
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -3850,6 +3850,21 @@
 Operating System Features and Limitations
 -----------------------------------------
 
+Apple
+^^^^^
+
+On Apple platforms, the standard headers and libraries are not provided by
+the base system and are instead part of the Xcode SDK application. The location
+of the SDK is determined in the following priority:
+
+- If passed to Clang, the ``-isysroot`` option specifies the path to the SDK.
+
+- If the sysroot isn't provided, the ``SDKROOT`` environment variable is checked.
+  This variable is set by various Xcode tools.
+
+- If the ``--infer-sdkroot-from-xcrun`` option is provided, Clang uses Xcode's
+  ``xcrun`` tool to find the SDK.
+
 Windows
 ^^^^^^^
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to