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