xref: /llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp (revision a4deb809be8f5ec3adec3626e9d700f6168d0e9f)
1 //===--- OHOS.cpp - OHOS ToolChain Implementations --------*- C++ -*-===//
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 "OHOS.h"
10 #include "Arch/ARM.h"
11 #include "CommonArgs.h"
12 #include "clang/Config/config.h"
13 #include "clang/Driver/Compilation.h"
14 #include "clang/Driver/Driver.h"
15 #include "clang/Driver/DriverDiagnostic.h"
16 #include "clang/Driver/Options.h"
17 #include "clang/Driver/SanitizerArgs.h"
18 #include "llvm/Option/ArgList.h"
19 #include "llvm/ProfileData/InstrProf.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/VirtualFileSystem.h"
23 #include "llvm/Support/ScopedPrinter.h"
24 
25 using namespace clang::driver;
26 using namespace clang::driver::toolchains;
27 using namespace clang::driver::tools;
28 using namespace clang;
29 using namespace llvm::opt;
30 using namespace clang::driver::tools::arm;
31 
32 using tools::addMultilibFlag;
33 using tools::addPathIfExists;
34 
35 static bool findOHOSMuslMultilibs(const Driver &D,
36                                   const Multilib::flags_list &Flags,
37                                   DetectedMultilibs &Result) {
38   MultilibSet Multilibs;
39   Multilibs.push_back(Multilib());
40   // -mcpu=cortex-a7
41   // -mfloat-abi=soft -mfloat-abi=softfp -mfloat-abi=hard
42   // -mfpu=neon-vfpv4
43   Multilibs.push_back(
44       Multilib("/a7_soft", {}, {}, {"-mcpu=cortex-a7", "-mfloat-abi=soft"}));
45 
46   Multilibs.push_back(
47       Multilib("/a7_softfp_neon-vfpv4", {}, {},
48                {"-mcpu=cortex-a7", "-mfloat-abi=softfp", "-mfpu=neon-vfpv4"}));
49 
50   Multilibs.push_back(
51       Multilib("/a7_hard_neon-vfpv4", {}, {},
52                {"-mcpu=cortex-a7", "-mfloat-abi=hard", "-mfpu=neon-vfpv4"}));
53 
54   if (Multilibs.select(D, Flags, Result.SelectedMultilibs)) {
55     Result.Multilibs = Multilibs;
56     return true;
57   }
58   return false;
59 }
60 
61 static bool findOHOSMultilibs(const Driver &D,
62                                       const ToolChain &TC,
63                                       const llvm::Triple &TargetTriple,
64                                       StringRef Path, const ArgList &Args,
65                                       DetectedMultilibs &Result) {
66   Multilib::flags_list Flags;
67   bool IsA7 = false;
68   if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
69     IsA7 = A->getValue() == StringRef("cortex-a7");
70   addMultilibFlag(IsA7, "-mcpu=cortex-a7", Flags);
71 
72   bool IsMFPU = false;
73   if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
74     IsMFPU = A->getValue() == StringRef("neon-vfpv4");
75   addMultilibFlag(IsMFPU, "-mfpu=neon-vfpv4", Flags);
76 
77   tools::arm::FloatABI ARMFloatABI = getARMFloatABI(D, TargetTriple, Args);
78   addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Soft),
79                   "-mfloat-abi=soft", Flags);
80   addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::SoftFP),
81                   "-mfloat-abi=softfp", Flags);
82   addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Hard),
83                   "-mfloat-abi=hard", Flags);
84 
85   return findOHOSMuslMultilibs(D, Flags, Result);
86 }
87 
88 std::string OHOS::getMultiarchTriple(const llvm::Triple &T) const {
89   // For most architectures, just use whatever we have rather than trying to be
90   // clever.
91   switch (T.getArch()) {
92   default:
93     break;
94 
95   // We use the existence of '/lib/<triple>' as a directory to detect some
96   // common linux triples that don't quite match the Clang triple for both
97   // 32-bit and 64-bit targets. Multiarch fixes its install triples to these
98   // regardless of what the actual target triple is.
99   case llvm::Triple::arm:
100   case llvm::Triple::thumb:
101     return T.isOSLiteOS() ? "arm-liteos-ohos" : "arm-linux-ohos";
102   case llvm::Triple::riscv32:
103     return "riscv32-linux-ohos";
104   case llvm::Triple::riscv64:
105     return "riscv64-linux-ohos";
106   case llvm::Triple::mipsel:
107     return "mipsel-linux-ohos";
108   case llvm::Triple::x86:
109     return "i686-linux-ohos";
110   case llvm::Triple::x86_64:
111     return "x86_64-linux-ohos";
112   case llvm::Triple::aarch64:
113     return "aarch64-linux-ohos";
114   }
115   return T.str();
116 }
117 
118 std::string OHOS::getMultiarchTriple(const Driver &D,
119                                      const llvm::Triple &TargetTriple,
120                                      StringRef SysRoot) const {
121   return getMultiarchTriple(TargetTriple);
122 }
123 
124 static std::string makePath(const std::initializer_list<std::string> &IL) {
125   SmallString<128> P;
126   for (const auto &S : IL)
127     llvm::sys::path::append(P, S);
128   return static_cast<std::string>(P.str());
129 }
130 
131 /// OHOS Toolchain
132 OHOS::OHOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
133     : Generic_ELF(D, Triple, Args) {
134   std::string SysRoot = computeSysRoot();
135 
136   // Select the correct multilib according to the given arguments.
137   DetectedMultilibs Result;
138   findOHOSMultilibs(D, *this, Triple, "", Args, Result);
139   Multilibs = Result.Multilibs;
140   SelectedMultilibs = Result.SelectedMultilibs;
141   if (!SelectedMultilibs.empty()) {
142     SelectedMultilib = SelectedMultilibs.back();
143   }
144 
145   getFilePaths().clear();
146   for (const auto &CandidateLibPath : getArchSpecificLibPaths())
147     if (getVFS().exists(CandidateLibPath))
148       getFilePaths().push_back(CandidateLibPath);
149 
150   getLibraryPaths().clear();
151   for (auto &Path : getRuntimePaths())
152     if (getVFS().exists(Path))
153       getLibraryPaths().push_back(Path);
154 
155   // OHOS sysroots contain a library directory for each supported OS
156   // version as well as some unversioned libraries in the usual multiarch
157   // directory. Support --target=aarch64-linux-ohosX.Y.Z or
158   // --target=aarch64-linux-ohosX.Y or --target=aarch64-linux-ohosX
159   path_list &Paths = getFilePaths();
160   std::string SysRootLibPath = makePath({SysRoot, "usr", "lib"});
161   std::string MultiarchTriple = getMultiarchTriple(getTriple());
162   addPathIfExists(D, makePath({SysRootLibPath, SelectedMultilib.gccSuffix()}),
163                   Paths);
164   addPathIfExists(D,
165                   makePath({D.Dir, "..", "lib", MultiarchTriple,
166                             SelectedMultilib.gccSuffix()}),
167                   Paths);
168 
169   addPathIfExists(
170       D,
171       makePath({SysRootLibPath, MultiarchTriple, SelectedMultilib.gccSuffix()}),
172       Paths);
173 }
174 
175 ToolChain::RuntimeLibType OHOS::GetRuntimeLibType(
176     const ArgList &Args) const {
177   if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
178     StringRef Value = A->getValue();
179     if (Value != "compiler-rt")
180       getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)
181           << A->getAsString(Args);
182   }
183 
184   return ToolChain::RLT_CompilerRT;
185 }
186 
187 ToolChain::CXXStdlibType
188 OHOS::GetCXXStdlibType(const ArgList &Args) const {
189   if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
190     StringRef Value = A->getValue();
191     if (Value != "libc++")
192       getDriver().Diag(diag::err_drv_invalid_stdlib_name)
193         << A->getAsString(Args);
194   }
195 
196   return ToolChain::CST_Libcxx;
197 }
198 
199 void OHOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
200                                         ArgStringList &CC1Args) const {
201   const Driver &D = getDriver();
202   const llvm::Triple &Triple = getTriple();
203   std::string SysRoot = computeSysRoot();
204 
205   if (DriverArgs.hasArg(options::OPT_nostdinc))
206     return;
207 
208   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
209     SmallString<128> P(D.ResourceDir);
210     llvm::sys::path::append(P, "include");
211     addSystemInclude(DriverArgs, CC1Args, P);
212   }
213 
214   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
215     return;
216 
217   // Check for configure-time C include directories.
218   StringRef CIncludeDirs(C_INCLUDE_DIRS);
219   if (CIncludeDirs != "") {
220     SmallVector<StringRef, 5> dirs;
221     CIncludeDirs.split(dirs, ":");
222     for (StringRef dir : dirs) {
223       StringRef Prefix =
224           llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
225       addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
226     }
227     return;
228   }
229 
230   addExternCSystemInclude(DriverArgs, CC1Args,
231                           SysRoot + "/usr/include/" +
232                               getMultiarchTriple(Triple));
233   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
234   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
235 }
236 
237 void OHOS::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
238                                         ArgStringList &CC1Args) const {
239   if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
240       DriverArgs.hasArg(options::OPT_nostdincxx))
241     return;
242 
243   switch (GetCXXStdlibType(DriverArgs)) {
244   case ToolChain::CST_Libcxx: {
245     std::string IncPath = makePath({getDriver().Dir, "..", "include"});
246     std::string IncTargetPath =
247         makePath({IncPath, getMultiarchTriple(getTriple()), "c++", "v1"});
248     if (getVFS().exists(IncTargetPath)) {
249       addSystemInclude(DriverArgs, CC1Args, makePath({IncPath, "c++", "v1"}));
250       addSystemInclude(DriverArgs, CC1Args, IncTargetPath);
251     }
252     break;
253   }
254 
255   default:
256     llvm_unreachable("invalid stdlib name");
257   }
258 }
259 
260 void OHOS::AddCXXStdlibLibArgs(const ArgList &Args,
261                                   ArgStringList &CmdArgs) const {
262   switch (GetCXXStdlibType(Args)) {
263   case ToolChain::CST_Libcxx:
264     CmdArgs.push_back("-lc++");
265     CmdArgs.push_back("-lc++abi");
266     CmdArgs.push_back("-lunwind");
267     break;
268 
269   case ToolChain::CST_Libstdcxx:
270     llvm_unreachable("invalid stdlib name");
271   }
272 }
273 
274 std::string OHOS::computeSysRoot() const {
275   std::string SysRoot =
276       !getDriver().SysRoot.empty()
277           ? getDriver().SysRoot
278           : makePath({getDriver().Dir, "..", "..", "sysroot"});
279   if (!llvm::sys::fs::exists(SysRoot))
280     return std::string();
281 
282   std::string ArchRoot = makePath({SysRoot, getMultiarchTriple(getTriple())});
283   return llvm::sys::fs::exists(ArchRoot) ? ArchRoot : SysRoot;
284 }
285 
286 ToolChain::path_list OHOS::getRuntimePaths() const {
287   SmallString<128> P;
288   path_list Paths;
289   const Driver &D = getDriver();
290   const llvm::Triple &Triple = getTriple();
291 
292   // First try the triple passed to driver as --target=<triple>.
293   P.assign(D.ResourceDir);
294   llvm::sys::path::append(P, "lib", D.getTargetTriple(), SelectedMultilib.gccSuffix());
295   Paths.push_back(P.c_str());
296 
297   // Second try the normalized triple.
298   P.assign(D.ResourceDir);
299   llvm::sys::path::append(P, "lib", Triple.str(), SelectedMultilib.gccSuffix());
300   Paths.push_back(P.c_str());
301 
302   // Third try the effective triple.
303   P.assign(D.ResourceDir);
304   std::string SysRoot = computeSysRoot();
305   llvm::sys::path::append(P, "lib", getMultiarchTriple(Triple),
306                           SelectedMultilib.gccSuffix());
307   Paths.push_back(P.c_str());
308 
309   return Paths;
310 }
311 
312 std::string OHOS::getDynamicLinker(const ArgList &Args) const {
313   const llvm::Triple &Triple = getTriple();
314   const llvm::Triple::ArchType Arch = getArch();
315 
316   assert(Triple.isMusl());
317   std::string ArchName;
318   bool IsArm = false;
319 
320   switch (Arch) {
321   case llvm::Triple::arm:
322   case llvm::Triple::thumb:
323     ArchName = "arm";
324     IsArm = true;
325     break;
326   case llvm::Triple::armeb:
327   case llvm::Triple::thumbeb:
328     ArchName = "armeb";
329     IsArm = true;
330     break;
331   default:
332     ArchName = Triple.getArchName().str();
333   }
334   if (IsArm &&
335       (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
336     ArchName += "hf";
337 
338   return "/lib/ld-musl-" + ArchName + ".so.1";
339 }
340 
341 std::string OHOS::getCompilerRT(const ArgList &Args, StringRef Component,
342                                 FileType Type) const {
343   SmallString<128> Path(getDriver().ResourceDir);
344   llvm::sys::path::append(Path, "lib", getMultiarchTriple(getTriple()),
345                           SelectedMultilib.gccSuffix());
346   const char *Prefix =
347       Type == ToolChain::FT_Object ? "" : "lib";
348   const char *Suffix;
349   switch (Type) {
350   case ToolChain::FT_Object:
351     Suffix = ".o";
352     break;
353   case ToolChain::FT_Static:
354     Suffix = ".a";
355     break;
356   case ToolChain::FT_Shared:
357     Suffix = ".so";
358     break;
359   }
360   llvm::sys::path::append(
361       Path, Prefix + Twine("clang_rt.") + Component + Suffix);
362   return static_cast<std::string>(Path.str());
363 }
364 
365 void OHOS::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
366   CmdArgs.push_back("-z");
367   CmdArgs.push_back("now");
368   CmdArgs.push_back("-z");
369   CmdArgs.push_back("relro");
370   CmdArgs.push_back("-z");
371   CmdArgs.push_back("max-page-size=4096");
372   // .gnu.hash section is not compatible with the MIPS target
373   if (getArch() != llvm::Triple::mipsel)
374     CmdArgs.push_back("--hash-style=both");
375 #ifdef ENABLE_LINKER_BUILD_ID
376   CmdArgs.push_back("--build-id");
377 #endif
378   CmdArgs.push_back("--enable-new-dtags");
379 }
380 
381 SanitizerMask OHOS::getSupportedSanitizers() const {
382   SanitizerMask Res = ToolChain::getSupportedSanitizers();
383   Res |= SanitizerKind::Address;
384   Res |= SanitizerKind::PointerCompare;
385   Res |= SanitizerKind::PointerSubtract;
386   Res |= SanitizerKind::Fuzzer;
387   Res |= SanitizerKind::FuzzerNoLink;
388   Res |= SanitizerKind::Memory;
389   Res |= SanitizerKind::Vptr;
390   Res |= SanitizerKind::SafeStack;
391   Res |= SanitizerKind::Scudo;
392   // TODO: kASAN for liteos ??
393   // TODO: Support TSAN and HWASAN and update mask.
394   return Res;
395 }
396 
397 // TODO: Make a base class for Linux and OHOS and move this there.
398 void OHOS::addProfileRTLibs(const llvm::opt::ArgList &Args,
399                              llvm::opt::ArgStringList &CmdArgs) const {
400   // Add linker option -u__llvm_profile_runtime to cause runtime
401   // initialization module to be linked in.
402   if (needsProfileRT(Args))
403     CmdArgs.push_back(Args.MakeArgString(
404         Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
405   ToolChain::addProfileRTLibs(Args, CmdArgs);
406 }
407 
408 ToolChain::path_list OHOS::getArchSpecificLibPaths() const {
409   ToolChain::path_list Paths;
410   llvm::Triple Triple = getTriple();
411   Paths.push_back(
412       makePath({getDriver().ResourceDir, "lib", getMultiarchTriple(Triple)}));
413   return Paths;
414 }
415 
416 ToolChain::UnwindLibType OHOS::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
417   if (Args.getLastArg(options::OPT_unwindlib_EQ))
418     return Generic_ELF::GetUnwindLibType(Args);
419   return GetDefaultUnwindLibType();
420 }
421