diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp | 324 |
1 files changed, 269 insertions, 55 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp index c816b29..b7e576e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp @@ -205,27 +205,103 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, #endif // USE_WIN32 } +// Convert LLVM's ArchType +// to the corresponding name of Windows SDK libraries subfolder +static StringRef getWindowsSDKArch(llvm::Triple::ArchType Arch) { + switch (Arch) { + case llvm::Triple::x86: + return "x86"; + case llvm::Triple::x86_64: + return "x64"; + case llvm::Triple::arm: + return "arm"; + default: + return ""; + } +} + +// Find the most recent version of Universal CRT or Windows 10 SDK. +// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include +// directory by name and uses the last one of the list. +// So we compare entry names lexicographically to find the greatest one. +static bool getWindows10SDKVersion(const std::string &SDKPath, + std::string &SDKVersion) { + SDKVersion.clear(); + + std::error_code EC; + llvm::SmallString<128> IncludePath(SDKPath); + llvm::sys::path::append(IncludePath, "Include"); + for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd; + DirIt != DirEnd && !EC; DirIt.increment(EC)) { + if (!llvm::sys::fs::is_directory(DirIt->path())) + continue; + StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); + // If WDK is installed, there could be subfolders like "wdf" in the + // "Include" directory. + // Allow only directories which names start with "10.". + if (!CandidateName.startswith("10.")) + continue; + if (CandidateName > SDKVersion) + SDKVersion = CandidateName; + } + + return !SDKVersion.empty(); +} + /// \brief Get Windows SDK installation directory. -bool MSVCToolChain::getWindowsSDKDir(std::string &path, int &major, - int &minor) const { - std::string sdkVersion; +bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major, + std::string &WindowsSDKIncludeVersion, + std::string &WindowsSDKLibVersion) const { + std::string RegistrySDKVersion; // Try the Windows registry. - bool hasSDKDir = getSystemRegistryString( - "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", - "InstallationFolder", path, &sdkVersion); - if (!sdkVersion.empty()) - std::sscanf(sdkVersion.c_str(), "v%d.%d", &major, &minor); - return hasSDKDir && !path.empty(); + if (!getSystemRegistryString( + "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", Path, &RegistrySDKVersion)) + return false; + if (Path.empty() || RegistrySDKVersion.empty()) + return false; + + WindowsSDKIncludeVersion.clear(); + WindowsSDKLibVersion.clear(); + Major = 0; + std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); + if (Major <= 7) + return true; + if (Major == 8) { + // Windows SDK 8.x installs libraries in a folder whose names depend on the + // version of the OS you're targeting. By default choose the newest, which + // usually corresponds to the version of the OS you've installed the SDK on. + const char *Tests[] = {"winv6.3", "win8", "win7"}; + for (const char *Test : Tests) { + llvm::SmallString<128> TestPath(Path); + llvm::sys::path::append(TestPath, "Lib", Test); + if (llvm::sys::fs::exists(TestPath.c_str())) { + WindowsSDKLibVersion = Test; + break; + } + } + return !WindowsSDKLibVersion.empty(); + } + if (Major == 10) { + if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion)) + return false; + WindowsSDKLibVersion = WindowsSDKIncludeVersion; + return true; + } + // Unsupported SDK version + return false; } // Gets the library path required to link against the Windows SDK. bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { std::string sdkPath; int sdkMajor = 0; - int sdkMinor = 0; + std::string windowsSDKIncludeVersion; + std::string windowsSDKLibVersion; path.clear(); - if (!getWindowsSDKDir(sdkPath, sdkMajor, sdkMinor)) + if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion, + windowsSDKLibVersion)) return false; llvm::SmallString<128> libPath(sdkPath); @@ -245,44 +321,57 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { return false; } } else { - // Windows SDK 8.x installs libraries in a folder whose names depend on the - // version of the OS you're targeting. By default choose the newest, which - // usually corresponds to the version of the OS you've installed the SDK on. - const char *tests[] = {"winv6.3", "win8", "win7"}; - bool found = false; - for (const char *test : tests) { - llvm::SmallString<128> testPath(libPath); - llvm::sys::path::append(testPath, test); - if (llvm::sys::fs::exists(testPath.c_str())) { - libPath = testPath; - found = true; - break; - } - } - - if (!found) - return false; - - llvm::sys::path::append(libPath, "um"); - switch (getArch()) { - case llvm::Triple::x86: - llvm::sys::path::append(libPath, "x86"); - break; - case llvm::Triple::x86_64: - llvm::sys::path::append(libPath, "x64"); - break; - case llvm::Triple::arm: - llvm::sys::path::append(libPath, "arm"); - break; - default: + const StringRef archName = getWindowsSDKArch(getArch()); + if (archName.empty()) return false; - } + llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", archName); } path = libPath.str(); return true; } +// Check if the Include path of a specified version of Visual Studio contains +// specific header files. If not, they are probably shipped with Universal CRT. +bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT( + std::string &VisualStudioDir) const { + llvm::SmallString<128> TestPath(VisualStudioDir); + llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h"); + + return !llvm::sys::fs::exists(TestPath); +} + +bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path, + std::string &UCRTVersion) const { + // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry + // for the specific key "KitsRoot10". So do we. + if (!getSystemRegistryString( + "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", + Path, nullptr)) + return false; + + return getWindows10SDKVersion(Path, UCRTVersion); +} + +bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { + std::string UniversalCRTSdkPath; + std::string UCRTVersion; + + Path.clear(); + if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) + return false; + + StringRef ArchName = getWindowsSDKArch(getArch()); + if (ArchName.empty()) + return false; + + llvm::SmallString<128> LibPath(UniversalCRTSdkPath); + llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); + + Path = LibPath.str(); + return true; +} + // Get the location to use for Visual Studio binaries. The location priority // is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on // system (as reported by the registry). @@ -419,12 +508,12 @@ bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const { return false; } -void MSVCToolChain::AddSystemIncludeWithSubfolder(const ArgList &DriverArgs, - ArgStringList &CC1Args, - const std::string &folder, - const char *subfolder) const { +void MSVCToolChain::AddSystemIncludeWithSubfolder( + const ArgList &DriverArgs, ArgStringList &CC1Args, + const std::string &folder, const Twine &subfolder1, const Twine &subfolder2, + const Twine &subfolder3) const { llvm::SmallString<128> path(folder); - llvm::sys::path::append(path, subfolder); + llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3); addSystemInclude(DriverArgs, CC1Args, path); } @@ -434,9 +523,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P); + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir, + "include"); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) @@ -460,16 +548,33 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (getVisualStudioInstallDir(VSDir)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include"); + if (useUniversalCRT(VSDir)) { + std::string UniversalCRTSdkPath; + std::string UCRTVersion; + if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) { + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, + "Include", UCRTVersion, "ucrt"); + } + } + std::string WindowsSDKDir; - int major, minor; - if (getWindowsSDKDir(WindowsSDKDir, major, minor)) { + int major; + std::string windowsSDKIncludeVersion; + std::string windowsSDKLibVersion; + if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion, + windowsSDKLibVersion)) { if (major >= 8) { + // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. + // Anyway, llvm::sys::path::append is able to manage it. AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include\\shared"); + "include", windowsSDKIncludeVersion, + "shared"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include\\um"); + "include", windowsSDKIncludeVersion, + "um"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include\\winrt"); + "include", windowsSDKIncludeVersion, + "winrt"); } else { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include"); @@ -528,3 +633,112 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers() const { Res |= SanitizerKind::Address; return Res; } + +llvm::opt::DerivedArgList * +MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // /Oy and /Oy- only has an effect under X86-32. + bool SupportsForcingFramePointer = getArch() == llvm::Triple::x86; + + // The -O[12xd] flag actually expands to several flags. We must desugar the + // flags so that options embedded can be negated. For example, the '-O2' flag + // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to + // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single + // aspect of '-O2'. + // + // Note that this expansion logic only applies to the *last* of '[12xd]'. + + // First step is to search for the character we'd like to expand. + const char *ExpandChar = nullptr; + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT__SLASH_O)) + continue; + StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + const char &OptChar = *(OptStr.data() + I); + if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') + ExpandChar = OptStr.data() + I; + } + } + + // The -O flag actually takes an amalgam of other options. For example, + // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT__SLASH_O)) { + DAL->append(A); + continue; + } + + StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + const char &OptChar = *(OptStr.data() + I); + switch (OptChar) { + default: + break; + case '1': + case '2': + case 'x': + case 'd': + if (&OptChar == ExpandChar) { + if (OptChar == 'd') { + DAL->AddFlagArg(A, Opts.getOption(options::OPT_O0)); + } else { + if (OptChar == '1') { + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + } else if (OptChar == '2' || OptChar == 'x') { + DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); + } + if (SupportsForcingFramePointer) + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_fomit_frame_pointer)); + if (OptChar == '1' || OptChar == '2') + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_ffunction_sections)); + } + } + break; + case 'b': + if (I + 1 != E && isdigit(OptStr[I + 1])) + ++I; + break; + case 'g': + break; + case 'i': + if (I + 1 != E && OptStr[I + 1] == '-') { + ++I; + DAL->AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); + } else { + DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + } + break; + case 's': + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + break; + case 't': + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); + break; + case 'y': { + bool OmitFramePointer = true; + if (I + 1 != E && OptStr[I + 1] == '-') { + OmitFramePointer = false; + ++I; + } + if (SupportsForcingFramePointer) { + if (OmitFramePointer) + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_fomit_frame_pointer)); + else + DAL->AddFlagArg( + A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); + } + break; + } + } + } + } + return DAL; +} |