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