arphaman updated this revision to Diff 178307.
arphaman added a comment.

Updated to infer deployment target version from SDK versions specified in the 
JSON file and to allow inferring the SDK version from the SDK path.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55673

Files:
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/Basic/TargetInfo.h
  include/clang/Basic/TargetOptions.h
  include/clang/Driver/CC1Options.td
  include/clang/Driver/DarwinSDKInfo.h
  lib/CodeGen/ModuleBuilder.cpp
  lib/Driver/CMakeLists.txt
  lib/Driver/DarwinSDKInfo.cpp
  lib/Driver/ToolChains/Darwin.cpp
  lib/Driver/ToolChains/Darwin.h
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGen/darwin-sdk-version.c
  test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
  test/Driver/darwin-sdk-version.c

Index: test/Driver/darwin-sdk-version.c
===================================================================
--- /dev/null
+++ test/Driver/darwin-sdk-version.c
@@ -0,0 +1,36 @@
+// RUN: %clang -target x86_64-apple-macosx10.13 -isysroot %S/Inputs/MacOSX10.14.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck %s
+// RUN: env SDKROOT=%S/Inputs/MacOSX10.14.sdk %clang -target x86_64-apple-macosx10.13 -c -### %s 2>&1 \
+// RUN:   | FileCheck %s
+//
+// RUN: rm -rf %t/SDKs/MacOSX10.10.sdk
+// RUN: mkdir -p %t/SDKs/MacOSX10.10.sdk
+// RUN: %clang -isysroot %t/SDKs/MacOSX10.10.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=INFER_SDK_VERSION %s
+// RUN: cp %S/Inputs/MacOSX10.14.sdk/SDKSettings.json %t/SDKs/MacOSX10.10.sdk
+// RUN: %clang -isysroot %t/SDKs/MacOSX10.10.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=INFER_DEPLOYMENT_TARGET_VERSION %s
+//
+// RUN: rm -rf %t/SDKs/MacOSX10.14.sdk
+// RUN: mkdir -p %t/SDKs/MacOSX10.14.sdk
+// RUN: %clang -target x86_64-apple-macosx10.13 -isysroot %t/SDKs/MacOSX10.14.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=NO_VERSION %s
+//
+// RUN: rm -rf %t/SDKs/MacOSX10.14.sdk
+// RUN: mkdir -p %t/SDKs/MacOSX10.14.sdk
+// RUN: echo '{broken json' > %t/SDKs/MacOSX10.14.sdk/SDKSettings.json
+// RUN: %clang -target x86_64-apple-macosx10.13 -isysroot %t/SDKs/MacOSX10.14.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefixes=NO_VERSION,ERROR %s
+//
+// RUN: rm -rf %t/SDKs/MacOSX10.14.sdk
+// RUN: mkdir -p %t/SDKs/MacOSX10.14.sdk
+// RUN: echo '{"Version":1}' > %t/SDKs/MacOSX10.14.sdk/SDKSettings.json
+// RUN: %clang -target x86_64-apple-macosx10.13 -isysroot %t/SDKs/MacOSX10.14.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefixes=NO_VERSION,ERROR %s
+
+// CHECK: -target-sdk-version=10.14
+// INFER_SDK_VERSION: "-triple" "x86_64-apple-macosx10.10.0"
+// INFER_SDK_VERSION-SAME: -target-sdk-version=10.10
+// INFER_DEPLOYMENT_TARGET_VERSION: "-triple" "x86_64-apple-macosx10.14.0"
+// NO_VERSION-NOT: target-sdk-version
+// ERROR: warning: SDK settings were ignored as 'SDKSettings.json' could not be parsed
Index: test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
===================================================================
--- /dev/null
+++ test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
@@ -0,0 +1 @@
+{"Version":"10.14"}
Index: test/CodeGen/darwin-sdk-version.c
===================================================================
--- /dev/null
+++ test/CodeGen/darwin-sdk-version.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14 -target-sdk-version=10.14.1 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: !llvm.module.flags = !{!0
+// CHECK: !0 = !{i32 2, !"SDK Version", [3 x i32] [i32 10, i32 14, i32 1]}
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -3192,6 +3192,14 @@
   Opts.ForceEnableInt128 = Args.hasArg(OPT_fforce_enable_int128);
   Opts.NVPTXUseShortPointers = Args.hasFlag(
       options::OPT_fcuda_short_ptr, options::OPT_fno_cuda_short_ptr, false);
+  if (Arg *A = Args.getLastArg(options::OPT_target_sdk_version_EQ)) {
+    llvm::VersionTuple Version;
+    if (Version.tryParse(A->getValue()))
+      Diags.Report(diag::err_drv_invalid_value)
+          << A->getAsString(Args) << A->getValue();
+    else
+      Opts.SDKVersion = Version;
+  }
 }
 
 bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Index: lib/Driver/ToolChains/Darwin.h
===================================================================
--- lib/Driver/ToolChains/Darwin.h
+++ lib/Driver/ToolChains/Darwin.h
@@ -11,9 +11,10 @@
 #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
 
 #include "Cuda.h"
-#include "clang/Driver/XRayArgs.h"
+#include "clang/Driver/DarwinSDKInfo.h"
 #include "clang/Driver/Tool.h"
 #include "clang/Driver/ToolChain.h"
+#include "clang/Driver/XRayArgs.h"
 
 namespace clang {
 namespace driver {
@@ -288,6 +289,9 @@
   /// The OS version we are targeting.
   mutable VersionTuple TargetVersion;
 
+  /// The information about the darwin SDK that was used.
+  mutable Optional<DarwinSDKInfo> SDKInfo;
+
   CudaInstallationDetector CudaInstallation;
 
 private:
Index: lib/Driver/ToolChains/Darwin.cpp
===================================================================
--- lib/Driver/ToolChains/Darwin.cpp
+++ lib/Driver/ToolChains/Darwin.cpp
@@ -1287,6 +1287,18 @@
     return DarwinPlatform(InferredFromArch, getPlatformFromOS(OS), Value);
   }
 
+  /// Constructs an inferred SDKInfo value based on the version inferred from
+  /// the SDK path itself. Only works for values that were created by inferring
+  /// the platform from the SDKPath.
+  DarwinSDKInfo inferSDKInfo() {
+    assert(Kind == InferredFromSDK && "can infer SDK info only");
+    llvm::VersionTuple Version;
+    bool IsValid = !Version.tryParse(OSVersion);
+    (void)IsValid;
+    assert(IsValid && "invalid SDK version");
+    return DarwinSDKInfo(Version);
+  }
+
 private:
   DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg *Argument)
       : Kind(Kind), Platform(Platform), Argument(Argument) {}
@@ -1420,8 +1432,11 @@
 }
 
 /// Tries to infer the deployment target from the SDK specified by -isysroot
-/// (or SDKROOT).
-Optional<DarwinPlatform> inferDeploymentTargetFromSDK(DerivedArgList &Args) {
+/// (or SDKROOT). Uses the version specified in the SDKSettings.json file if
+/// it's available.
+Optional<DarwinPlatform>
+inferDeploymentTargetFromSDK(DerivedArgList &Args,
+                             const Optional<DarwinSDKInfo> &SDKInfo) {
   const Arg *A = Args.getLastArg(options::OPT_isysroot);
   if (!A)
     return None;
@@ -1429,28 +1444,37 @@
   StringRef SDK = Darwin::getSDKName(isysroot);
   if (!SDK.size())
     return None;
-  // Slice the version number out.
-  // Version number is between the first and the last number.
-  size_t StartVer = SDK.find_first_of("0123456789");
-  size_t EndVer = SDK.find_last_of("0123456789");
-  if (StartVer != StringRef::npos && EndVer > StartVer) {
-    StringRef Version = SDK.slice(StartVer, EndVer + 1);
-    if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator"))
-      return DarwinPlatform::createFromSDK(
-          Darwin::IPhoneOS, Version,
-          /*IsSimulator=*/SDK.startswith("iPhoneSimulator"));
-    else if (SDK.startswith("MacOSX"))
-      return DarwinPlatform::createFromSDK(Darwin::MacOS,
-                                           getSystemOrSDKMacOSVersion(Version));
-    else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator"))
-      return DarwinPlatform::createFromSDK(
-          Darwin::WatchOS, Version,
-          /*IsSimulator=*/SDK.startswith("WatchSimulator"));
-    else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator"))
-      return DarwinPlatform::createFromSDK(
-          Darwin::TvOS, Version,
-          /*IsSimulator=*/SDK.startswith("AppleTVSimulator"));
-  }
+
+  std::string Version;
+  if (SDKInfo) {
+    // Get the version from the SDKSettings.json if it's available.
+    Version = SDKInfo->getVersion().getAsString();
+  } else {
+    // Slice the version number out.
+    // Version number is between the first and the last number.
+    size_t StartVer = SDK.find_first_of("0123456789");
+    size_t EndVer = SDK.find_last_of("0123456789");
+    if (StartVer != StringRef::npos && EndVer > StartVer)
+      Version = SDK.slice(StartVer, EndVer + 1);
+  }
+  if (Version.empty())
+    return None;
+
+  if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator"))
+    return DarwinPlatform::createFromSDK(
+        Darwin::IPhoneOS, Version,
+        /*IsSimulator=*/SDK.startswith("iPhoneSimulator"));
+  else if (SDK.startswith("MacOSX"))
+    return DarwinPlatform::createFromSDK(Darwin::MacOS,
+                                         getSystemOrSDKMacOSVersion(Version));
+  else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator"))
+    return DarwinPlatform::createFromSDK(
+        Darwin::WatchOS, Version,
+        /*IsSimulator=*/SDK.startswith("WatchSimulator"));
+  else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator"))
+    return DarwinPlatform::createFromSDK(
+        Darwin::TvOS, Version,
+        /*IsSimulator=*/SDK.startswith("AppleTVSimulator"));
   return None;
 }
 
@@ -1525,6 +1549,22 @@
                                           Args.getLastArg(options::OPT_target));
 }
 
+Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS,
+                                         const ArgList &Args,
+                                         const Driver &TheDriver) {
+  const Arg *A = Args.getLastArg(options::OPT_isysroot);
+  if (!A)
+    return None;
+  StringRef isysroot = A->getValue();
+  auto SDKInfoOrErr = driver::parseDarwinSDKInfo(VFS, isysroot);
+  if (!SDKInfoOrErr) {
+    llvm::consumeError(SDKInfoOrErr.takeError());
+    TheDriver.Diag(diag::warn_drv_darwin_sdk_invalid_settings);
+    return None;
+  }
+  return *SDKInfoOrErr;
+}
+
 } // namespace
 
 void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
@@ -1549,6 +1589,10 @@
     }
   }
 
+  // Read the SDKSettings.json file for more information, like the SDK version
+  // that we can pass down to the compiler.
+  SDKInfo = parseSDKSettings(getVFS(), Args, getDriver());
+
   // The OS and the version can be specified using the -target argument.
   Optional<DarwinPlatform> OSTarget =
       getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver());
@@ -1594,16 +1638,22 @@
           getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple());
       if (OSTarget) {
         // Don't infer simulator from the arch when the SDK is also specified.
-        Optional<DarwinPlatform> SDKTarget = inferDeploymentTargetFromSDK(Args);
+        Optional<DarwinPlatform> SDKTarget =
+            inferDeploymentTargetFromSDK(Args, SDKInfo);
         if (SDKTarget)
           OSTarget->setEnvironment(SDKTarget->getEnvironment());
       }
     }
     // If there is no command-line argument to specify the Target version and
     // no environment variable defined, see if we can set the default based
-    // on -isysroot.
-    if (!OSTarget)
-      OSTarget = inferDeploymentTargetFromSDK(Args);
+    // on -isysroot using SDKSettings.json if it exists.
+    if (!OSTarget) {
+      OSTarget = inferDeploymentTargetFromSDK(Args, SDKInfo);
+      /// If the target was successfully constructed from the SDK path, try to
+      /// infer the SDK info if the SDK doesn't have it.
+      if (OSTarget && !SDKInfo)
+        SDKInfo = OSTarget->inferSDKInfo();
+    }
     // If no OS targets have been specified, try to guess platform from -target
     // or arch name and compute the version from the triple.
     if (!OSTarget)
@@ -2046,6 +2096,15 @@
                                 options::OPT_fno_aligned_allocation) &&
       isAlignedAllocationUnavailable())
     CC1Args.push_back("-faligned-alloc-unavailable");
+
+  if (SDKInfo) {
+    /// Pass the SDK version to the compiler when the SDK information is
+    /// available.
+    std::string Arg;
+    llvm::raw_string_ostream OS(Arg);
+    OS << "-target-sdk-version=" << SDKInfo->getVersion();
+    CC1Args.push_back(DriverArgs.MakeArgString(OS.str()));
+  }
 }
 
 DerivedArgList *
Index: lib/Driver/DarwinSDKInfo.cpp
===================================================================
--- /dev/null
+++ lib/Driver/DarwinSDKInfo.cpp
@@ -0,0 +1,44 @@
+//===--- DarwinSDKInfo.cpp - SDK Information parser for darwin - ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/DarwinSDKInfo.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang;
+
+Expected<Optional<DarwinSDKInfo>>
+driver::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {
+  llvm::SmallString<256> Filepath = SDKRootPath;
+  llvm::sys::path::append(Filepath, "SDKSettings.json");
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+      VFS.getBufferForFile(Filepath);
+  if (!File) {
+    // If the file couldn't be read, assume it just doesn't exist.
+    return None;
+  }
+  Expected<llvm::json::Value> Result =
+      llvm::json::parse(File.get()->getBuffer());
+  if (!Result)
+    return Result.takeError();
+
+  if (const auto *Obj = Result->getAsObject()) {
+    auto VersionString = Obj->getString("Version");
+    if (VersionString) {
+      VersionTuple Version;
+      if (!Version.tryParse(*VersionString))
+        return DarwinSDKInfo(Version);
+    }
+  }
+  return llvm::make_error<llvm::StringError>("invalid SDKSettings.json",
+                                             llvm::inconvertibleErrorCode());
+}
Index: lib/Driver/CMakeLists.txt
===================================================================
--- lib/Driver/CMakeLists.txt
+++ lib/Driver/CMakeLists.txt
@@ -12,6 +12,7 @@
 add_clang_library(clangDriver
   Action.cpp
   Compilation.cpp
+  DarwinSDKInfo.cpp
   Distro.cpp
   Driver.cpp
   DriverOptions.cpp
Index: lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- lib/CodeGen/ModuleBuilder.cpp
+++ lib/CodeGen/ModuleBuilder.cpp
@@ -132,6 +132,9 @@
 
       M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
       M->setDataLayout(Ctx->getTargetInfo().getDataLayout());
+      const auto &SDKVersion = Ctx->getTargetInfo().getSDKVersion();
+      if (!SDKVersion.empty())
+        M->setSDKVersion(SDKVersion);
       Builder.reset(new CodeGen::CodeGenModule(Context, HeaderSearchOpts,
                                                PreprocessorOpts, CodeGenOpts,
                                                *M, Diags, CoverageInfo));
Index: include/clang/Driver/DarwinSDKInfo.h
===================================================================
--- /dev/null
+++ include/clang/Driver/DarwinSDKInfo.h
@@ -0,0 +1,42 @@
+//===--- DarwinSDKInfo.h - SDK Information parser for darwin ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DRIVER_DARWIN_SDK_INFO_H
+#define LLVM_CLANG_DRIVER_DARWIN_SDK_INFO_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace clang {
+namespace driver {
+
+/// The information about the darwin SDK that was used during this compilation.
+class DarwinSDKInfo {
+public:
+  DarwinSDKInfo(llvm::VersionTuple Version) : Version(Version) {}
+
+  const llvm::VersionTuple &getVersion() const { return Version; }
+
+private:
+  llvm::VersionTuple Version;
+};
+
+/// Parse the SDK information from the SDKSettings.json file.
+///
+/// \returns an error if the SDKSettings.json file is invalid, None if the
+/// SDK has no SDKSettings.json, or a valid \c DarwinSDKInfo otherwise.
+Expected<Optional<DarwinSDKInfo>> parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS,
+                                                     StringRef SDKRootPath);
+
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_DRIVER_DARWIN_SDK_INFO_H
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -27,6 +27,8 @@
   HelpText<"Specify target triple (e.g. i686-apple-darwin9)">;
 def target_abi : Separate<["-"], "target-abi">,
   HelpText<"Target a particular ABI type">;
+def target_sdk_version_EQ : Joined<["-"], "target-sdk-version=">,
+  HelpText<"The version of target SDK used for compilation">;
 
 }
 
Index: include/clang/Basic/TargetOptions.h
===================================================================
--- include/clang/Basic/TargetOptions.h
+++ include/clang/Basic/TargetOptions.h
@@ -15,10 +15,11 @@
 #ifndef LLVM_CLANG_BASIC_TARGETOPTIONS_H
 #define LLVM_CLANG_BASIC_TARGETOPTIONS_H
 
-#include <string>
-#include <vector>
 #include "clang/Basic/OpenCLOptions.h"
+#include "llvm/Support/VersionTuple.h"
 #include "llvm/Target/TargetOptions.h"
+#include <string>
+#include <vector>
 
 namespace clang {
 
@@ -73,6 +74,9 @@
   // "default" for the case when the user has not explicitly specified a
   // code model.
   std::string CodeModel;
+
+  /// The version of the SDK which was used during the compilation.
+  VersionTuple SDKVersion;
 };
 
 }  // end namespace clang
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -1321,6 +1321,12 @@
     return None;
   }
 
+  /// \returns The version of the SDK which was used during the compilation if
+  /// one was specified, or an empty version otherwise.
+  const llvm::VersionTuple &getSDKVersion() const {
+    return getTargetOpts().SDKVersion;
+  }
+
   /// Check the target is valid after it is fully initialized.
   virtual bool validateTarget(DiagnosticsEngine &Diags) const {
     return true;
Index: include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- include/clang/Basic/DiagnosticDriverKinds.td
+++ include/clang/Basic/DiagnosticDriverKinds.td
@@ -405,4 +405,8 @@
 def warn_drv_moutline_unsupported_opt : Warning<
   "The '%0' architecture does not support -moutline; flag ignored">,
   InGroup<OptionIgnored>;
+
+def warn_drv_darwin_sdk_invalid_settings : Warning<
+  "SDK settings were ignored as 'SDKSettings.json' could not be parsed">,
+  InGroup<DiagGroup<"darwin-sdk-settings">>;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to