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