File: | clang/lib/Driver/ToolChains/MSVC.cpp |
Warning: | line 1289, column 17 The left operand of '>=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | ||||
9 | #include "MSVC.h" | |||
10 | #include "CommonArgs.h" | |||
11 | #include "Darwin.h" | |||
12 | #include "clang/Basic/CharInfo.h" | |||
13 | #include "clang/Basic/Version.h" | |||
14 | #include "clang/Config/config.h" | |||
15 | #include "clang/Driver/Compilation.h" | |||
16 | #include "clang/Driver/Driver.h" | |||
17 | #include "clang/Driver/DriverDiagnostic.h" | |||
18 | #include "clang/Driver/Options.h" | |||
19 | #include "clang/Driver/SanitizerArgs.h" | |||
20 | #include "llvm/ADT/StringExtras.h" | |||
21 | #include "llvm/ADT/StringSwitch.h" | |||
22 | #include "llvm/Option/Arg.h" | |||
23 | #include "llvm/Option/ArgList.h" | |||
24 | #include "llvm/Support/ConvertUTF.h" | |||
25 | #include "llvm/Support/ErrorHandling.h" | |||
26 | #include "llvm/Support/FileSystem.h" | |||
27 | #include "llvm/Support/Host.h" | |||
28 | #include "llvm/Support/MemoryBuffer.h" | |||
29 | #include "llvm/Support/Path.h" | |||
30 | #include "llvm/Support/Process.h" | |||
31 | #include "llvm/Support/VirtualFileSystem.h" | |||
32 | #include <cstdio> | |||
33 | ||||
34 | #ifdef _WIN32 | |||
35 | #define WIN32_LEAN_AND_MEAN | |||
36 | #define NOGDI | |||
37 | #ifndef NOMINMAX | |||
38 | #define NOMINMAX | |||
39 | #endif | |||
40 | #include <windows.h> | |||
41 | #endif | |||
42 | ||||
43 | #ifdef _MSC_VER | |||
44 | // Don't support SetupApi on MinGW. | |||
45 | #define USE_MSVC_SETUP_API | |||
46 | ||||
47 | // Make sure this comes before MSVCSetupApi.h | |||
48 | #include <comdef.h> | |||
49 | ||||
50 | #include "MSVCSetupApi.h" | |||
51 | #include "llvm/Support/COM.h" | |||
52 | _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); | |||
53 | _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); | |||
54 | _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); | |||
55 | _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); | |||
56 | _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); | |||
57 | _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); | |||
58 | #endif | |||
59 | ||||
60 | using namespace clang::driver; | |||
61 | using namespace clang::driver::toolchains; | |||
62 | using namespace clang::driver::tools; | |||
63 | using namespace clang; | |||
64 | using namespace llvm::opt; | |||
65 | ||||
66 | static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { | |||
67 | auto Status = VFS.status(Path); | |||
68 | if (!Status) | |||
69 | return false; | |||
70 | return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0; | |||
71 | } | |||
72 | ||||
73 | // Defined below. | |||
74 | // Forward declare this so there aren't too many things above the constructor. | |||
75 | static bool getSystemRegistryString(const char *keyPath, const char *valueName, | |||
76 | std::string &value, std::string *phValue); | |||
77 | ||||
78 | static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS, | |||
79 | StringRef Directory) { | |||
80 | std::string Highest; | |||
81 | llvm::VersionTuple HighestTuple; | |||
82 | ||||
83 | std::error_code EC; | |||
84 | for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC), | |||
85 | DirEnd; | |||
86 | !EC && DirIt != DirEnd; DirIt.increment(EC)) { | |||
87 | auto Status = VFS.status(DirIt->path()); | |||
88 | if (!Status || !Status->isDirectory()) | |||
89 | continue; | |||
90 | StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); | |||
91 | llvm::VersionTuple Tuple; | |||
92 | if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error. | |||
93 | continue; | |||
94 | if (Tuple > HighestTuple) { | |||
95 | HighestTuple = Tuple; | |||
96 | Highest = CandidateName.str(); | |||
97 | } | |||
98 | } | |||
99 | ||||
100 | return Highest; | |||
101 | } | |||
102 | ||||
103 | // Check command line arguments to try and find a toolchain. | |||
104 | static bool | |||
105 | findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args, | |||
106 | std::string &Path, | |||
107 | MSVCToolChain::ToolsetLayout &VSLayout) { | |||
108 | // Don't validate the input; trust the value supplied by the user. | |||
109 | // The primary motivation is to prevent unnecessary file and registry access. | |||
110 | if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir, | |||
111 | options::OPT__SLASH_winsysroot)) { | |||
112 | if (A->getOption().getID() == options::OPT__SLASH_winsysroot) { | |||
113 | llvm::SmallString<128> ToolsPath(A->getValue()); | |||
114 | llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC"); | |||
115 | std::string VCToolsVersion; | |||
116 | if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion)) | |||
117 | VCToolsVersion = A->getValue(); | |||
118 | else | |||
119 | VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath); | |||
120 | llvm::sys::path::append(ToolsPath, VCToolsVersion); | |||
121 | Path = std::string(ToolsPath.str()); | |||
122 | } else { | |||
123 | Path = A->getValue(); | |||
124 | } | |||
125 | VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; | |||
126 | return true; | |||
127 | } | |||
128 | return false; | |||
129 | } | |||
130 | ||||
131 | // Check various environment variables to try and find a toolchain. | |||
132 | static bool | |||
133 | findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path, | |||
134 | MSVCToolChain::ToolsetLayout &VSLayout) { | |||
135 | // These variables are typically set by vcvarsall.bat | |||
136 | // when launching a developer command prompt. | |||
137 | if (llvm::Optional<std::string> VCToolsInstallDir = | |||
138 | llvm::sys::Process::GetEnv("VCToolsInstallDir")) { | |||
139 | // This is only set by newer Visual Studios, and it leads straight to | |||
140 | // the toolchain directory. | |||
141 | Path = std::move(*VCToolsInstallDir); | |||
142 | VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; | |||
143 | return true; | |||
144 | } | |||
145 | if (llvm::Optional<std::string> VCInstallDir = | |||
146 | llvm::sys::Process::GetEnv("VCINSTALLDIR")) { | |||
147 | // If the previous variable isn't set but this one is, then we've found | |||
148 | // an older Visual Studio. This variable is set by newer Visual Studios too, | |||
149 | // so this check has to appear second. | |||
150 | // In older Visual Studios, the VC directory is the toolchain. | |||
151 | Path = std::move(*VCInstallDir); | |||
152 | VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; | |||
153 | return true; | |||
154 | } | |||
155 | ||||
156 | // We couldn't find any VC environment variables. Let's walk through PATH and | |||
157 | // see if it leads us to a VC toolchain bin directory. If it does, pick the | |||
158 | // first one that we find. | |||
159 | if (llvm::Optional<std::string> PathEnv = | |||
160 | llvm::sys::Process::GetEnv("PATH")) { | |||
161 | llvm::SmallVector<llvm::StringRef, 8> PathEntries; | |||
162 | llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator); | |||
163 | for (llvm::StringRef PathEntry : PathEntries) { | |||
164 | if (PathEntry.empty()) | |||
165 | continue; | |||
166 | ||||
167 | llvm::SmallString<256> ExeTestPath; | |||
168 | ||||
169 | // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. | |||
170 | ExeTestPath = PathEntry; | |||
171 | llvm::sys::path::append(ExeTestPath, "cl.exe"); | |||
172 | if (!VFS.exists(ExeTestPath)) | |||
173 | continue; | |||
174 | ||||
175 | // cl.exe existing isn't a conclusive test for a VC toolchain; clang also | |||
176 | // has a cl.exe. So let's check for link.exe too. | |||
177 | ExeTestPath = PathEntry; | |||
178 | llvm::sys::path::append(ExeTestPath, "link.exe"); | |||
179 | if (!VFS.exists(ExeTestPath)) | |||
180 | continue; | |||
181 | ||||
182 | // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. | |||
183 | llvm::StringRef TestPath = PathEntry; | |||
184 | bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin"); | |||
185 | if (!IsBin) { | |||
186 | // Strip any architecture subdir like "amd64". | |||
187 | TestPath = llvm::sys::path::parent_path(TestPath); | |||
188 | IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin"); | |||
189 | } | |||
190 | if (IsBin) { | |||
191 | llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath); | |||
192 | llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath); | |||
193 | if (ParentFilename.equals_lower("VC")) { | |||
194 | Path = std::string(ParentPath); | |||
195 | VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; | |||
196 | return true; | |||
197 | } | |||
198 | if (ParentFilename.equals_lower("x86ret") || | |||
199 | ParentFilename.equals_lower("x86chk") || | |||
200 | ParentFilename.equals_lower("amd64ret") || | |||
201 | ParentFilename.equals_lower("amd64chk")) { | |||
202 | Path = std::string(ParentPath); | |||
203 | VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal; | |||
204 | return true; | |||
205 | } | |||
206 | ||||
207 | } else { | |||
208 | // This could be a new (>=VS2017) toolchain. If it is, we should find | |||
209 | // path components with these prefixes when walking backwards through | |||
210 | // the path. | |||
211 | // Note: empty strings match anything. | |||
212 | llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "", | |||
213 | "MSVC", "Tools", "VC"}; | |||
214 | ||||
215 | auto It = llvm::sys::path::rbegin(PathEntry); | |||
216 | auto End = llvm::sys::path::rend(PathEntry); | |||
217 | for (llvm::StringRef Prefix : ExpectedPrefixes) { | |||
218 | if (It == End) | |||
219 | goto NotAToolChain; | |||
220 | if (!It->startswith_lower(Prefix)) | |||
221 | goto NotAToolChain; | |||
222 | ++It; | |||
223 | } | |||
224 | ||||
225 | // We've found a new toolchain! | |||
226 | // Back up 3 times (/bin/Host/arch) to get the root path. | |||
227 | llvm::StringRef ToolChainPath(PathEntry); | |||
228 | for (int i = 0; i < 3; ++i) | |||
229 | ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); | |||
230 | ||||
231 | Path = std::string(ToolChainPath); | |||
232 | VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; | |||
233 | return true; | |||
234 | } | |||
235 | ||||
236 | NotAToolChain: | |||
237 | continue; | |||
238 | } | |||
239 | } | |||
240 | return false; | |||
241 | } | |||
242 | ||||
243 | // Query the Setup Config server for installs, then pick the newest version | |||
244 | // and find its default VC toolchain. | |||
245 | // This is the preferred way to discover new Visual Studios, as they're no | |||
246 | // longer listed in the registry. | |||
247 | static bool | |||
248 | findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path, | |||
249 | MSVCToolChain::ToolsetLayout &VSLayout) { | |||
250 | #if !defined(USE_MSVC_SETUP_API) | |||
251 | return false; | |||
252 | #else | |||
253 | // FIXME: This really should be done once in the top-level program's main | |||
254 | // function, as it may have already been initialized with a different | |||
255 | // threading model otherwise. | |||
256 | llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded); | |||
257 | HRESULT HR; | |||
258 | ||||
259 | // _com_ptr_t will throw a _com_error if a COM calls fail. | |||
260 | // The LLVM coding standards forbid exception handling, so we'll have to | |||
261 | // stop them from being thrown in the first place. | |||
262 | // The destructor will put the regular error handler back when we leave | |||
263 | // this scope. | |||
264 | struct SuppressCOMErrorsRAII { | |||
265 | static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} | |||
266 | ||||
267 | SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } | |||
268 | ||||
269 | ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } | |||
270 | ||||
271 | } COMErrorSuppressor; | |||
272 | ||||
273 | ISetupConfigurationPtr Query; | |||
274 | HR = Query.CreateInstance(__uuidof(SetupConfiguration)); | |||
275 | if (FAILED(HR)) | |||
276 | return false; | |||
277 | ||||
278 | IEnumSetupInstancesPtr EnumInstances; | |||
279 | HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); | |||
280 | if (FAILED(HR)) | |||
281 | return false; | |||
282 | ||||
283 | ISetupInstancePtr Instance; | |||
284 | HR = EnumInstances->Next(1, &Instance, nullptr); | |||
285 | if (HR != S_OK) | |||
286 | return false; | |||
287 | ||||
288 | ISetupInstancePtr NewestInstance; | |||
289 | Optional<uint64_t> NewestVersionNum; | |||
290 | do { | |||
291 | bstr_t VersionString; | |||
292 | uint64_t VersionNum; | |||
293 | HR = Instance->GetInstallationVersion(VersionString.GetAddress()); | |||
294 | if (FAILED(HR)) | |||
295 | continue; | |||
296 | HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); | |||
297 | if (FAILED(HR)) | |||
298 | continue; | |||
299 | if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { | |||
300 | NewestInstance = Instance; | |||
301 | NewestVersionNum = VersionNum; | |||
302 | } | |||
303 | } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); | |||
304 | ||||
305 | if (!NewestInstance) | |||
306 | return false; | |||
307 | ||||
308 | bstr_t VCPathWide; | |||
309 | HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); | |||
310 | if (FAILED(HR)) | |||
311 | return false; | |||
312 | ||||
313 | std::string VCRootPath; | |||
314 | llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); | |||
315 | ||||
316 | llvm::SmallString<256> ToolsVersionFilePath(VCRootPath); | |||
317 | llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", | |||
318 | "Microsoft.VCToolsVersion.default.txt"); | |||
319 | ||||
320 | auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath); | |||
321 | if (!ToolsVersionFile) | |||
322 | return false; | |||
323 | ||||
324 | llvm::SmallString<256> ToolchainPath(VCRootPath); | |||
325 | llvm::sys::path::append(ToolchainPath, "Tools", "MSVC", | |||
326 | ToolsVersionFile->get()->getBuffer().rtrim()); | |||
327 | auto Status = VFS.status(ToolchainPath); | |||
328 | if (!Status || !Status->isDirectory()) | |||
329 | return false; | |||
330 | ||||
331 | Path = std::string(ToolchainPath.str()); | |||
332 | VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; | |||
333 | return true; | |||
334 | #endif | |||
335 | } | |||
336 | ||||
337 | // Look in the registry for Visual Studio installs, and use that to get | |||
338 | // a toolchain path. VS2017 and newer don't get added to the registry. | |||
339 | // So if we find something here, we know that it's an older version. | |||
340 | static bool findVCToolChainViaRegistry(std::string &Path, | |||
341 | MSVCToolChain::ToolsetLayout &VSLayout) { | |||
342 | std::string VSInstallPath; | |||
343 | if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", | |||
344 | "InstallDir", VSInstallPath, nullptr) || | |||
345 | getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", | |||
346 | "InstallDir", VSInstallPath, nullptr)) { | |||
347 | if (!VSInstallPath.empty()) { | |||
348 | llvm::SmallString<256> VCPath(llvm::StringRef( | |||
349 | VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)"))); | |||
350 | llvm::sys::path::append(VCPath, "VC"); | |||
351 | ||||
352 | Path = std::string(VCPath.str()); | |||
353 | VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; | |||
354 | return true; | |||
355 | } | |||
356 | } | |||
357 | return false; | |||
358 | } | |||
359 | ||||
360 | // Try to find Exe from a Visual Studio distribution. This first tries to find | |||
361 | // an installed copy of Visual Studio and, failing that, looks in the PATH, | |||
362 | // making sure that whatever executable that's found is not a same-named exe | |||
363 | // from clang itself to prevent clang from falling back to itself. | |||
364 | static std::string FindVisualStudioExecutable(const ToolChain &TC, | |||
365 | const char *Exe) { | |||
366 | const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); | |||
367 | SmallString<128> FilePath(MSVC.getSubDirectoryPath( | |||
368 | toolchains::MSVCToolChain::SubDirectoryType::Bin)); | |||
369 | llvm::sys::path::append(FilePath, Exe); | |||
370 | return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe); | |||
371 | } | |||
372 | ||||
373 | void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, | |||
374 | const InputInfo &Output, | |||
375 | const InputInfoList &Inputs, | |||
376 | const ArgList &Args, | |||
377 | const char *LinkingOutput) const { | |||
378 | ArgStringList CmdArgs; | |||
379 | ||||
380 | auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain()); | |||
381 | ||||
382 | assert((Output.isFilename() || Output.isNothing()) && "invalid output")(static_cast <bool> ((Output.isFilename() || Output.isNothing ()) && "invalid output") ? void (0) : __assert_fail ( "(Output.isFilename() || Output.isNothing()) && \"invalid output\"" , "/build/llvm-toolchain-snapshot-13~++20210621111111+acefe0eaaf82/clang/lib/Driver/ToolChains/MSVC.cpp" , 382, __extension__ __PRETTY_FUNCTION__)); | |||
383 | if (Output.isFilename()) | |||
384 | CmdArgs.push_back( | |||
385 | Args.MakeArgString(std::string("-out:") + Output.getFilename())); | |||
386 | ||||
387 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && | |||
388 | !C.getDriver().IsCLMode()) { | |||
389 | CmdArgs.push_back("-defaultlib:libcmt"); | |||
390 | CmdArgs.push_back("-defaultlib:oldnames"); | |||
391 | } | |||
392 | ||||
393 | // If the VC environment hasn't been configured (perhaps because the user | |||
394 | // did not run vcvarsall), try to build a consistent link environment. If | |||
395 | // the environment variable is set however, assume the user knows what | |||
396 | // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that | |||
397 | // over env vars. | |||
398 | if (!llvm::sys::Process::GetEnv("LIB") || | |||
399 | Args.getLastArg(options::OPT__SLASH_vctoolsdir, | |||
400 | options::OPT__SLASH_winsysroot)) { | |||
401 | CmdArgs.push_back(Args.MakeArgString( | |||
402 | Twine("-libpath:") + | |||
403 | TC.getSubDirectoryPath( | |||
404 | toolchains::MSVCToolChain::SubDirectoryType::Lib))); | |||
405 | CmdArgs.push_back(Args.MakeArgString( | |||
406 | Twine("-libpath:") + | |||
407 | TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib, | |||
408 | "atlmfc"))); | |||
409 | } | |||
410 | if (!llvm::sys::Process::GetEnv("LIB") || | |||
411 | Args.getLastArg(options::OPT__SLASH_winsdkdir, | |||
412 | options::OPT__SLASH_winsysroot)) { | |||
413 | if (TC.useUniversalCRT()) { | |||
414 | std::string UniversalCRTLibPath; | |||
415 | if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath)) | |||
416 | CmdArgs.push_back( | |||
417 | Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath)); | |||
418 | } | |||
419 | std::string WindowsSdkLibPath; | |||
420 | if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath)) | |||
421 | CmdArgs.push_back( | |||
422 | Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); | |||
423 | } | |||
424 | ||||
425 | // Add the compiler-rt library directories to libpath if they exist to help | |||
426 | // the linker find the various sanitizer, builtin, and profiling runtimes. | |||
427 | for (const auto &LibPath : TC.getLibraryPaths()) { | |||
428 | if (TC.getVFS().exists(LibPath)) | |||
429 | CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); | |||
430 | } | |||
431 | auto CRTPath = TC.getCompilerRTPath(); | |||
432 | if (TC.getVFS().exists(CRTPath)) | |||
433 | CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath)); | |||
434 | ||||
435 | if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) | |||
436 | for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) | |||
437 | CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); | |||
438 | ||||
439 | CmdArgs.push_back("-nologo"); | |||
440 | ||||
441 | if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) | |||
442 | CmdArgs.push_back("-debug"); | |||
443 | ||||
444 | // Pass on /Brepro if it was passed to the compiler. | |||
445 | // Note that /Brepro maps to -mno-incremental-linker-compatible. | |||
446 | bool DefaultIncrementalLinkerCompatible = | |||
447 | C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); | |||
448 | if (!Args.hasFlag(options::OPT_mincremental_linker_compatible, | |||
449 | options::OPT_mno_incremental_linker_compatible, | |||
450 | DefaultIncrementalLinkerCompatible)) | |||
451 | CmdArgs.push_back("-Brepro"); | |||
452 | ||||
453 | bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, | |||
454 | options::OPT_shared); | |||
455 | if (DLL) { | |||
456 | CmdArgs.push_back(Args.MakeArgString("-dll")); | |||
457 | ||||
458 | SmallString<128> ImplibName(Output.getFilename()); | |||
459 | llvm::sys::path::replace_extension(ImplibName, "lib"); | |||
460 | CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); | |||
461 | } | |||
462 | ||||
463 | if (TC.getSanitizerArgs().needsFuzzer()) { | |||
464 | if (!Args.hasArg(options::OPT_shared)) | |||
465 | CmdArgs.push_back( | |||
466 | Args.MakeArgString(std::string("-wholearchive:") + | |||
467 | TC.getCompilerRTArgString(Args, "fuzzer"))); | |||
468 | CmdArgs.push_back(Args.MakeArgString("-debug")); | |||
469 | // Prevent the linker from padding sections we use for instrumentation | |||
470 | // arrays. | |||
471 | CmdArgs.push_back(Args.MakeArgString("-incremental:no")); | |||
472 | } | |||
473 | ||||
474 | if (TC.getSanitizerArgs().needsAsanRt()) { | |||
475 | CmdArgs.push_back(Args.MakeArgString("-debug")); | |||
476 | CmdArgs.push_back(Args.MakeArgString("-incremental:no")); | |||
477 | if (TC.getSanitizerArgs().needsSharedRt() || | |||
478 | Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { | |||
479 | for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) | |||
480 | CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); | |||
481 | // Make sure the dynamic runtime thunk is not optimized out at link time | |||
482 | // to ensure proper SEH handling. | |||
483 | CmdArgs.push_back(Args.MakeArgString( | |||
484 | TC.getArch() == llvm::Triple::x86 | |||
485 | ? "-include:___asan_seh_interceptor" | |||
486 | : "-include:__asan_seh_interceptor")); | |||
487 | // Make sure the linker consider all object files from the dynamic runtime | |||
488 | // thunk. | |||
489 | CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + | |||
490 | TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); | |||
491 | } else if (DLL) { | |||
492 | CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); | |||
493 | } else { | |||
494 | for (const auto &Lib : {"asan", "asan_cxx"}) { | |||
495 | CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); | |||
496 | // Make sure the linker consider all object files from the static lib. | |||
497 | // This is necessary because instrumented dlls need access to all the | |||
498 | // interface exported by the static lib in the main executable. | |||
499 | CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + | |||
500 | TC.getCompilerRT(Args, Lib))); | |||
501 | } | |||
502 | } | |||
503 | } | |||
504 | ||||
505 | Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); | |||
506 | ||||
507 | // Control Flow Guard checks | |||
508 | if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { | |||
509 | StringRef GuardArgs = A->getValue(); | |||
510 | if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) { | |||
511 | // MSVC doesn't yet support the "nochecks" modifier. | |||
512 | CmdArgs.push_back("-guard:cf"); | |||
513 | } else if (GuardArgs.equals_lower("cf-")) { | |||
514 | CmdArgs.push_back("-guard:cf-"); | |||
515 | } else if (GuardArgs.equals_lower("ehcont")) { | |||
516 | CmdArgs.push_back("-guard:ehcont"); | |||
517 | } else if (GuardArgs.equals_lower("ehcont-")) { | |||
518 | CmdArgs.push_back("-guard:ehcont-"); | |||
519 | } | |||
520 | } | |||
521 | ||||
522 | if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, | |||
523 | options::OPT_fno_openmp, false)) { | |||
524 | CmdArgs.push_back("-nodefaultlib:vcomp.lib"); | |||
525 | CmdArgs.push_back("-nodefaultlib:vcompd.lib"); | |||
526 | CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + | |||
527 | TC.getDriver().Dir + "/../lib")); | |||
528 | switch (TC.getDriver().getOpenMPRuntime(Args)) { | |||
529 | case Driver::OMPRT_OMP: | |||
530 | CmdArgs.push_back("-defaultlib:libomp.lib"); | |||
531 | break; | |||
532 | case Driver::OMPRT_IOMP5: | |||
533 | CmdArgs.push_back("-defaultlib:libiomp5md.lib"); | |||
534 | break; | |||
535 | case Driver::OMPRT_GOMP: | |||
536 | break; | |||
537 | case Driver::OMPRT_Unknown: | |||
538 | // Already diagnosed. | |||
539 | break; | |||
540 | } | |||
541 | } | |||
542 | ||||
543 | // Add compiler-rt lib in case if it was explicitly | |||
544 | // specified as an argument for --rtlib option. | |||
545 | if (!Args.hasArg(options::OPT_nostdlib)) { | |||
546 | AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); | |||
547 | } | |||
548 | ||||
549 | // Add filenames, libraries, and other linker inputs. | |||
550 | for (const auto &Input : Inputs) { | |||
551 | if (Input.isFilename()) { | |||
552 | CmdArgs.push_back(Input.getFilename()); | |||
553 | continue; | |||
554 | } | |||
555 | ||||
556 | const Arg &A = Input.getInputArg(); | |||
557 | ||||
558 | // Render -l options differently for the MSVC linker. | |||
559 | if (A.getOption().matches(options::OPT_l)) { | |||
560 | StringRef Lib = A.getValue(); | |||
561 | const char *LinkLibArg; | |||
562 | if (Lib.endswith(".lib")) | |||
563 | LinkLibArg = Args.MakeArgString(Lib); | |||
564 | else | |||
565 | LinkLibArg = Args.MakeArgString(Lib + ".lib"); | |||
566 | CmdArgs.push_back(LinkLibArg); | |||
567 | continue; | |||
568 | } | |||
569 | ||||
570 | // Otherwise, this is some other kind of linker input option like -Wl, -z, | |||
571 | // or -L. Render it, even if MSVC doesn't understand it. | |||
572 | A.renderAsInput(Args, CmdArgs); | |||
573 | } | |||
574 | ||||
575 | TC.addProfileRTLibs(Args, CmdArgs); | |||
576 | ||||
577 | std::vector<const char *> Environment; | |||
578 | ||||
579 | // We need to special case some linker paths. In the case of lld, we need to | |||
580 | // translate 'lld' into 'lld-link', and in the case of the regular msvc | |||
581 | // linker, we need to use a special search algorithm. | |||
582 | llvm::SmallString<128> linkPath; | |||
583 | StringRef Linker | |||
584 | = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER""); | |||
585 | if (Linker.empty()) | |||
586 | Linker = "link"; | |||
587 | if (Linker.equals_lower("lld")) | |||
588 | Linker = "lld-link"; | |||
589 | ||||
590 | if (Linker.equals_lower("link")) { | |||
591 | // If we're using the MSVC linker, it's not sufficient to just use link | |||
592 | // from the program PATH, because other environments like GnuWin32 install | |||
593 | // their own link.exe which may come first. | |||
594 | linkPath = FindVisualStudioExecutable(TC, "link.exe"); | |||
595 | ||||
596 | if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) { | |||
597 | llvm::SmallString<128> ClPath; | |||
598 | ClPath = TC.GetProgramPath("cl.exe"); | |||
599 | if (canExecute(TC.getVFS(), ClPath)) { | |||
600 | linkPath = llvm::sys::path::parent_path(ClPath); | |||
601 | llvm::sys::path::append(linkPath, "link.exe"); | |||
602 | if (!canExecute(TC.getVFS(), linkPath)) | |||
603 | C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found); | |||
604 | } else { | |||
605 | C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found); | |||
606 | } | |||
607 | } | |||
608 | ||||
609 | #ifdef _WIN32 | |||
610 | // When cross-compiling with VS2017 or newer, link.exe expects to have | |||
611 | // its containing bin directory at the top of PATH, followed by the | |||
612 | // native target bin directory. | |||
613 | // e.g. when compiling for x86 on an x64 host, PATH should start with: | |||
614 | // /bin/Hostx64/x86;/bin/Hostx64/x64 | |||
615 | // This doesn't attempt to handle ToolsetLayout::DevDivInternal. | |||
616 | if (TC.getIsVS2017OrNewer() && | |||
617 | llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) { | |||
618 | auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch(); | |||
619 | ||||
620 | auto EnvBlockWide = | |||
621 | std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>( | |||
622 | GetEnvironmentStringsW(), FreeEnvironmentStringsW); | |||
623 | if (!EnvBlockWide) | |||
624 | goto SkipSettingEnvironment; | |||
625 | ||||
626 | size_t EnvCount = 0; | |||
627 | size_t EnvBlockLen = 0; | |||
628 | while (EnvBlockWide[EnvBlockLen] != L'\0') { | |||
629 | ++EnvCount; | |||
630 | EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) + | |||
631 | 1 /*string null-terminator*/; | |||
632 | } | |||
633 | ++EnvBlockLen; // add the block null-terminator | |||
634 | ||||
635 | std::string EnvBlock; | |||
636 | if (!llvm::convertUTF16ToUTF8String( | |||
637 | llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()), | |||
638 | EnvBlockLen * sizeof(EnvBlockWide[0])), | |||
639 | EnvBlock)) | |||
640 | goto SkipSettingEnvironment; | |||
641 | ||||
642 | Environment.reserve(EnvCount); | |||
643 | ||||
644 | // Now loop over each string in the block and copy them into the | |||
645 | // environment vector, adjusting the PATH variable as needed when we | |||
646 | // find it. | |||
647 | for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { | |||
648 | llvm::StringRef EnvVar(Cursor); | |||
649 | if (EnvVar.startswith_lower("path=")) { | |||
650 | using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType; | |||
651 | constexpr size_t PrefixLen = 5; // strlen("path=") | |||
652 | Environment.push_back(Args.MakeArgString( | |||
653 | EnvVar.substr(0, PrefixLen) + | |||
654 | TC.getSubDirectoryPath(SubDirectoryType::Bin) + | |||
655 | llvm::Twine(llvm::sys::EnvPathSeparator) + | |||
656 | TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) + | |||
657 | (EnvVar.size() > PrefixLen | |||
658 | ? llvm::Twine(llvm::sys::EnvPathSeparator) + | |||
659 | EnvVar.substr(PrefixLen) | |||
660 | : ""))); | |||
661 | } else { | |||
662 | Environment.push_back(Args.MakeArgString(EnvVar)); | |||
663 | } | |||
664 | Cursor += EnvVar.size() + 1 /*null-terminator*/; | |||
665 | } | |||
666 | } | |||
667 | SkipSettingEnvironment:; | |||
668 | #endif | |||
669 | } else { | |||
670 | linkPath = TC.GetProgramPath(Linker.str().c_str()); | |||
671 | } | |||
672 | ||||
673 | auto LinkCmd = std::make_unique<Command>( | |||
674 | JA, *this, ResponseFileSupport::AtFileUTF16(), | |||
675 | Args.MakeArgString(linkPath), CmdArgs, Inputs, Output); | |||
676 | if (!Environment.empty()) | |||
677 | LinkCmd->setEnvironment(Environment); | |||
678 | C.addCommand(std::move(LinkCmd)); | |||
679 | } | |||
680 | ||||
681 | MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, | |||
682 | const ArgList &Args) | |||
683 | : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), | |||
684 | RocmInstallation(D, Triple, Args) { | |||
685 | getProgramPaths().push_back(getDriver().getInstalledDir()); | |||
686 | if (getDriver().getInstalledDir() != getDriver().Dir) | |||
687 | getProgramPaths().push_back(getDriver().Dir); | |||
688 | ||||
689 | // Check the command line first, that's the user explicitly telling us what to | |||
690 | // use. Check the environment next, in case we're being invoked from a VS | |||
691 | // command prompt. Failing that, just try to find the newest Visual Studio | |||
692 | // version we can and use its default VC toolchain. | |||
693 | findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) || | |||
694 | findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) || | |||
695 | findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) || | |||
696 | findVCToolChainViaRegistry(VCToolChainPath, VSLayout); | |||
697 | } | |||
698 | ||||
699 | Tool *MSVCToolChain::buildLinker() const { | |||
700 | return new tools::visualstudio::Linker(*this); | |||
701 | } | |||
702 | ||||
703 | Tool *MSVCToolChain::buildAssembler() const { | |||
704 | if (getTriple().isOSBinFormatMachO()) | |||
705 | return new tools::darwin::Assembler(*this); | |||
706 | getDriver().Diag(clang::diag::err_no_external_assembler); | |||
707 | return nullptr; | |||
708 | } | |||
709 | ||||
710 | bool MSVCToolChain::IsIntegratedAssemblerDefault() const { | |||
711 | return true; | |||
712 | } | |||
713 | ||||
714 | bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { | |||
715 | // Don't emit unwind tables by default for MachO targets. | |||
716 | if (getTriple().isOSBinFormatMachO()) | |||
717 | return false; | |||
718 | ||||
719 | // All non-x86_32 Windows targets require unwind tables. However, LLVM | |||
720 | // doesn't know how to generate them for all targets, so only enable | |||
721 | // the ones that are actually implemented. | |||
722 | return getArch() == llvm::Triple::x86_64 || | |||
723 | getArch() == llvm::Triple::aarch64; | |||
724 | } | |||
725 | ||||
726 | bool MSVCToolChain::isPICDefault() const { | |||
727 | return getArch() == llvm::Triple::x86_64; | |||
728 | } | |||
729 | ||||
730 | bool MSVCToolChain::isPIEDefault() const { | |||
731 | return false; | |||
732 | } | |||
733 | ||||
734 | bool MSVCToolChain::isPICDefaultForced() const { | |||
735 | return getArch() == llvm::Triple::x86_64; | |||
736 | } | |||
737 | ||||
738 | void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, | |||
739 | ArgStringList &CC1Args) const { | |||
740 | CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); | |||
741 | } | |||
742 | ||||
743 | void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, | |||
744 | ArgStringList &CC1Args) const { | |||
745 | RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); | |||
746 | } | |||
747 | ||||
748 | void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { | |||
749 | CudaInstallation.print(OS); | |||
750 | RocmInstallation.print(OS); | |||
751 | } | |||
752 | ||||
753 | // Windows SDKs and VC Toolchains group their contents into subdirectories based | |||
754 | // on the target architecture. This function converts an llvm::Triple::ArchType | |||
755 | // to the corresponding subdirectory name. | |||
756 | static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { | |||
757 | using ArchType = llvm::Triple::ArchType; | |||
758 | switch (Arch) { | |||
759 | case ArchType::x86: | |||
760 | return "x86"; | |||
761 | case ArchType::x86_64: | |||
762 | return "x64"; | |||
763 | case ArchType::arm: | |||
764 | return "arm"; | |||
765 | case ArchType::aarch64: | |||
766 | return "arm64"; | |||
767 | default: | |||
768 | return ""; | |||
769 | } | |||
770 | } | |||
771 | ||||
772 | // Similar to the above function, but for Visual Studios before VS2017. | |||
773 | static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { | |||
774 | using ArchType = llvm::Triple::ArchType; | |||
775 | switch (Arch) { | |||
776 | case ArchType::x86: | |||
777 | // x86 is default in legacy VC toolchains. | |||
778 | // e.g. x86 libs are directly in /lib as opposed to /lib/x86. | |||
779 | return ""; | |||
780 | case ArchType::x86_64: | |||
781 | return "amd64"; | |||
782 | case ArchType::arm: | |||
783 | return "arm"; | |||
784 | case ArchType::aarch64: | |||
785 | return "arm64"; | |||
786 | default: | |||
787 | return ""; | |||
788 | } | |||
789 | } | |||
790 | ||||
791 | // Similar to the above function, but for DevDiv internal builds. | |||
792 | static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { | |||
793 | using ArchType = llvm::Triple::ArchType; | |||
794 | switch (Arch) { | |||
795 | case ArchType::x86: | |||
796 | return "i386"; | |||
797 | case ArchType::x86_64: | |||
798 | return "amd64"; | |||
799 | case ArchType::arm: | |||
800 | return "arm"; | |||
801 | case ArchType::aarch64: | |||
802 | return "arm64"; | |||
803 | default: | |||
804 | return ""; | |||
805 | } | |||
806 | } | |||
807 | ||||
808 | // Get the path to a specific subdirectory in the current toolchain for | |||
809 | // a given target architecture. | |||
810 | // VS2017 changed the VC toolchain layout, so this should be used instead | |||
811 | // of hardcoding paths. | |||
812 | std::string | |||
813 | MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type, | |||
814 | llvm::StringRef SubdirParent, | |||
815 | llvm::Triple::ArchType TargetArch) const { | |||
816 | const char *SubdirName; | |||
817 | const char *IncludeName; | |||
818 | switch (VSLayout) { | |||
819 | case ToolsetLayout::OlderVS: | |||
820 | SubdirName = llvmArchToLegacyVCArch(TargetArch); | |||
821 | IncludeName = "include"; | |||
822 | break; | |||
823 | case ToolsetLayout::VS2017OrNewer: | |||
824 | SubdirName = llvmArchToWindowsSDKArch(TargetArch); | |||
825 | IncludeName = "include"; | |||
826 | break; | |||
827 | case ToolsetLayout::DevDivInternal: | |||
828 | SubdirName = llvmArchToDevDivInternalArch(TargetArch); | |||
829 | IncludeName = "inc"; | |||
830 | break; | |||
831 | } | |||
832 | ||||
833 | llvm::SmallString<256> Path(VCToolChainPath); | |||
834 | if (!SubdirParent.empty()) | |||
835 | llvm::sys::path::append(Path, SubdirParent); | |||
836 | ||||
837 | switch (Type) { | |||
838 | case SubDirectoryType::Bin: | |||
839 | if (VSLayout == ToolsetLayout::VS2017OrNewer) { | |||
840 | const bool HostIsX64 = | |||
841 | llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit(); | |||
842 | const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86"; | |||
843 | llvm::sys::path::append(Path, "bin", HostName, SubdirName); | |||
844 | } else { // OlderVS or DevDivInternal | |||
845 | llvm::sys::path::append(Path, "bin", SubdirName); | |||
846 | } | |||
847 | break; | |||
848 | case SubDirectoryType::Include: | |||
849 | llvm::sys::path::append(Path, IncludeName); | |||
850 | break; | |||
851 | case SubDirectoryType::Lib: | |||
852 | llvm::sys::path::append(Path, "lib", SubdirName); | |||
853 | break; | |||
854 | } | |||
855 | return std::string(Path.str()); | |||
856 | } | |||
857 | ||||
858 | #ifdef _WIN32 | |||
859 | static bool readFullStringValue(HKEY hkey, const char *valueName, | |||
860 | std::string &value) { | |||
861 | std::wstring WideValueName; | |||
862 | if (!llvm::ConvertUTF8toWide(valueName, WideValueName)) | |||
863 | return false; | |||
864 | ||||
865 | DWORD result = 0; | |||
866 | DWORD valueSize = 0; | |||
867 | DWORD type = 0; | |||
868 | // First just query for the required size. | |||
869 | result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL__null, &type, NULL__null, | |||
870 | &valueSize); | |||
871 | if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize) | |||
872 | return false; | |||
873 | std::vector<BYTE> buffer(valueSize); | |||
874 | result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL__null, NULL__null, &buffer[0], | |||
875 | &valueSize); | |||
876 | if (result == ERROR_SUCCESS) { | |||
877 | std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()), | |||
878 | valueSize / sizeof(wchar_t)); | |||
879 | if (valueSize && WideValue.back() == L'\0') { | |||
880 | WideValue.pop_back(); | |||
881 | } | |||
882 | // The destination buffer must be empty as an invariant of the conversion | |||
883 | // function; but this function is sometimes called in a loop that passes in | |||
884 | // the same buffer, however. Simply clear it out so we can overwrite it. | |||
885 | value.clear(); | |||
886 | return llvm::convertWideToUTF8(WideValue, value); | |||
887 | } | |||
888 | return false; | |||
889 | } | |||
890 | #endif | |||
891 | ||||
892 | /// Read registry string. | |||
893 | /// This also supports a means to look for high-versioned keys by use | |||
894 | /// of a $VERSION placeholder in the key path. | |||
895 | /// $VERSION in the key path is a placeholder for the version number, | |||
896 | /// causing the highest value path to be searched for and used. | |||
897 | /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". | |||
898 | /// There can be additional characters in the component. Only the numeric | |||
899 | /// characters are compared. This function only searches HKLM. | |||
900 | static bool getSystemRegistryString(const char *keyPath, const char *valueName, | |||
901 | std::string &value, std::string *phValue) { | |||
902 | #ifndef _WIN32 | |||
903 | return false; | |||
904 | #else | |||
905 | HKEY hRootKey = HKEY_LOCAL_MACHINE; | |||
906 | HKEY hKey = NULL__null; | |||
907 | long lResult; | |||
908 | bool returnValue = false; | |||
909 | ||||
910 | const char *placeHolder = strstr(keyPath, "$VERSION"); | |||
911 | std::string bestName; | |||
912 | // If we have a $VERSION placeholder, do the highest-version search. | |||
913 | if (placeHolder) { | |||
914 | const char *keyEnd = placeHolder - 1; | |||
915 | const char *nextKey = placeHolder; | |||
916 | // Find end of previous key. | |||
917 | while ((keyEnd > keyPath) && (*keyEnd != '\\')) | |||
918 | keyEnd--; | |||
919 | // Find end of key containing $VERSION. | |||
920 | while (*nextKey && (*nextKey != '\\')) | |||
921 | nextKey++; | |||
922 | size_t partialKeyLength = keyEnd - keyPath; | |||
923 | char partialKey[256]; | |||
924 | if (partialKeyLength >= sizeof(partialKey)) | |||
925 | partialKeyLength = sizeof(partialKey) - 1; | |||
926 | strncpy(partialKey, keyPath, partialKeyLength); | |||
927 | partialKey[partialKeyLength] = '\0'; | |||
928 | HKEY hTopKey = NULL__null; | |||
929 | lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, | |||
930 | &hTopKey); | |||
931 | if (lResult == ERROR_SUCCESS) { | |||
932 | char keyName[256]; | |||
933 | double bestValue = 0.0; | |||
934 | DWORD index, size = sizeof(keyName) - 1; | |||
935 | for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL__null, NULL__null, | |||
936 | NULL__null, NULL__null) == ERROR_SUCCESS; | |||
937 | index++) { | |||
938 | const char *sp = keyName; | |||
939 | while (*sp && !isDigit(*sp)) | |||
940 | sp++; | |||
941 | if (!*sp) | |||
942 | continue; | |||
943 | const char *ep = sp + 1; | |||
944 | while (*ep && (isDigit(*ep) || (*ep == '.'))) | |||
945 | ep++; | |||
946 | char numBuf[32]; | |||
947 | strncpy(numBuf, sp, sizeof(numBuf) - 1); | |||
948 | numBuf[sizeof(numBuf) - 1] = '\0'; | |||
949 | double dvalue = strtod(numBuf, NULL__null); | |||
950 | if (dvalue > bestValue) { | |||
951 | // Test that InstallDir is indeed there before keeping this index. | |||
952 | // Open the chosen key path remainder. | |||
953 | bestName = keyName; | |||
954 | // Append rest of key. | |||
955 | bestName.append(nextKey); | |||
956 | lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, | |||
957 | KEY_READ | KEY_WOW64_32KEY, &hKey); | |||
958 | if (lResult == ERROR_SUCCESS) { | |||
959 | if (readFullStringValue(hKey, valueName, value)) { | |||
960 | bestValue = dvalue; | |||
961 | if (phValue) | |||
962 | *phValue = bestName; | |||
963 | returnValue = true; | |||
964 | } | |||
965 | RegCloseKey(hKey); | |||
966 | } | |||
967 | } | |||
968 | size = sizeof(keyName) - 1; | |||
969 | } | |||
970 | RegCloseKey(hTopKey); | |||
971 | } | |||
972 | } else { | |||
973 | lResult = | |||
974 | RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); | |||
975 | if (lResult == ERROR_SUCCESS) { | |||
976 | if (readFullStringValue(hKey, valueName, value)) | |||
977 | returnValue = true; | |||
978 | if (phValue) | |||
979 | phValue->clear(); | |||
980 | RegCloseKey(hKey); | |||
981 | } | |||
982 | } | |||
983 | return returnValue; | |||
984 | #endif // _WIN32 | |||
985 | } | |||
986 | ||||
987 | // Find the most recent version of Universal CRT or Windows 10 SDK. | |||
988 | // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include | |||
989 | // directory by name and uses the last one of the list. | |||
990 | // So we compare entry names lexicographically to find the greatest one. | |||
991 | static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS, | |||
992 | const std::string &SDKPath, | |||
993 | std::string &SDKVersion) { | |||
994 | llvm::SmallString<128> IncludePath(SDKPath); | |||
995 | llvm::sys::path::append(IncludePath, "Include"); | |||
996 | SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath); | |||
997 | return !SDKVersion.empty(); | |||
998 | } | |||
999 | ||||
1000 | static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS, | |||
1001 | const ArgList &Args, | |||
1002 | std::string &Path, int &Major, | |||
1003 | std::string &Version) { | |||
1004 | if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir, | |||
1005 | options::OPT__SLASH_winsysroot)) { | |||
1006 | // Don't validate the input; trust the value supplied by the user. | |||
1007 | // The motivation is to prevent unnecessary file and registry access. | |||
1008 | llvm::VersionTuple SDKVersion; | |||
1009 | if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) | |||
1010 | SDKVersion.tryParse(A->getValue()); | |||
1011 | ||||
1012 | if (A->getOption().getID() == options::OPT__SLASH_winsysroot) { | |||
1013 | llvm::SmallString<128> SDKPath(A->getValue()); | |||
1014 | llvm::sys::path::append(SDKPath, "Windows Kits"); | |||
1015 | if (!SDKVersion.empty()) | |||
1016 | llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor())); | |||
1017 | else | |||
1018 | llvm::sys::path::append( | |||
1019 | SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath)); | |||
1020 | Path = std::string(SDKPath.str()); | |||
1021 | } else { | |||
1022 | Path = A->getValue(); | |||
1023 | } | |||
1024 | ||||
1025 | if (!SDKVersion.empty()) { | |||
1026 | Major = SDKVersion.getMajor(); | |||
1027 | Version = SDKVersion.getAsString(); | |||
1028 | } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) { | |||
1029 | Major = 10; | |||
1030 | } | |||
1031 | return true; | |||
1032 | } | |||
1033 | return false; | |||
1034 | } | |||
1035 | ||||
1036 | /// Get Windows SDK installation directory. | |||
1037 | static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args, | |||
1038 | std::string &Path, int &Major, | |||
1039 | std::string &WindowsSDKIncludeVersion, | |||
1040 | std::string &WindowsSDKLibVersion) { | |||
1041 | // Trust /winsdkdir and /winsdkversion if present. | |||
1042 | if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, | |||
1043 | WindowsSDKIncludeVersion)) { | |||
1044 | WindowsSDKLibVersion = WindowsSDKIncludeVersion; | |||
1045 | return true; | |||
1046 | } | |||
1047 | ||||
1048 | // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry. | |||
1049 | ||||
1050 | // Try the Windows registry. | |||
1051 | std::string RegistrySDKVersion; | |||
1052 | if (!getSystemRegistryString( | |||
1053 | "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", | |||
1054 | "InstallationFolder", Path, &RegistrySDKVersion)) | |||
1055 | return false; | |||
1056 | if (Path.empty() || RegistrySDKVersion.empty()) | |||
1057 | return false; | |||
1058 | ||||
1059 | WindowsSDKIncludeVersion.clear(); | |||
1060 | WindowsSDKLibVersion.clear(); | |||
1061 | Major = 0; | |||
1062 | std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); | |||
1063 | if (Major <= 7) | |||
1064 | return true; | |||
1065 | if (Major == 8) { | |||
1066 | // Windows SDK 8.x installs libraries in a folder whose names depend on the | |||
1067 | // version of the OS you're targeting. By default choose the newest, which | |||
1068 | // usually corresponds to the version of the OS you've installed the SDK on. | |||
1069 | const char *Tests[] = {"winv6.3", "win8", "win7"}; | |||
1070 | for (const char *Test : Tests) { | |||
1071 | llvm::SmallString<128> TestPath(Path); | |||
1072 | llvm::sys::path::append(TestPath, "Lib", Test); | |||
1073 | if (VFS.exists(TestPath)) { | |||
1074 | WindowsSDKLibVersion = Test; | |||
1075 | break; | |||
1076 | } | |||
1077 | } | |||
1078 | return !WindowsSDKLibVersion.empty(); | |||
1079 | } | |||
1080 | if (Major == 10) { | |||
1081 | if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion)) | |||
1082 | return false; | |||
1083 | WindowsSDKLibVersion = WindowsSDKIncludeVersion; | |||
1084 | return true; | |||
1085 | } | |||
1086 | // Unsupported SDK version | |||
1087 | return false; | |||
1088 | } | |||
1089 | ||||
1090 | // Gets the library path required to link against the Windows SDK. | |||
1091 | bool MSVCToolChain::getWindowsSDKLibraryPath( | |||
1092 | const ArgList &Args, std::string &path) const { | |||
1093 | std::string sdkPath; | |||
1094 | int sdkMajor = 0; | |||
1095 | std::string windowsSDKIncludeVersion; | |||
1096 | std::string windowsSDKLibVersion; | |||
1097 | ||||
1098 | path.clear(); | |||
1099 | if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor, | |||
1100 | windowsSDKIncludeVersion, windowsSDKLibVersion)) | |||
1101 | return false; | |||
1102 | ||||
1103 | llvm::SmallString<128> libPath(sdkPath); | |||
1104 | llvm::sys::path::append(libPath, "Lib"); | |||
1105 | if (sdkMajor >= 8) { | |||
1106 | llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", | |||
1107 | llvmArchToWindowsSDKArch(getArch())); | |||
1108 | } else { | |||
1109 | switch (getArch()) { | |||
1110 | // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. | |||
1111 | case llvm::Triple::x86: | |||
1112 | break; | |||
1113 | case llvm::Triple::x86_64: | |||
1114 | llvm::sys::path::append(libPath, "x64"); | |||
1115 | break; | |||
1116 | case llvm::Triple::arm: | |||
1117 | // It is not necessary to link against Windows SDK 7.x when targeting ARM. | |||
1118 | return false; | |||
1119 | default: | |||
1120 | return false; | |||
1121 | } | |||
1122 | } | |||
1123 | ||||
1124 | path = std::string(libPath.str()); | |||
1125 | return true; | |||
1126 | } | |||
1127 | ||||
1128 | // Check if the Include path of a specified version of Visual Studio contains | |||
1129 | // specific header files. If not, they are probably shipped with Universal CRT. | |||
1130 | bool MSVCToolChain::useUniversalCRT() const { | |||
1131 | llvm::SmallString<128> TestPath( | |||
1132 | getSubDirectoryPath(SubDirectoryType::Include)); | |||
1133 | llvm::sys::path::append(TestPath, "stdlib.h"); | |||
1134 | return !getVFS().exists(TestPath); | |||
1135 | } | |||
1136 | ||||
1137 | static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS, | |||
1138 | const ArgList &Args, std::string &Path, | |||
1139 | std::string &UCRTVersion) { | |||
1140 | // If /winsdkdir is passed, use it as location for the UCRT too. | |||
1141 | // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir? | |||
1142 | int Major; | |||
1143 | if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion)) | |||
1144 | return true; | |||
1145 | ||||
1146 | // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to | |||
1147 | // registry. | |||
1148 | ||||
1149 | // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry | |||
1150 | // for the specific key "KitsRoot10". So do we. | |||
1151 | if (!getSystemRegistryString( | |||
1152 | "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", | |||
1153 | Path, nullptr)) | |||
1154 | return false; | |||
1155 | ||||
1156 | return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion); | |||
1157 | } | |||
1158 | ||||
1159 | bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, | |||
1160 | std::string &Path) const { | |||
1161 | std::string UniversalCRTSdkPath; | |||
1162 | std::string UCRTVersion; | |||
1163 | ||||
1164 | Path.clear(); | |||
1165 | if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion)) | |||
1166 | return false; | |||
1167 | ||||
1168 | StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); | |||
1169 | if (ArchName.empty()) | |||
1170 | return false; | |||
1171 | ||||
1172 | llvm::SmallString<128> LibPath(UniversalCRTSdkPath); | |||
1173 | llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); | |||
1174 | ||||
1175 | Path = std::string(LibPath.str()); | |||
1176 | return true; | |||
1177 | } | |||
1178 | ||||
1179 | static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) { | |||
1180 | unsigned Major, Minor, Micro; | |||
1181 | Triple.getEnvironmentVersion(Major, Minor, Micro); | |||
1182 | if (Major || Minor || Micro) | |||
1183 | return VersionTuple(Major, Minor, Micro); | |||
1184 | return VersionTuple(); | |||
1185 | } | |||
1186 | ||||
1187 | static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) { | |||
1188 | VersionTuple Version; | |||
1189 | #ifdef _WIN32 | |||
1190 | SmallString<128> ClExe(BinDir); | |||
1191 | llvm::sys::path::append(ClExe, "cl.exe"); | |||
1192 | ||||
1193 | std::wstring ClExeWide; | |||
1194 | if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide)) | |||
1195 | return Version; | |||
1196 | ||||
1197 | const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(), | |||
1198 | nullptr); | |||
1199 | if (VersionSize == 0) | |||
1200 | return Version; | |||
1201 | ||||
1202 | SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize); | |||
1203 | if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize, | |||
1204 | VersionBlock.data())) | |||
1205 | return Version; | |||
1206 | ||||
1207 | VS_FIXEDFILEINFO *FileInfo = nullptr; | |||
1208 | UINT FileInfoSize = 0; | |||
1209 | if (!::VerQueryValueW(VersionBlock.data(), L"\\", | |||
1210 | reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) || | |||
1211 | FileInfoSize < sizeof(*FileInfo)) | |||
1212 | return Version; | |||
1213 | ||||
1214 | const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF; | |||
1215 | const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF; | |||
1216 | const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF; | |||
1217 | ||||
1218 | Version = VersionTuple(Major, Minor, Micro); | |||
1219 | #endif | |||
1220 | return Version; | |||
1221 | } | |||
1222 | ||||
1223 | void MSVCToolChain::AddSystemIncludeWithSubfolder( | |||
1224 | const ArgList &DriverArgs, ArgStringList &CC1Args, | |||
1225 | const std::string &folder, const Twine &subfolder1, const Twine &subfolder2, | |||
1226 | const Twine &subfolder3) const { | |||
1227 | llvm::SmallString<128> path(folder); | |||
1228 | llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3); | |||
1229 | addSystemInclude(DriverArgs, CC1Args, path); | |||
1230 | } | |||
1231 | ||||
1232 | void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, | |||
1233 | ArgStringList &CC1Args) const { | |||
1234 | if (DriverArgs.hasArg(options::OPT_nostdinc)) | |||
| ||||
1235 | return; | |||
1236 | ||||
1237 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { | |||
1238 | AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir, | |||
1239 | "include"); | |||
1240 | } | |||
1241 | ||||
1242 | // Add %INCLUDE%-like directories from the -imsvc flag. | |||
1243 | for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc)) | |||
1244 | addSystemInclude(DriverArgs, CC1Args, Path); | |||
1245 | ||||
1246 | if (DriverArgs.hasArg(options::OPT_nostdlibinc)) | |||
1247 | return; | |||
1248 | ||||
1249 | // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat. | |||
1250 | // Skip if the user expressly set a vctoolsdir | |||
1251 | if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir, | |||
1252 | options::OPT__SLASH_winsysroot)) { | |||
1253 | if (llvm::Optional<std::string> cl_include_dir = | |||
1254 | llvm::sys::Process::GetEnv("INCLUDE")) { | |||
1255 | SmallVector<StringRef, 8> Dirs; | |||
1256 | StringRef(*cl_include_dir) | |||
1257 | .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false); | |||
1258 | for (StringRef Dir : Dirs) | |||
1259 | addSystemInclude(DriverArgs, CC1Args, Dir); | |||
1260 | if (!Dirs.empty()) | |||
1261 | return; | |||
1262 | } | |||
1263 | } | |||
1264 | ||||
1265 | // When built with access to the proper Windows APIs, try to actually find | |||
1266 | // the correct include paths first. | |||
1267 | if (!VCToolChainPath.empty()) { | |||
1268 | addSystemInclude(DriverArgs, CC1Args, | |||
1269 | getSubDirectoryPath(SubDirectoryType::Include)); | |||
1270 | addSystemInclude(DriverArgs, CC1Args, | |||
1271 | getSubDirectoryPath(SubDirectoryType::Include, "atlmfc")); | |||
1272 | ||||
1273 | if (useUniversalCRT()) { | |||
1274 | std::string UniversalCRTSdkPath; | |||
1275 | std::string UCRTVersion; | |||
1276 | if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath, | |||
1277 | UCRTVersion)) { | |||
1278 | AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, | |||
1279 | "Include", UCRTVersion, "ucrt"); | |||
1280 | } | |||
1281 | } | |||
1282 | ||||
1283 | std::string WindowsSDKDir; | |||
1284 | int major; | |||
1285 | std::string windowsSDKIncludeVersion; | |||
1286 | std::string windowsSDKLibVersion; | |||
1287 | if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major, | |||
1288 | windowsSDKIncludeVersion, windowsSDKLibVersion)) { | |||
1289 | if (major >= 8) { | |||
| ||||
1290 | // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. | |||
1291 | // Anyway, llvm::sys::path::append is able to manage it. | |||
1292 | AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, | |||
1293 | "Include", windowsSDKIncludeVersion, | |||
1294 | "shared"); | |||
1295 | AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, | |||
1296 | "Include", windowsSDKIncludeVersion, | |||
1297 | "um"); | |||
1298 | AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, | |||
1299 | "Include", windowsSDKIncludeVersion, | |||
1300 | "winrt"); | |||
1301 | } else { | |||
1302 | AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, | |||
1303 | "Include"); | |||
1304 | } | |||
1305 | } | |||
1306 | ||||
1307 | return; | |||
1308 | } | |||
1309 | ||||
1310 | #if defined(_WIN32) | |||
1311 | // As a fallback, select default install paths. | |||
1312 | // FIXME: Don't guess drives and paths like this on Windows. | |||
1313 | const StringRef Paths[] = { | |||
1314 | "C:/Program Files/Microsoft Visual Studio 10.0/VC/include", | |||
1315 | "C:/Program Files/Microsoft Visual Studio 9.0/VC/include", | |||
1316 | "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", | |||
1317 | "C:/Program Files/Microsoft Visual Studio 8/VC/include", | |||
1318 | "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" | |||
1319 | }; | |||
1320 | addSystemIncludes(DriverArgs, CC1Args, Paths); | |||
1321 | #endif | |||
1322 | } | |||
1323 | ||||
1324 | void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, | |||
1325 | ArgStringList &CC1Args) const { | |||
1326 | // FIXME: There should probably be logic here to find libc++ on Windows. | |||
1327 | } | |||
1328 | ||||
1329 | VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, | |||
1330 | const ArgList &Args) const { | |||
1331 | bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); | |||
1332 | VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); | |||
1333 | if (MSVT.empty()) | |||
1334 | MSVT = getMSVCVersionFromTriple(getTriple()); | |||
1335 | if (MSVT.empty() && IsWindowsMSVC) | |||
1336 | MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin)); | |||
1337 | if (MSVT.empty() && | |||
1338 | Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, | |||
1339 | IsWindowsMSVC)) { | |||
1340 | // -fms-compatibility-version=19.14 is default, aka 2017, 15.7 | |||
1341 | MSVT = VersionTuple(19, 14); | |||
1342 | } | |||
1343 | return MSVT; | |||
1344 | } | |||
1345 | ||||
1346 | std::string | |||
1347 | MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, | |||
1348 | types::ID InputType) const { | |||
1349 | // The MSVC version doesn't care about the architecture, even though it | |||
1350 | // may look at the triple internally. | |||
1351 | VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); | |||
1352 | MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0), | |||
1353 | MSVT.getSubminor().getValueOr(0)); | |||
1354 | ||||
1355 | // For the rest of the triple, however, a computed architecture name may | |||
1356 | // be needed. | |||
1357 | llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType)); | |||
1358 | if (Triple.getEnvironment() == llvm::Triple::MSVC) { | |||
1359 | StringRef ObjFmt = Triple.getEnvironmentName().split('-').second; | |||
1360 | if (ObjFmt.empty()) | |||
1361 | Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str()); | |||
1362 | else | |||
1363 | Triple.setEnvironmentName( | |||
1364 | (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str()); | |||
1365 | } | |||
1366 | return Triple.getTriple(); | |||
1367 | } | |||
1368 | ||||
1369 | SanitizerMask MSVCToolChain::getSupportedSanitizers() const { | |||
1370 | SanitizerMask Res = ToolChain::getSupportedSanitizers(); | |||
1371 | Res |= SanitizerKind::Address; | |||
1372 | Res |= SanitizerKind::PointerCompare; | |||
1373 | Res |= SanitizerKind::PointerSubtract; | |||
1374 | Res |= SanitizerKind::Fuzzer; | |||
1375 | Res |= SanitizerKind::FuzzerNoLink; | |||
1376 | Res &= ~SanitizerKind::CFIMFCall; | |||
1377 | return Res; | |||
1378 | } | |||
1379 | ||||
1380 | static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, | |||
1381 | bool SupportsForcingFramePointer, | |||
1382 | const char *ExpandChar, const OptTable &Opts) { | |||
1383 | assert(A->getOption().matches(options::OPT__SLASH_O))(static_cast <bool> (A->getOption().matches(options:: OPT__SLASH_O)) ? void (0) : __assert_fail ("A->getOption().matches(options::OPT__SLASH_O)" , "/build/llvm-toolchain-snapshot-13~++20210621111111+acefe0eaaf82/clang/lib/Driver/ToolChains/MSVC.cpp" , 1383, __extension__ __PRETTY_FUNCTION__)); | |||
1384 | ||||
1385 | StringRef OptStr = A->getValue(); | |||
1386 | for (size_t I = 0, E = OptStr.size(); I != E; ++I) { | |||
1387 | const char &OptChar = *(OptStr.data() + I); | |||
1388 | switch (OptChar) { | |||
1389 | default: | |||
1390 | break; | |||
1391 | case '1': | |||
1392 | case '2': | |||
1393 | case 'x': | |||
1394 | case 'd': | |||
1395 | // Ignore /O[12xd] flags that aren't the last one on the command line. | |||
1396 | // Only the last one gets expanded. | |||
1397 | if (&OptChar != ExpandChar) { | |||
1398 | A->claim(); | |||
1399 | break; | |||
1400 | } | |||
1401 | if (OptChar == 'd') { | |||
1402 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); | |||
1403 | } else { | |||
1404 | if (OptChar == '1') { | |||
1405 | DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); | |||
1406 | } else if (OptChar == '2' || OptChar == 'x') { | |||
1407 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); | |||
1408 | DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); | |||
1409 | } | |||
1410 | if (SupportsForcingFramePointer && | |||
1411 | !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) | |||
1412 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); | |||
1413 | if (OptChar == '1' || OptChar == '2') | |||
1414 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); | |||
1415 | } | |||
1416 | break; | |||
1417 | case 'b': | |||
1418 | if (I + 1 != E && isdigit(OptStr[I + 1])) { | |||
1419 | switch (OptStr[I + 1]) { | |||
1420 | case '0': | |||
1421 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); | |||
1422 | break; | |||
1423 | case '1': | |||
1424 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); | |||
1425 | break; | |||
1426 | case '2': | |||
1427 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); | |||
1428 | break; | |||
1429 | } | |||
1430 | ++I; | |||
1431 | } | |||
1432 | break; | |||
1433 | case 'g': | |||
1434 | A->claim(); | |||
1435 | break; | |||
1436 | case 'i': | |||
1437 | if (I + 1 != E && OptStr[I + 1] == '-') { | |||
1438 | ++I; | |||
1439 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); | |||
1440 | } else { | |||
1441 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); | |||
1442 | } | |||
1443 | break; | |||
1444 | case 's': | |||
1445 | DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); | |||
1446 | break; | |||
1447 | case 't': | |||
1448 | DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); | |||
1449 | break; | |||
1450 | case 'y': { | |||
1451 | bool OmitFramePointer = true; | |||
1452 | if (I + 1 != E && OptStr[I + 1] == '-') { | |||
1453 | OmitFramePointer = false; | |||
1454 | ++I; | |||
1455 | } | |||
1456 | if (SupportsForcingFramePointer) { | |||
1457 | if (OmitFramePointer) | |||
1458 | DAL.AddFlagArg(A, | |||
1459 | Opts.getOption(options::OPT_fomit_frame_pointer)); | |||
1460 | else | |||
1461 | DAL.AddFlagArg( | |||
1462 | A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); | |||
1463 | } else { | |||
1464 | // Don't warn about /Oy- in x86-64 builds (where | |||
1465 | // SupportsForcingFramePointer is false). The flag having no effect | |||
1466 | // there is a compiler-internal optimization, and people shouldn't have | |||
1467 | // to special-case their build files for x86-64 clang-cl. | |||
1468 | A->claim(); | |||
1469 | } | |||
1470 | break; | |||
1471 | } | |||
1472 | } | |||
1473 | } | |||
1474 | } | |||
1475 | ||||
1476 | static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, | |||
1477 | const OptTable &Opts) { | |||
1478 | assert(A->getOption().matches(options::OPT_D))(static_cast <bool> (A->getOption().matches(options:: OPT_D)) ? void (0) : __assert_fail ("A->getOption().matches(options::OPT_D)" , "/build/llvm-toolchain-snapshot-13~++20210621111111+acefe0eaaf82/clang/lib/Driver/ToolChains/MSVC.cpp" , 1478, __extension__ __PRETTY_FUNCTION__)); | |||
1479 | ||||
1480 | StringRef Val = A->getValue(); | |||
1481 | size_t Hash = Val.find('#'); | |||
1482 | if (Hash == StringRef::npos || Hash > Val.find('=')) { | |||
1483 | DAL.append(A); | |||
1484 | return; | |||
1485 | } | |||
1486 | ||||
1487 | std::string NewVal = std::string(Val); | |||
1488 | NewVal[Hash] = '='; | |||
1489 | DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal); | |||
1490 | } | |||
1491 | ||||
1492 | static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL, | |||
1493 | const OptTable &Opts) { | |||
1494 | DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_)); | |||
1495 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names)); | |||
1496 | } | |||
1497 | ||||
1498 | static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL, | |||
1499 | const OptTable &Opts) { | |||
1500 | DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase)); | |||
1501 | DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names)); | |||
1502 | } | |||
1503 | ||||
1504 | llvm::opt::DerivedArgList * | |||
1505 | MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, | |||
1506 | StringRef BoundArch, | |||
1507 | Action::OffloadKind OFK) const { | |||
1508 | DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); | |||
1509 | const OptTable &Opts = getDriver().getOpts(); | |||
1510 | ||||
1511 | // /Oy and /Oy- don't have an effect on X86-64 | |||
1512 | bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64; | |||
1513 | ||||
1514 | // The -O[12xd] flag actually expands to several flags. We must desugar the | |||
1515 | // flags so that options embedded can be negated. For example, the '-O2' flag | |||
1516 | // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to | |||
1517 | // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single | |||
1518 | // aspect of '-O2'. | |||
1519 | // | |||
1520 | // Note that this expansion logic only applies to the *last* of '[12xd]'. | |||
1521 | ||||
1522 | // First step is to search for the character we'd like to expand. | |||
1523 | const char *ExpandChar = nullptr; | |||
1524 | for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { | |||
1525 | StringRef OptStr = A->getValue(); | |||
1526 | for (size_t I = 0, E = OptStr.size(); I != E; ++I) { | |||
1527 | char OptChar = OptStr[I]; | |||
1528 | char PrevChar = I > 0 ? OptStr[I - 1] : '0'; | |||
1529 | if (PrevChar == 'b') { | |||
1530 | // OptChar does not expand; it's an argument to the previous char. | |||
1531 | continue; | |||
1532 | } | |||
1533 | if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') | |||
1534 | ExpandChar = OptStr.data() + I; | |||
1535 | } | |||
1536 | } | |||
1537 | ||||
1538 | for (Arg *A : Args) { | |||
1539 | if (A->getOption().matches(options::OPT__SLASH_O)) { | |||
1540 | // The -O flag actually takes an amalgam of other options. For example, | |||
1541 | // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. | |||
1542 | TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts); | |||
1543 | } else if (A->getOption().matches(options::OPT_D)) { | |||
1544 | // Translate -Dfoo#bar into -Dfoo=bar. | |||
1545 | TranslateDArg(A, *DAL, Opts); | |||
1546 | } else if (A->getOption().matches(options::OPT__SLASH_permissive)) { | |||
1547 | // Expand /permissive | |||
1548 | TranslatePermissive(A, *DAL, Opts); | |||
1549 | } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) { | |||
1550 | // Expand /permissive- | |||
1551 | TranslatePermissiveMinus(A, *DAL, Opts); | |||
1552 | } else if (OFK != Action::OFK_HIP) { | |||
1553 | // HIP Toolchain translates input args by itself. | |||
1554 | DAL->append(A); | |||
1555 | } | |||
1556 | } | |||
1557 | ||||
1558 | return DAL; | |||
1559 | } | |||
1560 | ||||
1561 | void MSVCToolChain::addClangTargetOptions( | |||
1562 | const ArgList &DriverArgs, ArgStringList &CC1Args, | |||
1563 | Action::OffloadKind DeviceOffloadKind) const { | |||
1564 | // MSVC STL kindly allows removing all usages of typeid by defining | |||
1565 | // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti | |||
1566 | if (DriverArgs.hasArg(options::OPT_fno_rtti, options::OPT_frtti, | |||
1567 | /*Default=*/false)) | |||
1568 | CC1Args.push_back("-D_HAS_STATIC_RTTI=0"); | |||
1569 | } |