From: Alex Lorenz Date: Mon, 17 Dec 2018 19:19:15 +0000 (+0000) Subject: [darwin] parse the SDK settings from SDKSettings.json if it exists and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=228f2c50c5313094fa41671e6ac2d1548db7d19d;p=clang [darwin] parse the SDK settings from SDKSettings.json if it exists and pass in the -target-sdk-version to the compiler and backend This commit adds support for reading the SDKSettings.json file in the Darwin driver. This file is used by the driver to determine the SDK's version, and it uses that information to pass it down to the compiler using the new -target-sdk-version= option. This option is then used to set the appropriate SDK Version module metadata introduced in r349119. Note: I had to adjust the two ast tests as the SDKROOT environment variable on macOS caused SDK version to be picked up for the compilation of source file but not the AST. rdar://45774000 Differential Revision: https://reviews.llvm.org/D55673 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@349380 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index af528e1718..a154443248 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -405,4 +405,8 @@ def warn_drv_experimental_isel_incomplete_opt : Warning< 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>; } diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 4a7254e02c..786b1c251c 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -1321,6 +1321,12 @@ public: 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; diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h index 7559e3169e..711e53627f 100644 --- a/include/clang/Basic/TargetOptions.h +++ b/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 @@ public: // "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 diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 9d2d2df7d2..742787bf0c 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -27,6 +27,8 @@ def triple : Separate<["-"], "triple">, 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">; } diff --git a/include/clang/Driver/DarwinSDKInfo.h b/include/clang/Driver/DarwinSDKInfo.h new file mode 100644 index 0000000000..4ffb02fea3 --- /dev/null +++ b/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 diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 1264893ec1..c0a37698e7 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -132,6 +132,9 @@ namespace { 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)); diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index bc96098d0a..084176b524 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -12,6 +12,7 @@ endif() add_clang_library(clangDriver Action.cpp Compilation.cpp + DarwinSDKInfo.cpp Distro.cpp Driver.cpp DriverOptions.cpp diff --git a/lib/Driver/DarwinSDKInfo.cpp b/lib/Driver/DarwinSDKInfo.cpp new file mode 100644 index 0000000000..547978b2f9 --- /dev/null +++ b/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()); +} diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp index e5dafa2b09..0cc187ab47 100644 --- a/lib/Driver/ToolChains/Darwin.cpp +++ b/lib/Driver/ToolChains/Darwin.cpp @@ -1287,6 +1287,18 @@ struct DarwinPlatform { 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 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, } /// Tries to infer the deployment target from the SDK specified by -isysroot -/// (or SDKROOT). -Optional inferDeploymentTargetFromSDK(DerivedArgList &Args) { +/// (or SDKROOT). Uses the version specified in the SDKSettings.json file if +/// it's available. +Optional +inferDeploymentTargetFromSDK(DerivedArgList &Args, + const Optional &SDKInfo) { const Arg *A = Args.getLastArg(options::OPT_isysroot); if (!A) return None; @@ -1429,28 +1444,37 @@ Optional inferDeploymentTargetFromSDK(DerivedArgList &Args) { 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 @@ Optional getDeploymentTargetFromTargetArg( Args.getLastArg(options::OPT_target)); } +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; +} + } // namespace void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { @@ -1549,6 +1589,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } + // 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 OSTarget = getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver()); @@ -1594,16 +1638,22 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple()); if (OSTarget) { // Don't infer simulator from the arch when the SDK is also specified. - Optional SDKTarget = inferDeploymentTargetFromSDK(Args); + Optional 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 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, 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 * diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h index e6a88dce3c..d753f8967a 100644 --- a/lib/Driver/ToolChains/Darwin.h +++ b/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 @@ public: /// The OS version we are targeting. mutable VersionTuple TargetVersion; + /// The information about the darwin SDK that was used. + mutable Optional SDKInfo; + CudaInstallationDetector CudaInstallation; private: diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d491f35769..eaa61b29d9 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -3193,6 +3193,14 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, 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, diff --git a/test/CodeGen/darwin-sdk-version.c b/test/CodeGen/darwin-sdk-version.c new file mode 100644 index 0000000000..23c43f5932 --- /dev/null +++ b/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]} diff --git a/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json b/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json new file mode 100644 index 0000000000..bca56e4f1e --- /dev/null +++ b/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json @@ -0,0 +1 @@ +{"Version":"10.14"} diff --git a/test/Driver/darwin-sdk-version.c b/test/Driver/darwin-sdk-version.c new file mode 100644 index 0000000000..a80ed39c60 --- /dev/null +++ b/test/Driver/darwin-sdk-version.c @@ -0,0 +1,37 @@ +// 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 +// REQUIRES: system-darwin && native +// +// 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 diff --git a/test/Frontend/ast-main.c b/test/Frontend/ast-main.c index 43237a12ef..74e8bcf6db 100644 --- a/test/Frontend/ast-main.c +++ b/test/Frontend/ast-main.c @@ -1,6 +1,6 @@ -// RUN: %clang -emit-llvm -S -o %t1.ll -x c - < %s -// RUN: %clang -emit-ast -o %t.ast %s -// RUN: %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast +// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t1.ll -x c - < %s +// RUN: env SDKROOT="/" %clang -emit-ast -o %t.ast %s +// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast // RUN: diff %t1.ll %t2.ll int main() { diff --git a/test/Frontend/ast-main.cpp b/test/Frontend/ast-main.cpp index 4bddbe1372..89fd5e5a63 100644 --- a/test/Frontend/ast-main.cpp +++ b/test/Frontend/ast-main.cpp @@ -1,6 +1,6 @@ -// RUN: %clang -emit-llvm -S -o %t1.ll -x c++ - < %s -// RUN: %clang -fno-delayed-template-parsing -emit-ast -o %t.ast %s -// RUN: %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast +// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t1.ll -x c++ - < %s +// RUN: env SDKROOT="/" %clang -fno-delayed-template-parsing -emit-ast -o %t.ast %s +// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast // RUN: diff %t1.ll %t2.ll // http://llvm.org/bugs/show_bug.cgi?id=15377