1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "WebAssembly.h" |
10 | #include "CommonArgs.h" |
11 | #include "clang/Driver/Compilation.h" |
12 | #include "clang/Driver/Driver.h" |
13 | #include "clang/Driver/DriverDiagnostic.h" |
14 | #include "clang/Driver/Options.h" |
15 | #include "llvm/Support/FileSystem.h" |
16 | #include "llvm/Support/Path.h" |
17 | #include "llvm/Option/ArgList.h" |
18 | |
19 | using namespace clang::driver; |
20 | using namespace clang::driver::tools; |
21 | using namespace clang::driver::toolchains; |
22 | using namespace clang; |
23 | using namespace llvm::opt; |
24 | |
25 | wasm::Linker::Linker(const ToolChain &TC) |
26 | : GnuTool("wasm::Linker", "lld", TC) {} |
27 | |
28 | |
29 | |
30 | static std::string getMultiarchTriple(const Driver &D, |
31 | const llvm::Triple &TargetTriple, |
32 | StringRef SysRoot) { |
33 | return (TargetTriple.getArchName() + "-" + |
34 | TargetTriple.getOSAndEnvironmentName()).str(); |
35 | } |
36 | |
37 | bool wasm::Linker::isLinkJob() const { return true; } |
38 | |
39 | bool wasm::Linker::hasIntegratedCPP() const { return false; } |
40 | |
41 | std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { |
42 | const ToolChain &ToolChain = getToolChain(); |
43 | if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { |
44 | StringRef UseLinker = A->getValue(); |
45 | if (!UseLinker.empty()) { |
46 | if (llvm::sys::path::is_absolute(UseLinker) && |
47 | llvm::sys::fs::can_execute(UseLinker)) |
48 | return UseLinker; |
49 | |
50 | |
51 | if (UseLinker != "lld" && UseLinker != "ld") |
52 | ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) |
53 | << A->getAsString(Args); |
54 | } |
55 | } |
56 | |
57 | return ToolChain.GetProgramPath(ToolChain.getDefaultLinker()); |
58 | } |
59 | |
60 | void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
61 | const InputInfo &Output, |
62 | const InputInfoList &Inputs, |
63 | const ArgList &Args, |
64 | const char *LinkingOutput) const { |
65 | |
66 | const ToolChain &ToolChain = getToolChain(); |
67 | const char *Linker = Args.MakeArgString(getLinkerPath(Args)); |
68 | ArgStringList CmdArgs; |
69 | |
70 | if (Args.hasArg(options::OPT_s)) |
71 | CmdArgs.push_back("--strip-all"); |
72 | |
73 | Args.AddAllArgs(CmdArgs, options::OPT_L); |
74 | Args.AddAllArgs(CmdArgs, options::OPT_u); |
75 | ToolChain.AddFilePathLibArgs(Args, CmdArgs); |
76 | |
77 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) |
78 | CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); |
79 | |
80 | AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); |
81 | |
82 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { |
83 | if (ToolChain.ShouldLinkCXXStdlib(Args)) |
84 | ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); |
85 | |
86 | if (Args.hasArg(options::OPT_pthread)) { |
87 | CmdArgs.push_back("-lpthread"); |
88 | CmdArgs.push_back("--shared-memory"); |
89 | } |
90 | |
91 | CmdArgs.push_back("-lc"); |
92 | AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); |
93 | } |
94 | |
95 | CmdArgs.push_back("-o"); |
96 | CmdArgs.push_back(Output.getFilename()); |
97 | |
98 | C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); |
99 | } |
100 | |
101 | WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, |
102 | const llvm::opt::ArgList &Args) |
103 | : ToolChain(D, Triple, Args) { |
104 | |
105 | assert(Triple.isArch32Bit() != Triple.isArch64Bit()); |
106 | |
107 | getProgramPaths().push_back(getDriver().getInstalledDir()); |
108 | |
109 | if (getTriple().getOS() == llvm::Triple::UnknownOS) { |
110 | |
111 | |
112 | |
113 | |
114 | getFilePaths().push_back(getDriver().SysRoot + "/lib"); |
115 | } else { |
116 | const std::string MultiarchTriple = |
117 | getMultiarchTriple(getDriver(), Triple, getDriver().SysRoot); |
118 | getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple); |
119 | } |
120 | } |
121 | |
122 | bool WebAssembly::IsMathErrnoDefault() const { return false; } |
123 | |
124 | bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } |
125 | |
126 | bool WebAssembly::UseObjCMixedDispatch() const { return true; } |
127 | |
128 | bool WebAssembly::isPICDefault() const { return false; } |
129 | |
130 | bool WebAssembly::isPIEDefault() const { return false; } |
131 | |
132 | bool WebAssembly::isPICDefaultForced() const { return false; } |
133 | |
134 | bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } |
135 | |
136 | bool WebAssembly::hasBlocksRuntime() const { return false; } |
137 | |
138 | |
139 | bool WebAssembly::SupportsProfiling() const { return false; } |
140 | |
141 | bool WebAssembly::HasNativeLLVMSupport() const { return true; } |
142 | |
143 | void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, |
144 | ArgStringList &CC1Args, |
145 | Action::OffloadKind) const { |
146 | if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, |
147 | options::OPT_fno_use_init_array, true)) |
148 | CC1Args.push_back("-fuse-init-array"); |
149 | |
150 | |
151 | if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread, |
152 | false)) { |
153 | if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, |
154 | false)) |
155 | getDriver().Diag(diag::err_drv_argument_not_allowed_with) |
156 | << "-pthread" |
157 | << "-mno-atomics"; |
158 | CC1Args.push_back("-target-feature"); |
159 | CC1Args.push_back("+atomics"); |
160 | } |
161 | } |
162 | |
163 | ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const { |
164 | return ToolChain::RLT_CompilerRT; |
165 | } |
166 | |
167 | ToolChain::CXXStdlibType |
168 | WebAssembly::GetCXXStdlibType(const ArgList &Args) const { |
169 | if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { |
170 | StringRef Value = A->getValue(); |
171 | if (Value != "libc++") |
172 | getDriver().Diag(diag::err_drv_invalid_stdlib_name) |
173 | << A->getAsString(Args); |
174 | } |
175 | return ToolChain::CST_Libcxx; |
176 | } |
177 | |
178 | void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
179 | ArgStringList &CC1Args) const { |
180 | if (!DriverArgs.hasArg(options::OPT_nostdinc)) { |
181 | if (getTriple().getOS() != llvm::Triple::UnknownOS) { |
182 | const std::string MultiarchTriple = |
183 | getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); |
184 | addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include/" + MultiarchTriple); |
185 | } |
186 | addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); |
187 | } |
188 | } |
189 | |
190 | void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, |
191 | ArgStringList &CC1Args) const { |
192 | if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && |
193 | !DriverArgs.hasArg(options::OPT_nostdincxx)) { |
194 | if (getTriple().getOS() != llvm::Triple::UnknownOS) { |
195 | const std::string MultiarchTriple = |
196 | getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); |
197 | addSystemInclude(DriverArgs, CC1Args, |
198 | getDriver().SysRoot + "/include/" + MultiarchTriple + "/c++/v1"); |
199 | } |
200 | addSystemInclude(DriverArgs, CC1Args, |
201 | getDriver().SysRoot + "/include/c++/v1"); |
202 | } |
203 | } |
204 | |
205 | void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, |
206 | llvm::opt::ArgStringList &CmdArgs) const { |
207 | |
208 | switch (GetCXXStdlibType(Args)) { |
209 | case ToolChain::CST_Libcxx: |
210 | CmdArgs.push_back("-lc++"); |
211 | CmdArgs.push_back("-lc++abi"); |
212 | break; |
213 | case ToolChain::CST_Libstdcxx: |
214 | llvm_unreachable("invalid stdlib name"); |
215 | } |
216 | } |
217 | |
218 | Tool *WebAssembly::buildLinker() const { |
219 | return new tools::wasm::Linker(*this); |
220 | } |
221 | |