1 //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MSVC.h" 10 #include "CommonArgs.h" 11 #include "Darwin.h" 12 #include "clang/Basic/CharInfo.h" 13 #include "clang/Basic/Version.h" 14 #include "clang/Config/config.h" 15 #include "clang/Driver/Compilation.h" 16 #include "clang/Driver/Driver.h" 17 #include "clang/Driver/DriverDiagnostic.h" 18 #include "clang/Driver/Options.h" 19 #include "clang/Driver/SanitizerArgs.h" 20 #include "llvm/ADT/StringExtras.h" 21 #include "llvm/ADT/StringSwitch.h" 22 #include "llvm/Option/Arg.h" 23 #include "llvm/Option/ArgList.h" 24 #include "llvm/Support/ConvertUTF.h" 25 #include "llvm/Support/ErrorHandling.h" 26 #include "llvm/Support/FileSystem.h" 27 #include "llvm/Support/Host.h" 28 #include "llvm/Support/MemoryBuffer.h" 29 #include "llvm/Support/Path.h" 30 #include "llvm/Support/Process.h" 31 #include "llvm/Support/VirtualFileSystem.h" 32 #include <cstdio> 33 34 #ifdef _WIN32 35 #define WIN32_LEAN_AND_MEAN 36 #define NOGDI 37 #ifndef NOMINMAX 38 #define NOMINMAX 39 #endif 40 #include <windows.h> 41 #endif 42 43 using namespace clang::driver; 44 using namespace clang::driver::toolchains; 45 using namespace clang::driver::tools; 46 using namespace clang; 47 using namespace llvm::opt; 48 49 static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { 50 auto Status = VFS.status(Path); 51 if (!Status) 52 return false; 53 return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0; 54 } 55 56 // Try to find Exe from a Visual Studio distribution. This first tries to find 57 // an installed copy of Visual Studio and, failing that, looks in the PATH, 58 // making sure that whatever executable that's found is not a same-named exe 59 // from clang itself to prevent clang from falling back to itself. 60 static std::string FindVisualStudioExecutable(const ToolChain &TC, 61 const char *Exe) { 62 const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); 63 SmallString<128> FilePath( 64 MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin)); 65 llvm::sys::path::append(FilePath, Exe); 66 return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe); 67 } 68 69 void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, 70 const InputInfo &Output, 71 const InputInfoList &Inputs, 72 const ArgList &Args, 73 const char *LinkingOutput) const { 74 ArgStringList CmdArgs; 75 76 auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain()); 77 78 assert((Output.isFilename() || Output.isNothing()) && "invalid output"); 79 if (Output.isFilename()) 80 CmdArgs.push_back( 81 Args.MakeArgString(std::string("-out:") + Output.getFilename())); 82 83 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && 84 !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { 85 CmdArgs.push_back("-defaultlib:libcmt"); 86 CmdArgs.push_back("-defaultlib:oldnames"); 87 } 88 89 // If the VC environment hasn't been configured (perhaps because the user 90 // did not run vcvarsall), try to build a consistent link environment. If 91 // the environment variable is set however, assume the user knows what 92 // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that 93 // over env vars. 94 if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir, 95 options::OPT__SLASH_winsysroot)) { 96 // cl.exe doesn't find the DIA SDK automatically, so this too requires 97 // explicit flags and doesn't automatically look in "DIA SDK" relative 98 // to the path we found for VCToolChainPath. 99 llvm::SmallString<128> DIAPath(A->getValue()); 100 if (A->getOption().getID() == options::OPT__SLASH_winsysroot) 101 llvm::sys::path::append(DIAPath, "DIA SDK"); 102 103 // The DIA SDK always uses the legacy vc arch, even in new MSVC versions. 104 llvm::sys::path::append(DIAPath, "lib", 105 llvm::archToLegacyVCArch(TC.getArch())); 106 CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath)); 107 } 108 if (!llvm::sys::Process::GetEnv("LIB") || 109 Args.getLastArg(options::OPT__SLASH_vctoolsdir, 110 options::OPT__SLASH_winsysroot)) { 111 CmdArgs.push_back(Args.MakeArgString( 112 Twine("-libpath:") + 113 TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib))); 114 CmdArgs.push_back(Args.MakeArgString( 115 Twine("-libpath:") + 116 TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc"))); 117 } 118 if (!llvm::sys::Process::GetEnv("LIB") || 119 Args.getLastArg(options::OPT__SLASH_winsdkdir, 120 options::OPT__SLASH_winsysroot)) { 121 if (TC.useUniversalCRT()) { 122 std::string UniversalCRTLibPath; 123 if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath)) 124 CmdArgs.push_back( 125 Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath)); 126 } 127 std::string WindowsSdkLibPath; 128 if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath)) 129 CmdArgs.push_back( 130 Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); 131 } 132 133 if (C.getDriver().IsFlangMode()) { 134 addFortranRuntimeLibraryPath(TC, Args, CmdArgs); 135 addFortranRuntimeLibs(TC, CmdArgs); 136 137 // Inform the MSVC linker that we're generating a console application, i.e. 138 // one with `main` as the "user-defined" entry point. The `main` function is 139 // defined in flang's runtime libraries. 140 CmdArgs.push_back("/subsystem:console"); 141 } 142 143 // Add the compiler-rt library directories to libpath if they exist to help 144 // the linker find the various sanitizer, builtin, and profiling runtimes. 145 for (const auto &LibPath : TC.getLibraryPaths()) { 146 if (TC.getVFS().exists(LibPath)) 147 CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); 148 } 149 auto CRTPath = TC.getCompilerRTPath(); 150 if (TC.getVFS().exists(CRTPath)) 151 CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath)); 152 153 if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) 154 for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) 155 CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); 156 157 CmdArgs.push_back("-nologo"); 158 159 if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) 160 CmdArgs.push_back("-debug"); 161 162 // If we specify /hotpatch, let the linker add padding in front of each 163 // function, like MSVC does. 164 if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch)) 165 CmdArgs.push_back("-functionpadmin"); 166 167 // Pass on /Brepro if it was passed to the compiler. 168 // Note that /Brepro maps to -mno-incremental-linker-compatible. 169 bool DefaultIncrementalLinkerCompatible = 170 C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); 171 if (!Args.hasFlag(options::OPT_mincremental_linker_compatible, 172 options::OPT_mno_incremental_linker_compatible, 173 DefaultIncrementalLinkerCompatible)) 174 CmdArgs.push_back("-Brepro"); 175 176 bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, 177 options::OPT_shared); 178 if (DLL) { 179 CmdArgs.push_back(Args.MakeArgString("-dll")); 180 181 SmallString<128> ImplibName(Output.getFilename()); 182 llvm::sys::path::replace_extension(ImplibName, "lib"); 183 CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); 184 } 185 186 if (TC.getSanitizerArgs(Args).needsFuzzer()) { 187 if (!Args.hasArg(options::OPT_shared)) 188 CmdArgs.push_back( 189 Args.MakeArgString(std::string("-wholearchive:") + 190 TC.getCompilerRTArgString(Args, "fuzzer"))); 191 CmdArgs.push_back(Args.MakeArgString("-debug")); 192 // Prevent the linker from padding sections we use for instrumentation 193 // arrays. 194 CmdArgs.push_back(Args.MakeArgString("-incremental:no")); 195 } 196 197 if (TC.getSanitizerArgs(Args).needsAsanRt()) { 198 CmdArgs.push_back(Args.MakeArgString("-debug")); 199 CmdArgs.push_back(Args.MakeArgString("-incremental:no")); 200 if (TC.getSanitizerArgs(Args).needsSharedRt() || 201 Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { 202 for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) 203 CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); 204 // Make sure the dynamic runtime thunk is not optimized out at link time 205 // to ensure proper SEH handling. 206 CmdArgs.push_back(Args.MakeArgString( 207 TC.getArch() == llvm::Triple::x86 208 ? "-include:___asan_seh_interceptor" 209 : "-include:__asan_seh_interceptor")); 210 // Make sure the linker consider all object files from the dynamic runtime 211 // thunk. 212 CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + 213 TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); 214 } else if (DLL) { 215 CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); 216 } else { 217 for (const auto &Lib : {"asan", "asan_cxx"}) { 218 CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); 219 // Make sure the linker consider all object files from the static lib. 220 // This is necessary because instrumented dlls need access to all the 221 // interface exported by the static lib in the main executable. 222 CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + 223 TC.getCompilerRT(Args, Lib))); 224 } 225 } 226 } 227 228 Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); 229 230 // Control Flow Guard checks 231 if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { 232 StringRef GuardArgs = A->getValue(); 233 if (GuardArgs.equals_insensitive("cf") || 234 GuardArgs.equals_insensitive("cf,nochecks")) { 235 // MSVC doesn't yet support the "nochecks" modifier. 236 CmdArgs.push_back("-guard:cf"); 237 } else if (GuardArgs.equals_insensitive("cf-")) { 238 CmdArgs.push_back("-guard:cf-"); 239 } else if (GuardArgs.equals_insensitive("ehcont")) { 240 CmdArgs.push_back("-guard:ehcont"); 241 } else if (GuardArgs.equals_insensitive("ehcont-")) { 242 CmdArgs.push_back("-guard:ehcont-"); 243 } 244 } 245 246 if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, 247 options::OPT_fno_openmp, false)) { 248 CmdArgs.push_back("-nodefaultlib:vcomp.lib"); 249 CmdArgs.push_back("-nodefaultlib:vcompd.lib"); 250 CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + 251 TC.getDriver().Dir + "/../lib")); 252 switch (TC.getDriver().getOpenMPRuntime(Args)) { 253 case Driver::OMPRT_OMP: 254 CmdArgs.push_back("-defaultlib:libomp.lib"); 255 break; 256 case Driver::OMPRT_IOMP5: 257 CmdArgs.push_back("-defaultlib:libiomp5md.lib"); 258 break; 259 case Driver::OMPRT_GOMP: 260 break; 261 case Driver::OMPRT_Unknown: 262 // Already diagnosed. 263 break; 264 } 265 } 266 267 // Add compiler-rt lib in case if it was explicitly 268 // specified as an argument for --rtlib option. 269 if (!Args.hasArg(options::OPT_nostdlib)) { 270 AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); 271 } 272 273 // Add filenames, libraries, and other linker inputs. 274 for (const auto &Input : Inputs) { 275 if (Input.isFilename()) { 276 CmdArgs.push_back(Input.getFilename()); 277 continue; 278 } 279 280 const Arg &A = Input.getInputArg(); 281 282 // Render -l options differently for the MSVC linker. 283 if (A.getOption().matches(options::OPT_l)) { 284 StringRef Lib = A.getValue(); 285 const char *LinkLibArg; 286 if (Lib.endswith(".lib")) 287 LinkLibArg = Args.MakeArgString(Lib); 288 else 289 LinkLibArg = Args.MakeArgString(Lib + ".lib"); 290 CmdArgs.push_back(LinkLibArg); 291 continue; 292 } 293 294 // Otherwise, this is some other kind of linker input option like -Wl, -z, 295 // or -L. Render it, even if MSVC doesn't understand it. 296 A.renderAsInput(Args, CmdArgs); 297 } 298 299 addHIPRuntimeLibArgs(TC, Args, CmdArgs); 300 301 TC.addProfileRTLibs(Args, CmdArgs); 302 303 std::vector<const char *> Environment; 304 305 // We need to special case some linker paths. In the case of lld, we need to 306 // translate 'lld' into 'lld-link', and in the case of the regular msvc 307 // linker, we need to use a special search algorithm. 308 llvm::SmallString<128> linkPath; 309 StringRef Linker 310 = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); 311 if (Linker.empty()) 312 Linker = "link"; 313 if (Linker.equals_insensitive("lld")) 314 Linker = "lld-link"; 315 316 if (Linker.equals_insensitive("link")) { 317 // If we're using the MSVC linker, it's not sufficient to just use link 318 // from the program PATH, because other environments like GnuWin32 install 319 // their own link.exe which may come first. 320 linkPath = FindVisualStudioExecutable(TC, "link.exe"); 321 322 if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) { 323 llvm::SmallString<128> ClPath; 324 ClPath = TC.GetProgramPath("cl.exe"); 325 if (canExecute(TC.getVFS(), ClPath)) { 326 linkPath = llvm::sys::path::parent_path(ClPath); 327 llvm::sys::path::append(linkPath, "link.exe"); 328 if (!canExecute(TC.getVFS(), linkPath)) 329 C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found); 330 } else { 331 C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found); 332 } 333 } 334 335 #ifdef _WIN32 336 // When cross-compiling with VS2017 or newer, link.exe expects to have 337 // its containing bin directory at the top of PATH, followed by the 338 // native target bin directory. 339 // e.g. when compiling for x86 on an x64 host, PATH should start with: 340 // /bin/Hostx64/x86;/bin/Hostx64/x64 341 // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal. 342 if (TC.getIsVS2017OrNewer() && 343 llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) { 344 auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch(); 345 346 auto EnvBlockWide = 347 std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>( 348 GetEnvironmentStringsW(), FreeEnvironmentStringsW); 349 if (!EnvBlockWide) 350 goto SkipSettingEnvironment; 351 352 size_t EnvCount = 0; 353 size_t EnvBlockLen = 0; 354 while (EnvBlockWide[EnvBlockLen] != L'\0') { 355 ++EnvCount; 356 EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) + 357 1 /*string null-terminator*/; 358 } 359 ++EnvBlockLen; // add the block null-terminator 360 361 std::string EnvBlock; 362 if (!llvm::convertUTF16ToUTF8String( 363 llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()), 364 EnvBlockLen * sizeof(EnvBlockWide[0])), 365 EnvBlock)) 366 goto SkipSettingEnvironment; 367 368 Environment.reserve(EnvCount); 369 370 // Now loop over each string in the block and copy them into the 371 // environment vector, adjusting the PATH variable as needed when we 372 // find it. 373 for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { 374 llvm::StringRef EnvVar(Cursor); 375 if (EnvVar.startswith_insensitive("path=")) { 376 constexpr size_t PrefixLen = 5; // strlen("path=") 377 Environment.push_back(Args.MakeArgString( 378 EnvVar.substr(0, PrefixLen) + 379 TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) + 380 llvm::Twine(llvm::sys::EnvPathSeparator) + 381 TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) + 382 (EnvVar.size() > PrefixLen 383 ? llvm::Twine(llvm::sys::EnvPathSeparator) + 384 EnvVar.substr(PrefixLen) 385 : ""))); 386 } else { 387 Environment.push_back(Args.MakeArgString(EnvVar)); 388 } 389 Cursor += EnvVar.size() + 1 /*null-terminator*/; 390 } 391 } 392 SkipSettingEnvironment:; 393 #endif 394 } else { 395 linkPath = TC.GetProgramPath(Linker.str().c_str()); 396 } 397 398 auto LinkCmd = std::make_unique<Command>( 399 JA, *this, ResponseFileSupport::AtFileUTF16(), 400 Args.MakeArgString(linkPath), CmdArgs, Inputs, Output); 401 if (!Environment.empty()) 402 LinkCmd->setEnvironment(Environment); 403 C.addCommand(std::move(LinkCmd)); 404 } 405 406 MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, 407 const ArgList &Args) 408 : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), 409 RocmInstallation(D, Triple, Args) { 410 getProgramPaths().push_back(getDriver().getInstalledDir()); 411 if (getDriver().getInstalledDir() != getDriver().Dir) 412 getProgramPaths().push_back(getDriver().Dir); 413 414 Optional<llvm::StringRef> VCToolsDir, VCToolsVersion; 415 if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir)) 416 VCToolsDir = A->getValue(); 417 if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion)) 418 VCToolsVersion = A->getValue(); 419 if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir)) 420 WinSdkDir = A->getValue(); 421 if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) 422 WinSdkVersion = A->getValue(); 423 if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot)) 424 WinSysRoot = A->getValue(); 425 426 // Check the command line first, that's the user explicitly telling us what to 427 // use. Check the environment next, in case we're being invoked from a VS 428 // command prompt. Failing that, just try to find the newest Visual Studio 429 // version we can and use its default VC toolchain. 430 llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion, 431 WinSysRoot, VCToolChainPath, VSLayout) || 432 llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, 433 VSLayout) || 434 llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, 435 VSLayout) || 436 llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout); 437 } 438 439 Tool *MSVCToolChain::buildLinker() const { 440 return new tools::visualstudio::Linker(*this); 441 } 442 443 Tool *MSVCToolChain::buildAssembler() const { 444 if (getTriple().isOSBinFormatMachO()) 445 return new tools::darwin::Assembler(*this); 446 getDriver().Diag(clang::diag::err_no_external_assembler); 447 return nullptr; 448 } 449 450 bool MSVCToolChain::IsIntegratedAssemblerDefault() const { 451 return true; 452 } 453 454 bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { 455 // Don't emit unwind tables by default for MachO targets. 456 if (getTriple().isOSBinFormatMachO()) 457 return false; 458 459 // All non-x86_32 Windows targets require unwind tables. However, LLVM 460 // doesn't know how to generate them for all targets, so only enable 461 // the ones that are actually implemented. 462 return getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || 463 getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64; 464 } 465 466 bool MSVCToolChain::isPICDefault() const { 467 return getArch() == llvm::Triple::x86_64 || 468 getArch() == llvm::Triple::aarch64; 469 } 470 471 bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { 472 return false; 473 } 474 475 bool MSVCToolChain::isPICDefaultForced() const { 476 return getArch() == llvm::Triple::x86_64 || 477 getArch() == llvm::Triple::aarch64; 478 } 479 480 void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, 481 ArgStringList &CC1Args) const { 482 CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); 483 } 484 485 void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, 486 ArgStringList &CC1Args) const { 487 RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); 488 } 489 490 void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args, 491 ArgStringList &CmdArgs) const { 492 CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") + 493 RocmInstallation.getLibPath()), 494 "amdhip64.lib"}); 495 } 496 497 void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { 498 CudaInstallation.print(OS); 499 RocmInstallation.print(OS); 500 } 501 502 std::string 503 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, 504 llvm::StringRef SubdirParent) const { 505 return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(), 506 SubdirParent); 507 } 508 509 std::string 510 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, 511 llvm::Triple::ArchType TargetArch) const { 512 return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch, 513 ""); 514 } 515 516 // Find the most recent version of Universal CRT or Windows 10 SDK. 517 // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include 518 // directory by name and uses the last one of the list. 519 // So we compare entry names lexicographically to find the greatest one. 520 // Gets the library path required to link against the Windows SDK. 521 bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args, 522 std::string &path) const { 523 std::string sdkPath; 524 int sdkMajor = 0; 525 std::string windowsSDKIncludeVersion; 526 std::string windowsSDKLibVersion; 527 528 path.clear(); 529 if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, 530 sdkPath, sdkMajor, windowsSDKIncludeVersion, 531 windowsSDKLibVersion)) 532 return false; 533 534 llvm::SmallString<128> libPath(sdkPath); 535 llvm::sys::path::append(libPath, "Lib"); 536 if (sdkMajor >= 8) 537 llvm::sys::path::append(libPath, windowsSDKLibVersion, "um"); 538 return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(), 539 path); 540 } 541 542 bool MSVCToolChain::useUniversalCRT() const { 543 return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS()); 544 } 545 546 bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, 547 std::string &Path) const { 548 std::string UniversalCRTSdkPath; 549 std::string UCRTVersion; 550 551 Path.clear(); 552 if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, 553 WinSysRoot, UniversalCRTSdkPath, 554 UCRTVersion)) 555 return false; 556 557 StringRef ArchName = llvm::archToWindowsSDKArch(getArch()); 558 if (ArchName.empty()) 559 return false; 560 561 llvm::SmallString<128> LibPath(UniversalCRTSdkPath); 562 llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); 563 564 Path = std::string(LibPath.str()); 565 return true; 566 } 567 568 static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) { 569 VersionTuple Version; 570 #ifdef _WIN32 571 SmallString<128> ClExe(BinDir); 572 llvm::sys::path::append(ClExe, "cl.exe"); 573 574 std::wstring ClExeWide; 575 if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide)) 576 return Version; 577 578 const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(), 579 nullptr); 580 if (VersionSize == 0) 581 return Version; 582 583 SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize); 584 if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize, 585 VersionBlock.data())) 586 return Version; 587 588 VS_FIXEDFILEINFO *FileInfo = nullptr; 589 UINT FileInfoSize = 0; 590 if (!::VerQueryValueW(VersionBlock.data(), L"\\", 591 reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) || 592 FileInfoSize < sizeof(*FileInfo)) 593 return Version; 594 595 const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF; 596 const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF; 597 const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF; 598 599 Version = VersionTuple(Major, Minor, Micro); 600 #endif 601 return Version; 602 } 603 604 void MSVCToolChain::AddSystemIncludeWithSubfolder( 605 const ArgList &DriverArgs, ArgStringList &CC1Args, 606 const std::string &folder, const Twine &subfolder1, const Twine &subfolder2, 607 const Twine &subfolder3) const { 608 llvm::SmallString<128> path(folder); 609 llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3); 610 addSystemInclude(DriverArgs, CC1Args, path); 611 } 612 613 void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 614 ArgStringList &CC1Args) const { 615 if (DriverArgs.hasArg(options::OPT_nostdinc)) 616 return; 617 618 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 619 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir, 620 "include"); 621 } 622 623 // Add %INCLUDE%-like directories from the -imsvc flag. 624 for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc)) 625 addSystemInclude(DriverArgs, CC1Args, Path); 626 627 auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool { 628 if (auto Val = llvm::sys::Process::GetEnv(Var)) { 629 SmallVector<StringRef, 8> Dirs; 630 StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false); 631 if (!Dirs.empty()) { 632 addSystemIncludes(DriverArgs, CC1Args, Dirs); 633 return true; 634 } 635 } 636 return false; 637 }; 638 639 // Add %INCLUDE%-like dirs via /external:env: flags. 640 for (const auto &Var : 641 DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) { 642 AddSystemIncludesFromEnv(Var); 643 } 644 645 // Add DIA SDK include if requested. 646 if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir, 647 options::OPT__SLASH_winsysroot)) { 648 // cl.exe doesn't find the DIA SDK automatically, so this too requires 649 // explicit flags and doesn't automatically look in "DIA SDK" relative 650 // to the path we found for VCToolChainPath. 651 llvm::SmallString<128> DIASDKPath(A->getValue()); 652 if (A->getOption().getID() == options::OPT__SLASH_winsysroot) 653 llvm::sys::path::append(DIASDKPath, "DIA SDK"); 654 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath), 655 "include"); 656 } 657 658 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 659 return; 660 661 // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search 662 // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir. 663 if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir, 664 options::OPT__SLASH_winsysroot)) { 665 bool Found = AddSystemIncludesFromEnv("INCLUDE"); 666 Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE"); 667 if (Found) 668 return; 669 } 670 671 // When built with access to the proper Windows APIs, try to actually find 672 // the correct include paths first. 673 if (!VCToolChainPath.empty()) { 674 addSystemInclude(DriverArgs, CC1Args, 675 getSubDirectoryPath(llvm::SubDirectoryType::Include)); 676 addSystemInclude( 677 DriverArgs, CC1Args, 678 getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc")); 679 680 if (useUniversalCRT()) { 681 std::string UniversalCRTSdkPath; 682 std::string UCRTVersion; 683 if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, 684 WinSysRoot, UniversalCRTSdkPath, 685 UCRTVersion)) { 686 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, 687 "Include", UCRTVersion, "ucrt"); 688 } 689 } 690 691 std::string WindowsSDKDir; 692 int major = 0; 693 std::string windowsSDKIncludeVersion; 694 std::string windowsSDKLibVersion; 695 if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, 696 WindowsSDKDir, major, windowsSDKIncludeVersion, 697 windowsSDKLibVersion)) { 698 if (major >= 8) { 699 // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. 700 // Anyway, llvm::sys::path::append is able to manage it. 701 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, 702 "Include", windowsSDKIncludeVersion, 703 "shared"); 704 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, 705 "Include", windowsSDKIncludeVersion, 706 "um"); 707 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, 708 "Include", windowsSDKIncludeVersion, 709 "winrt"); 710 if (major >= 10) { 711 llvm::VersionTuple Tuple; 712 if (!Tuple.tryParse(windowsSDKIncludeVersion) && 713 Tuple.getSubminor().value_or(0) >= 17134) { 714 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, 715 "Include", windowsSDKIncludeVersion, 716 "cppwinrt"); 717 } 718 } 719 } else { 720 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, 721 "Include"); 722 } 723 } 724 725 return; 726 } 727 728 #if defined(_WIN32) 729 // As a fallback, select default install paths. 730 // FIXME: Don't guess drives and paths like this on Windows. 731 const StringRef Paths[] = { 732 "C:/Program Files/Microsoft Visual Studio 10.0/VC/include", 733 "C:/Program Files/Microsoft Visual Studio 9.0/VC/include", 734 "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", 735 "C:/Program Files/Microsoft Visual Studio 8/VC/include", 736 "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" 737 }; 738 addSystemIncludes(DriverArgs, CC1Args, Paths); 739 #endif 740 } 741 742 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, 743 ArgStringList &CC1Args) const { 744 // FIXME: There should probably be logic here to find libc++ on Windows. 745 } 746 747 VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, 748 const ArgList &Args) const { 749 bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); 750 VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); 751 if (MSVT.empty()) 752 MSVT = getTriple().getEnvironmentVersion(); 753 if (MSVT.empty() && IsWindowsMSVC) 754 MSVT = 755 getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin)); 756 if (MSVT.empty() && 757 Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, 758 IsWindowsMSVC)) { 759 // -fms-compatibility-version=19.20 is default, aka 2019, 16.x 760 MSVT = VersionTuple(19, 20); 761 } 762 return MSVT; 763 } 764 765 std::string 766 MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, 767 types::ID InputType) const { 768 // The MSVC version doesn't care about the architecture, even though it 769 // may look at the triple internally. 770 VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); 771 MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0), 772 MSVT.getSubminor().value_or(0)); 773 774 // For the rest of the triple, however, a computed architecture name may 775 // be needed. 776 llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType)); 777 if (Triple.getEnvironment() == llvm::Triple::MSVC) { 778 StringRef ObjFmt = Triple.getEnvironmentName().split('-').second; 779 if (ObjFmt.empty()) 780 Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str()); 781 else 782 Triple.setEnvironmentName( 783 (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str()); 784 } 785 return Triple.getTriple(); 786 } 787 788 SanitizerMask MSVCToolChain::getSupportedSanitizers() const { 789 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 790 Res |= SanitizerKind::Address; 791 Res |= SanitizerKind::PointerCompare; 792 Res |= SanitizerKind::PointerSubtract; 793 Res |= SanitizerKind::Fuzzer; 794 Res |= SanitizerKind::FuzzerNoLink; 795 Res &= ~SanitizerKind::CFIMFCall; 796 return Res; 797 } 798 799 static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, 800 bool SupportsForcingFramePointer, 801 const char *ExpandChar, const OptTable &Opts) { 802 assert(A->getOption().matches(options::OPT__SLASH_O)); 803 804 StringRef OptStr = A->getValue(); 805 for (size_t I = 0, E = OptStr.size(); I != E; ++I) { 806 const char &OptChar = *(OptStr.data() + I); 807 switch (OptChar) { 808 default: 809 break; 810 case '1': 811 case '2': 812 case 'x': 813 case 'd': 814 // Ignore /O[12xd] flags that aren't the last one on the command line. 815 // Only the last one gets expanded. 816 if (&OptChar != ExpandChar) { 817 A->claim(); 818 break; 819 } 820 if (OptChar == 'd') { 821 DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); 822 } else { 823 if (OptChar == '1') { 824 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); 825 } else if (OptChar == '2' || OptChar == 'x') { 826 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); 827 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); 828 } 829 if (SupportsForcingFramePointer && 830 !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) 831 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); 832 if (OptChar == '1' || OptChar == '2') 833 DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); 834 } 835 break; 836 case 'b': 837 if (I + 1 != E && isdigit(OptStr[I + 1])) { 838 switch (OptStr[I + 1]) { 839 case '0': 840 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); 841 break; 842 case '1': 843 DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); 844 break; 845 case '2': 846 DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); 847 break; 848 } 849 ++I; 850 } 851 break; 852 case 'g': 853 A->claim(); 854 break; 855 case 'i': 856 if (I + 1 != E && OptStr[I + 1] == '-') { 857 ++I; 858 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); 859 } else { 860 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); 861 } 862 break; 863 case 's': 864 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); 865 break; 866 case 't': 867 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); 868 break; 869 case 'y': { 870 bool OmitFramePointer = true; 871 if (I + 1 != E && OptStr[I + 1] == '-') { 872 OmitFramePointer = false; 873 ++I; 874 } 875 if (SupportsForcingFramePointer) { 876 if (OmitFramePointer) 877 DAL.AddFlagArg(A, 878 Opts.getOption(options::OPT_fomit_frame_pointer)); 879 else 880 DAL.AddFlagArg( 881 A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); 882 } else { 883 // Don't warn about /Oy- in x86-64 builds (where 884 // SupportsForcingFramePointer is false). The flag having no effect 885 // there is a compiler-internal optimization, and people shouldn't have 886 // to special-case their build files for x86-64 clang-cl. 887 A->claim(); 888 } 889 break; 890 } 891 } 892 } 893 } 894 895 static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, 896 const OptTable &Opts) { 897 assert(A->getOption().matches(options::OPT_D)); 898 899 StringRef Val = A->getValue(); 900 size_t Hash = Val.find('#'); 901 if (Hash == StringRef::npos || Hash > Val.find('=')) { 902 DAL.append(A); 903 return; 904 } 905 906 std::string NewVal = std::string(Val); 907 NewVal[Hash] = '='; 908 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal); 909 } 910 911 static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL, 912 const OptTable &Opts) { 913 DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_)); 914 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names)); 915 } 916 917 static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL, 918 const OptTable &Opts) { 919 DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase)); 920 DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names)); 921 } 922 923 llvm::opt::DerivedArgList * 924 MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, 925 StringRef BoundArch, 926 Action::OffloadKind OFK) const { 927 DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); 928 const OptTable &Opts = getDriver().getOpts(); 929 930 // /Oy and /Oy- don't have an effect on X86-64 931 bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64; 932 933 // The -O[12xd] flag actually expands to several flags. We must desugar the 934 // flags so that options embedded can be negated. For example, the '-O2' flag 935 // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to 936 // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single 937 // aspect of '-O2'. 938 // 939 // Note that this expansion logic only applies to the *last* of '[12xd]'. 940 941 // First step is to search for the character we'd like to expand. 942 const char *ExpandChar = nullptr; 943 for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { 944 StringRef OptStr = A->getValue(); 945 for (size_t I = 0, E = OptStr.size(); I != E; ++I) { 946 char OptChar = OptStr[I]; 947 char PrevChar = I > 0 ? OptStr[I - 1] : '0'; 948 if (PrevChar == 'b') { 949 // OptChar does not expand; it's an argument to the previous char. 950 continue; 951 } 952 if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') 953 ExpandChar = OptStr.data() + I; 954 } 955 } 956 957 for (Arg *A : Args) { 958 if (A->getOption().matches(options::OPT__SLASH_O)) { 959 // The -O flag actually takes an amalgam of other options. For example, 960 // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. 961 TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts); 962 } else if (A->getOption().matches(options::OPT_D)) { 963 // Translate -Dfoo#bar into -Dfoo=bar. 964 TranslateDArg(A, *DAL, Opts); 965 } else if (A->getOption().matches(options::OPT__SLASH_permissive)) { 966 // Expand /permissive 967 TranslatePermissive(A, *DAL, Opts); 968 } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) { 969 // Expand /permissive- 970 TranslatePermissiveMinus(A, *DAL, Opts); 971 } else if (OFK != Action::OFK_HIP) { 972 // HIP Toolchain translates input args by itself. 973 DAL->append(A); 974 } 975 } 976 977 return DAL; 978 } 979 980 void MSVCToolChain::addClangTargetOptions( 981 const ArgList &DriverArgs, ArgStringList &CC1Args, 982 Action::OffloadKind DeviceOffloadKind) const { 983 // MSVC STL kindly allows removing all usages of typeid by defining 984 // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti 985 if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti, 986 /*Default=*/false)) 987 CC1Args.push_back("-D_HAS_STATIC_RTTI=0"); 988 } 989