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