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; + +def warn_drv_darwin_sdk_invalid_settings : Warning< + "SDK settings were ignored as 'SDKSettings.json' could not be parsed">, + InGroup>; } 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/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 -#include #include "clang/Basic/OpenCLOptions.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Target/TargetOptions.h" +#include +#include 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/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/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> parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, + StringRef SDKRootPath); + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_DRIVER_DARWIN_SDK_INFO_H 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: 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/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> +driver::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) { + llvm::SmallString<256> Filepath = SDKRootPath; + llvm::sys::path::append(Filepath, "SDKSettings.json"); + llvm::ErrorOr> File = + VFS.getBufferForFile(Filepath); + if (!File) { + // If the file couldn't be read, assume it just doesn't exist. + return None; + } + Expected 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("invalid SDKSettings.json", + llvm::inconvertibleErrorCode()); +} Index: lib/Driver/ToolChains/Darwin.cpp =================================================================== --- lib/Driver/ToolChains/Darwin.cpp +++ lib/Driver/ToolChains/Darwin.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/DarwinSDKInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -2037,6 +2038,22 @@ return TargetVersion < alignedAllocMinVersion(OS); } +static Optional 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; +} + void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const { @@ -2046,6 +2063,15 @@ options::OPT_fno_aligned_allocation) && isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); + + // Read the SDKSettings.json file for more information, like the SDK version + // that we can pass down to the compiler. + if (auto SDKInfo = parseSDKSettings(getVFS(), DriverArgs, getDriver())) { + 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/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -3188,6 +3188,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: 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: 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/Driver/darwin-sdk-version.c =================================================================== --- /dev/null +++ test/Driver/darwin-sdk-version.c @@ -0,0 +1,25 @@ +// 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.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 +// NO_VERSION-NOT: target-sdk-version +// ERROR: warning: SDK settings were ignored as 'SDKSettings.json' could not be parsed