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