xref: /openbsd-src/gnu/llvm/clang/lib/Driver/ToolChains/BareMetal.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "BareMetal.h"
10e5dd7070Spatrick 
11e5dd7070Spatrick #include "CommonArgs.h"
12e5dd7070Spatrick #include "Gnu.h"
13a9ac8606Spatrick #include "clang/Driver/InputInfo.h"
14e5dd7070Spatrick 
15a9ac8606Spatrick #include "Arch/RISCV.h"
16e5dd7070Spatrick #include "clang/Driver/Compilation.h"
17e5dd7070Spatrick #include "clang/Driver/Driver.h"
18e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h"
19e5dd7070Spatrick #include "clang/Driver/Options.h"
20e5dd7070Spatrick #include "llvm/Option/ArgList.h"
21e5dd7070Spatrick #include "llvm/Support/Path.h"
22e5dd7070Spatrick #include "llvm/Support/VirtualFileSystem.h"
23e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
24e5dd7070Spatrick 
25e5dd7070Spatrick using namespace llvm::opt;
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick using namespace clang::driver;
28e5dd7070Spatrick using namespace clang::driver::tools;
29e5dd7070Spatrick using namespace clang::driver::toolchains;
30e5dd7070Spatrick 
makeMultilib(StringRef commonSuffix)31a9ac8606Spatrick static Multilib makeMultilib(StringRef commonSuffix) {
32a9ac8606Spatrick   return Multilib(commonSuffix, commonSuffix, commonSuffix);
33a9ac8606Spatrick }
34a9ac8606Spatrick 
findRISCVMultilibs(const Driver & D,const llvm::Triple & TargetTriple,const ArgList & Args,DetectedMultilibs & Result)35a9ac8606Spatrick static bool findRISCVMultilibs(const Driver &D,
36a9ac8606Spatrick                                const llvm::Triple &TargetTriple,
37a9ac8606Spatrick                                const ArgList &Args, DetectedMultilibs &Result) {
38a9ac8606Spatrick   Multilib::flags_list Flags;
39a9ac8606Spatrick   StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
40a9ac8606Spatrick   StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
41a9ac8606Spatrick 
42*12c85518Srobert   if (TargetTriple.isRISCV64()) {
43a9ac8606Spatrick     Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
44a9ac8606Spatrick     Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
45a9ac8606Spatrick                           .flag("+march=rv64imafdc")
46a9ac8606Spatrick                           .flag("+mabi=lp64d");
47a9ac8606Spatrick 
48a9ac8606Spatrick     // Multilib reuse
49a9ac8606Spatrick     bool UseImafdc =
50a9ac8606Spatrick         (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
51a9ac8606Spatrick 
52a9ac8606Spatrick     addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
53a9ac8606Spatrick     addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
54a9ac8606Spatrick     addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
55a9ac8606Spatrick     addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
56a9ac8606Spatrick 
57a9ac8606Spatrick     Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
58a9ac8606Spatrick     return Result.Multilibs.select(Flags, Result.SelectedMultilib);
59a9ac8606Spatrick   }
60*12c85518Srobert   if (TargetTriple.isRISCV32()) {
61a9ac8606Spatrick     Multilib Imac =
62a9ac8606Spatrick         makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
63a9ac8606Spatrick     Multilib I =
64a9ac8606Spatrick         makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
65a9ac8606Spatrick     Multilib Im =
66a9ac8606Spatrick         makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
67a9ac8606Spatrick     Multilib Iac = makeMultilib("/rv32iac/ilp32")
68a9ac8606Spatrick                        .flag("+march=rv32iac")
69a9ac8606Spatrick                        .flag("+mabi=ilp32");
70a9ac8606Spatrick     Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
71a9ac8606Spatrick                          .flag("+march=rv32imafc")
72a9ac8606Spatrick                          .flag("+mabi=ilp32f");
73a9ac8606Spatrick 
74a9ac8606Spatrick     // Multilib reuse
75a9ac8606Spatrick     bool UseI = (Arch == "rv32i") || (Arch == "rv32ic");    // ic => i
76a9ac8606Spatrick     bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
77a9ac8606Spatrick     bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
78a9ac8606Spatrick                     (Arch == "rv32gc"); // imafdc,gc => imafc
79a9ac8606Spatrick 
80a9ac8606Spatrick     addMultilibFlag(UseI, "march=rv32i", Flags);
81a9ac8606Spatrick     addMultilibFlag(UseIm, "march=rv32im", Flags);
82a9ac8606Spatrick     addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
83a9ac8606Spatrick     addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
84a9ac8606Spatrick     addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
85a9ac8606Spatrick     addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
86a9ac8606Spatrick     addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
87a9ac8606Spatrick 
88a9ac8606Spatrick     Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
89a9ac8606Spatrick     return Result.Multilibs.select(Flags, Result.SelectedMultilib);
90a9ac8606Spatrick   }
91a9ac8606Spatrick   return false;
92a9ac8606Spatrick }
93a9ac8606Spatrick 
BareMetal(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)94e5dd7070Spatrick BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
95e5dd7070Spatrick                      const ArgList &Args)
96e5dd7070Spatrick     : ToolChain(D, Triple, Args) {
97e5dd7070Spatrick   getProgramPaths().push_back(getDriver().getInstalledDir());
98e5dd7070Spatrick   if (getDriver().getInstalledDir() != getDriver().Dir)
99e5dd7070Spatrick     getProgramPaths().push_back(getDriver().Dir);
100e5dd7070Spatrick 
101a9ac8606Spatrick   findMultilibs(D, Triple, Args);
102a9ac8606Spatrick   SmallString<128> SysRoot(computeSysRoot());
103a9ac8606Spatrick   if (!SysRoot.empty()) {
104a9ac8606Spatrick     llvm::sys::path::append(SysRoot, "lib");
105a9ac8606Spatrick     getFilePaths().push_back(std::string(SysRoot));
106*12c85518Srobert     getLibraryPaths().push_back(std::string(SysRoot));
107a9ac8606Spatrick   }
108a9ac8606Spatrick }
109e5dd7070Spatrick 
110e5dd7070Spatrick /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
isARMBareMetal(const llvm::Triple & Triple)111e5dd7070Spatrick static bool isARMBareMetal(const llvm::Triple &Triple) {
112e5dd7070Spatrick   if (Triple.getArch() != llvm::Triple::arm &&
113e5dd7070Spatrick       Triple.getArch() != llvm::Triple::thumb)
114e5dd7070Spatrick     return false;
115e5dd7070Spatrick 
116e5dd7070Spatrick   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
117e5dd7070Spatrick     return false;
118e5dd7070Spatrick 
119e5dd7070Spatrick   if (Triple.getOS() != llvm::Triple::UnknownOS)
120e5dd7070Spatrick     return false;
121e5dd7070Spatrick 
122e5dd7070Spatrick   if (Triple.getEnvironment() != llvm::Triple::EABI &&
123e5dd7070Spatrick       Triple.getEnvironment() != llvm::Triple::EABIHF)
124e5dd7070Spatrick     return false;
125e5dd7070Spatrick 
126e5dd7070Spatrick   return true;
127e5dd7070Spatrick }
128e5dd7070Spatrick 
129*12c85518Srobert /// Is the triple aarch64-none-elf?
isAArch64BareMetal(const llvm::Triple & Triple)130*12c85518Srobert static bool isAArch64BareMetal(const llvm::Triple &Triple) {
131*12c85518Srobert   if (Triple.getArch() != llvm::Triple::aarch64)
132*12c85518Srobert     return false;
133*12c85518Srobert 
134*12c85518Srobert   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
135*12c85518Srobert     return false;
136*12c85518Srobert 
137*12c85518Srobert   if (Triple.getOS() != llvm::Triple::UnknownOS)
138*12c85518Srobert     return false;
139*12c85518Srobert 
140*12c85518Srobert   return Triple.getEnvironmentName() == "elf";
141*12c85518Srobert }
142*12c85518Srobert 
isRISCVBareMetal(const llvm::Triple & Triple)143a9ac8606Spatrick static bool isRISCVBareMetal(const llvm::Triple &Triple) {
144*12c85518Srobert   if (!Triple.isRISCV())
145a9ac8606Spatrick     return false;
146a9ac8606Spatrick 
147a9ac8606Spatrick   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
148a9ac8606Spatrick     return false;
149a9ac8606Spatrick 
150a9ac8606Spatrick   if (Triple.getOS() != llvm::Triple::UnknownOS)
151a9ac8606Spatrick     return false;
152a9ac8606Spatrick 
153a9ac8606Spatrick   return Triple.getEnvironmentName() == "elf";
154a9ac8606Spatrick }
155a9ac8606Spatrick 
findMultilibs(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)156a9ac8606Spatrick void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
157a9ac8606Spatrick                               const ArgList &Args) {
158a9ac8606Spatrick   DetectedMultilibs Result;
159a9ac8606Spatrick   if (isRISCVBareMetal(Triple)) {
160a9ac8606Spatrick     if (findRISCVMultilibs(D, Triple, Args, Result)) {
161a9ac8606Spatrick       SelectedMultilib = Result.SelectedMultilib;
162a9ac8606Spatrick       Multilibs = Result.Multilibs;
163a9ac8606Spatrick     }
164a9ac8606Spatrick   }
165a9ac8606Spatrick }
166a9ac8606Spatrick 
handlesTarget(const llvm::Triple & Triple)167e5dd7070Spatrick bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
168*12c85518Srobert   return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
169*12c85518Srobert          isRISCVBareMetal(Triple);
170e5dd7070Spatrick }
171e5dd7070Spatrick 
buildLinker() const172e5dd7070Spatrick Tool *BareMetal::buildLinker() const {
173e5dd7070Spatrick   return new tools::baremetal::Linker(*this);
174e5dd7070Spatrick }
175e5dd7070Spatrick 
computeSysRoot() const176a9ac8606Spatrick std::string BareMetal::computeSysRoot() const {
177a9ac8606Spatrick   if (!getDriver().SysRoot.empty())
178a9ac8606Spatrick     return getDriver().SysRoot + SelectedMultilib.osSuffix();
179a9ac8606Spatrick 
180a9ac8606Spatrick   SmallString<128> SysRootDir;
181a9ac8606Spatrick   llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
182a9ac8606Spatrick                           getDriver().getTargetTriple());
183a9ac8606Spatrick 
184a9ac8606Spatrick   SysRootDir += SelectedMultilib.osSuffix();
185a9ac8606Spatrick   return std::string(SysRootDir);
186a9ac8606Spatrick }
187a9ac8606Spatrick 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const188e5dd7070Spatrick void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
189e5dd7070Spatrick                                           ArgStringList &CC1Args) const {
190e5dd7070Spatrick   if (DriverArgs.hasArg(options::OPT_nostdinc))
191e5dd7070Spatrick     return;
192e5dd7070Spatrick 
193e5dd7070Spatrick   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
194e5dd7070Spatrick     SmallString<128> Dir(getDriver().ResourceDir);
195e5dd7070Spatrick     llvm::sys::path::append(Dir, "include");
196e5dd7070Spatrick     addSystemInclude(DriverArgs, CC1Args, Dir.str());
197e5dd7070Spatrick   }
198e5dd7070Spatrick 
199e5dd7070Spatrick   if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
200a9ac8606Spatrick     SmallString<128> Dir(computeSysRoot());
201a9ac8606Spatrick     if (!Dir.empty()) {
202e5dd7070Spatrick       llvm::sys::path::append(Dir, "include");
203e5dd7070Spatrick       addSystemInclude(DriverArgs, CC1Args, Dir.str());
204e5dd7070Spatrick     }
205e5dd7070Spatrick   }
206a9ac8606Spatrick }
207e5dd7070Spatrick 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const208e5dd7070Spatrick void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
209e5dd7070Spatrick                                       ArgStringList &CC1Args,
210e5dd7070Spatrick                                       Action::OffloadKind) const {
211e5dd7070Spatrick   CC1Args.push_back("-nostdsysteminc");
212e5dd7070Spatrick }
213e5dd7070Spatrick 
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const214*12c85518Srobert void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
215*12c85518Srobert                                              ArgStringList &CC1Args) const {
216e5dd7070Spatrick   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
217e5dd7070Spatrick       DriverArgs.hasArg(options::OPT_nostdlibinc) ||
218e5dd7070Spatrick       DriverArgs.hasArg(options::OPT_nostdincxx))
219e5dd7070Spatrick     return;
220e5dd7070Spatrick 
221*12c85518Srobert   const Driver &D = getDriver();
222a9ac8606Spatrick   std::string SysRoot(computeSysRoot());
223e5dd7070Spatrick   if (SysRoot.empty())
224e5dd7070Spatrick     return;
225e5dd7070Spatrick 
226e5dd7070Spatrick   switch (GetCXXStdlibType(DriverArgs)) {
227e5dd7070Spatrick   case ToolChain::CST_Libcxx: {
228*12c85518Srobert     // First check sysroot/usr/include/c++/v1 if it exists.
229*12c85518Srobert     SmallString<128> TargetDir(SysRoot);
230*12c85518Srobert     llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
231*12c85518Srobert     if (D.getVFS().exists(TargetDir)) {
232*12c85518Srobert       addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
233*12c85518Srobert       break;
234*12c85518Srobert     }
235*12c85518Srobert     // Add generic path if nothing else succeeded so far.
236e5dd7070Spatrick     SmallString<128> Dir(SysRoot);
237e5dd7070Spatrick     llvm::sys::path::append(Dir, "include", "c++", "v1");
238e5dd7070Spatrick     addSystemInclude(DriverArgs, CC1Args, Dir.str());
239e5dd7070Spatrick     break;
240e5dd7070Spatrick   }
241e5dd7070Spatrick   case ToolChain::CST_Libstdcxx: {
242e5dd7070Spatrick     SmallString<128> Dir(SysRoot);
243e5dd7070Spatrick     llvm::sys::path::append(Dir, "include", "c++");
244e5dd7070Spatrick     std::error_code EC;
245e5dd7070Spatrick     Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
246e5dd7070Spatrick     // Walk the subdirs, and find the one with the newest gcc version:
247*12c85518Srobert     for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir.str(), EC),
248e5dd7070Spatrick                                        LE;
249e5dd7070Spatrick          !EC && LI != LE; LI = LI.increment(EC)) {
250e5dd7070Spatrick       StringRef VersionText = llvm::sys::path::filename(LI->path());
251e5dd7070Spatrick       auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
252e5dd7070Spatrick       if (CandidateVersion.Major == -1)
253e5dd7070Spatrick         continue;
254e5dd7070Spatrick       if (CandidateVersion <= Version)
255e5dd7070Spatrick         continue;
256e5dd7070Spatrick       Version = CandidateVersion;
257e5dd7070Spatrick     }
258e5dd7070Spatrick     if (Version.Major == -1)
259e5dd7070Spatrick       return;
260e5dd7070Spatrick     llvm::sys::path::append(Dir, Version.Text);
261e5dd7070Spatrick     addSystemInclude(DriverArgs, CC1Args, Dir.str());
262e5dd7070Spatrick     break;
263e5dd7070Spatrick   }
264e5dd7070Spatrick   }
265e5dd7070Spatrick }
266e5dd7070Spatrick 
AddCXXStdlibLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const267e5dd7070Spatrick void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
268e5dd7070Spatrick                                     ArgStringList &CmdArgs) const {
269e5dd7070Spatrick   switch (GetCXXStdlibType(Args)) {
270e5dd7070Spatrick   case ToolChain::CST_Libcxx:
271e5dd7070Spatrick     CmdArgs.push_back("-lc++");
272*12c85518Srobert     if (Args.hasArg(options::OPT_fexperimental_library))
273*12c85518Srobert       CmdArgs.push_back("-lc++experimental");
274e5dd7070Spatrick     CmdArgs.push_back("-lc++abi");
275e5dd7070Spatrick     break;
276e5dd7070Spatrick   case ToolChain::CST_Libstdcxx:
277e5dd7070Spatrick     CmdArgs.push_back("-lstdc++");
278e5dd7070Spatrick     CmdArgs.push_back("-lsupc++");
279e5dd7070Spatrick     break;
280e5dd7070Spatrick   }
281e5dd7070Spatrick   CmdArgs.push_back("-lunwind");
282e5dd7070Spatrick }
283e5dd7070Spatrick 
AddLinkRuntimeLib(const ArgList & Args,ArgStringList & CmdArgs) const284e5dd7070Spatrick void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
285e5dd7070Spatrick                                   ArgStringList &CmdArgs) const {
286a9ac8606Spatrick   ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
287a9ac8606Spatrick   switch (RLT) {
288*12c85518Srobert   case ToolChain::RLT_CompilerRT: {
289*12c85518Srobert     const std::string FileName = getCompilerRT(Args, "builtins");
290*12c85518Srobert     llvm::StringRef BaseName = llvm::sys::path::filename(FileName);
291*12c85518Srobert     BaseName.consume_front("lib");
292*12c85518Srobert     BaseName.consume_back(".a");
293*12c85518Srobert     CmdArgs.push_back(Args.MakeArgString("-l" + BaseName));
294a9ac8606Spatrick     return;
295*12c85518Srobert   }
296a9ac8606Spatrick   case ToolChain::RLT_Libgcc:
297a9ac8606Spatrick     CmdArgs.push_back("-lgcc");
298a9ac8606Spatrick     return;
299a9ac8606Spatrick   }
300a9ac8606Spatrick   llvm_unreachable("Unhandled RuntimeLibType.");
301e5dd7070Spatrick }
302e5dd7070Spatrick 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const303e5dd7070Spatrick void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
304e5dd7070Spatrick                                      const InputInfo &Output,
305e5dd7070Spatrick                                      const InputInfoList &Inputs,
306e5dd7070Spatrick                                      const ArgList &Args,
307e5dd7070Spatrick                                      const char *LinkingOutput) const {
308e5dd7070Spatrick   ArgStringList CmdArgs;
309e5dd7070Spatrick 
310e5dd7070Spatrick   auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
311e5dd7070Spatrick 
312e5dd7070Spatrick   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
313e5dd7070Spatrick 
314e5dd7070Spatrick   CmdArgs.push_back("-Bstatic");
315e5dd7070Spatrick 
316e5dd7070Spatrick   Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
317e5dd7070Spatrick                             options::OPT_e, options::OPT_s, options::OPT_t,
318e5dd7070Spatrick                             options::OPT_Z_Flag, options::OPT_r});
319e5dd7070Spatrick 
320a9ac8606Spatrick   TC.AddFilePathLibArgs(Args, CmdArgs);
321a9ac8606Spatrick 
322*12c85518Srobert   for (const auto &LibPath : TC.getLibraryPaths())
323*12c85518Srobert     CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
324*12c85518Srobert 
325*12c85518Srobert   const std::string FileName = TC.getCompilerRT(Args, "builtins");
326*12c85518Srobert   llvm::SmallString<128> PathBuf{FileName};
327*12c85518Srobert   llvm::sys::path::remove_filename(PathBuf);
328*12c85518Srobert   CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf));
329a9ac8606Spatrick 
330e5dd7070Spatrick   if (TC.ShouldLinkCXXStdlib(Args))
331e5dd7070Spatrick     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
332*12c85518Srobert 
333e5dd7070Spatrick   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
334e5dd7070Spatrick     CmdArgs.push_back("-lc");
335e5dd7070Spatrick     CmdArgs.push_back("-lm");
336e5dd7070Spatrick 
337e5dd7070Spatrick     TC.AddLinkRuntimeLib(Args, CmdArgs);
338e5dd7070Spatrick   }
339e5dd7070Spatrick 
340e5dd7070Spatrick   CmdArgs.push_back("-o");
341e5dd7070Spatrick   CmdArgs.push_back(Output.getFilename());
342e5dd7070Spatrick 
343ec727ea7Spatrick   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
344e5dd7070Spatrick                                          Args.MakeArgString(TC.GetLinkerPath()),
345a9ac8606Spatrick                                          CmdArgs, Inputs, Output));
346e5dd7070Spatrick }
347