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