1 | //===--- Gnu.h - Gnu Tool and 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 | #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H |
10 | #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H |
11 | |
12 | #include "Cuda.h" |
13 | #include "LazyDetector.h" |
14 | #include "ROCm.h" |
15 | #include "clang/Driver/Tool.h" |
16 | #include "clang/Driver/ToolChain.h" |
17 | #include <set> |
18 | |
19 | namespace clang { |
20 | namespace driver { |
21 | |
22 | struct DetectedMultilibs { |
23 | /// The set of multilibs that the detected installation supports. |
24 | MultilibSet Multilibs; |
25 | |
26 | /// The multilibs appropriate for the given flags. |
27 | llvm::SmallVector<Multilib> SelectedMultilibs; |
28 | |
29 | /// On Biarch systems, this corresponds to the default multilib when |
30 | /// targeting the non-default multilib. Otherwise, it is empty. |
31 | std::optional<Multilib> BiarchSibling; |
32 | }; |
33 | |
34 | bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, |
35 | StringRef Path, const llvm::opt::ArgList &Args, |
36 | DetectedMultilibs &Result); |
37 | |
38 | namespace tools { |
39 | |
40 | /// Directly call GNU Binutils' assembler and linker. |
41 | namespace gnutools { |
42 | class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { |
43 | public: |
44 | Assembler(const ToolChain &TC) : Tool("GNU::Assembler" , "assembler" , TC) {} |
45 | |
46 | bool hasIntegratedCPP() const override { return false; } |
47 | |
48 | void ConstructJob(Compilation &C, const JobAction &JA, |
49 | const InputInfo &Output, const InputInfoList &Inputs, |
50 | const llvm::opt::ArgList &TCArgs, |
51 | const char *LinkingOutput) const override; |
52 | }; |
53 | |
54 | class LLVM_LIBRARY_VISIBILITY Linker : public Tool { |
55 | public: |
56 | Linker(const ToolChain &TC) : Tool("GNU::Linker" , "linker" , TC) {} |
57 | |
58 | bool hasIntegratedCPP() const override { return false; } |
59 | bool isLinkJob() const override { return true; } |
60 | |
61 | void ConstructJob(Compilation &C, const JobAction &JA, |
62 | const InputInfo &Output, const InputInfoList &Inputs, |
63 | const llvm::opt::ArgList &TCArgs, |
64 | const char *LinkingOutput) const override; |
65 | }; |
66 | |
67 | class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool { |
68 | public: |
69 | StaticLibTool(const ToolChain &TC) |
70 | : Tool("GNU::StaticLibTool" , "static-lib-linker" , TC) {} |
71 | |
72 | bool hasIntegratedCPP() const override { return false; } |
73 | bool isLinkJob() const override { return true; } |
74 | |
75 | void ConstructJob(Compilation &C, const JobAction &JA, |
76 | const InputInfo &Output, const InputInfoList &Inputs, |
77 | const llvm::opt::ArgList &TCArgs, |
78 | const char *LinkingOutput) const override; |
79 | }; |
80 | } // end namespace gnutools |
81 | |
82 | /// gcc - Generic GCC tool implementations. |
83 | namespace gcc { |
84 | class LLVM_LIBRARY_VISIBILITY Common : public Tool { |
85 | public: |
86 | Common(const char *Name, const char *ShortName, const ToolChain &TC) |
87 | : Tool(Name, ShortName, TC) {} |
88 | |
89 | // A gcc tool has an "integrated" assembler that it will call to produce an |
90 | // object. Let it use that assembler so that we don't have to deal with |
91 | // assembly syntax incompatibilities. |
92 | bool hasIntegratedAssembler() const override { return true; } |
93 | void ConstructJob(Compilation &C, const JobAction &JA, |
94 | const InputInfo &Output, const InputInfoList &Inputs, |
95 | const llvm::opt::ArgList &TCArgs, |
96 | const char *LinkingOutput) const override; |
97 | |
98 | /// RenderExtraToolArgs - Render any arguments necessary to force |
99 | /// the particular tool mode. |
100 | virtual void (const JobAction &JA, |
101 | llvm::opt::ArgStringList &CmdArgs) const = 0; |
102 | }; |
103 | |
104 | class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common { |
105 | public: |
106 | Preprocessor(const ToolChain &TC) |
107 | : Common("gcc::Preprocessor" , "gcc preprocessor" , TC) {} |
108 | |
109 | bool hasGoodDiagnostics() const override { return true; } |
110 | bool hasIntegratedCPP() const override { return false; } |
111 | |
112 | void (const JobAction &JA, |
113 | llvm::opt::ArgStringList &CmdArgs) const override; |
114 | }; |
115 | |
116 | class LLVM_LIBRARY_VISIBILITY Compiler : public Common { |
117 | public: |
118 | Compiler(const ToolChain &TC) : Common("gcc::Compiler" , "gcc frontend" , TC) {} |
119 | |
120 | bool hasGoodDiagnostics() const override { return true; } |
121 | bool hasIntegratedCPP() const override { return true; } |
122 | |
123 | void (const JobAction &JA, |
124 | llvm::opt::ArgStringList &CmdArgs) const override; |
125 | }; |
126 | |
127 | class LLVM_LIBRARY_VISIBILITY Linker : public Common { |
128 | public: |
129 | Linker(const ToolChain &TC) : Common("gcc::Linker" , "linker (via gcc)" , TC) {} |
130 | |
131 | bool hasIntegratedCPP() const override { return false; } |
132 | bool isLinkJob() const override { return true; } |
133 | |
134 | void (const JobAction &JA, |
135 | llvm::opt::ArgStringList &CmdArgs) const override; |
136 | }; |
137 | } // end namespace gcc |
138 | } // end namespace tools |
139 | |
140 | namespace toolchains { |
141 | |
142 | /// Generic_GCC - A tool chain using the 'gcc' command to perform |
143 | /// all subcommands; this relies on gcc translating the majority of |
144 | /// command line options. |
145 | class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { |
146 | public: |
147 | /// Struct to store and manipulate GCC versions. |
148 | /// |
149 | /// We rely on assumptions about the form and structure of GCC version |
150 | /// numbers: they consist of at most three '.'-separated components, and each |
151 | /// component is a non-negative integer except for the last component. For |
152 | /// the last component we are very flexible in order to tolerate release |
153 | /// candidates or 'x' wildcards. |
154 | /// |
155 | /// Note that the ordering established among GCCVersions is based on the |
156 | /// preferred version string to use. For example we prefer versions without |
157 | /// a hard-coded patch number to those with a hard coded patch number. |
158 | /// |
159 | /// Currently this doesn't provide any logic for textual suffixes to patches |
160 | /// in the way that (for example) Debian's version format does. If that ever |
161 | /// becomes necessary, it can be added. |
162 | struct GCCVersion { |
163 | /// The unparsed text of the version. |
164 | std::string Text; |
165 | |
166 | /// The parsed major, minor, and patch numbers. |
167 | int Major, Minor, Patch; |
168 | |
169 | /// The text of the parsed major, and major+minor versions. |
170 | std::string MajorStr, MinorStr; |
171 | |
172 | /// Any textual suffix on the patch number. |
173 | std::string PatchSuffix; |
174 | |
175 | static GCCVersion Parse(StringRef VersionText); |
176 | bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, |
177 | StringRef RHSPatchSuffix = StringRef()) const; |
178 | bool operator<(const GCCVersion &RHS) const { |
179 | return isOlderThan(RHSMajor: RHS.Major, RHSMinor: RHS.Minor, RHSPatch: RHS.Patch, RHSPatchSuffix: RHS.PatchSuffix); |
180 | } |
181 | bool operator>(const GCCVersion &RHS) const { return RHS < *this; } |
182 | bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } |
183 | bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } |
184 | }; |
185 | |
186 | /// This is a class to find a viable GCC installation for Clang to |
187 | /// use. |
188 | /// |
189 | /// This class tries to find a GCC installation on the system, and report |
190 | /// information about it. It starts from the host information provided to the |
191 | /// Driver, and has logic for fuzzing that where appropriate. |
192 | class GCCInstallationDetector { |
193 | bool IsValid; |
194 | llvm::Triple GCCTriple; |
195 | const Driver &D; |
196 | |
197 | // FIXME: These might be better as path objects. |
198 | std::string GCCInstallPath; |
199 | std::string GCCParentLibPath; |
200 | |
201 | /// The primary multilib appropriate for the given flags. |
202 | Multilib SelectedMultilib; |
203 | /// On Biarch systems, this corresponds to the default multilib when |
204 | /// targeting the non-default multilib. Otherwise, it is empty. |
205 | std::optional<Multilib> BiarchSibling; |
206 | |
207 | GCCVersion Version; |
208 | |
209 | // We retain the list of install paths that were considered and rejected in |
210 | // order to print out detailed information in verbose mode. |
211 | std::set<std::string> CandidateGCCInstallPaths; |
212 | |
213 | /// The set of multilibs that the detected installation supports. |
214 | MultilibSet Multilibs; |
215 | |
216 | // Gentoo-specific toolchain configurations are stored here. |
217 | const std::string GentooConfigDir = "/etc/env.d/gcc" ; |
218 | |
219 | public: |
220 | explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} |
221 | void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); |
222 | |
223 | /// Check whether we detected a valid GCC install. |
224 | bool isValid() const { return IsValid; } |
225 | |
226 | /// Get the GCC triple for the detected install. |
227 | const llvm::Triple &getTriple() const { return GCCTriple; } |
228 | |
229 | /// Get the detected GCC installation path. |
230 | StringRef getInstallPath() const { return GCCInstallPath; } |
231 | |
232 | /// Get the detected GCC parent lib path. |
233 | StringRef getParentLibPath() const { return GCCParentLibPath; } |
234 | |
235 | /// Get the detected Multilib |
236 | const Multilib &getMultilib() const { return SelectedMultilib; } |
237 | |
238 | /// Get the whole MultilibSet |
239 | const MultilibSet &getMultilibs() const { return Multilibs; } |
240 | |
241 | /// Get the biarch sibling multilib (if it exists). |
242 | /// \return true iff such a sibling exists |
243 | bool getBiarchSibling(Multilib &M) const; |
244 | |
245 | /// Get the detected GCC version string. |
246 | const GCCVersion &getVersion() const { return Version; } |
247 | |
248 | /// Print information about the detected GCC installation. |
249 | void print(raw_ostream &OS) const; |
250 | |
251 | private: |
252 | static void |
253 | CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, |
254 | const llvm::Triple &BiarchTriple, |
255 | SmallVectorImpl<StringRef> &LibDirs, |
256 | SmallVectorImpl<StringRef> &TripleAliases, |
257 | SmallVectorImpl<StringRef> &BiarchLibDirs, |
258 | SmallVectorImpl<StringRef> &BiarchTripleAliases); |
259 | |
260 | void AddDefaultGCCPrefixes(const llvm::Triple &TargetTriple, |
261 | SmallVectorImpl<std::string> &Prefixes, |
262 | StringRef SysRoot); |
263 | |
264 | bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, |
265 | const llvm::opt::ArgList &Args, |
266 | StringRef Path, |
267 | bool NeedsBiarchSuffix = false); |
268 | |
269 | void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, |
270 | const llvm::opt::ArgList &Args, |
271 | const std::string &LibDir, |
272 | StringRef CandidateTriple, |
273 | bool NeedsBiarchSuffix, bool GCCDirExists, |
274 | bool GCCCrossDirExists); |
275 | |
276 | bool ScanGentooConfigs(const llvm::Triple &TargetTriple, |
277 | const llvm::opt::ArgList &Args, |
278 | const SmallVectorImpl<StringRef> &CandidateTriples, |
279 | const SmallVectorImpl<StringRef> &BiarchTriples); |
280 | |
281 | bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, |
282 | const llvm::opt::ArgList &Args, |
283 | StringRef CandidateTriple, |
284 | bool NeedsBiarchSuffix = false); |
285 | }; |
286 | |
287 | protected: |
288 | GCCInstallationDetector GCCInstallation; |
289 | LazyDetector<CudaInstallationDetector> CudaInstallation; |
290 | LazyDetector<RocmInstallationDetector> RocmInstallation; |
291 | |
292 | public: |
293 | Generic_GCC(const Driver &D, const llvm::Triple &Triple, |
294 | const llvm::opt::ArgList &Args); |
295 | ~Generic_GCC() override; |
296 | |
297 | void printVerboseInfo(raw_ostream &OS) const override; |
298 | |
299 | UnwindTableLevel |
300 | getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; |
301 | bool isPICDefault() const override; |
302 | bool isPIEDefault(const llvm::opt::ArgList &Args) const override; |
303 | bool isPICDefaultForced() const override; |
304 | bool IsIntegratedAssemblerDefault() const override; |
305 | llvm::opt::DerivedArgList * |
306 | TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, |
307 | Action::OffloadKind DeviceOffloadKind) const override; |
308 | |
309 | protected: |
310 | Tool *getTool(Action::ActionClass AC) const override; |
311 | Tool *buildAssembler() const override; |
312 | Tool *buildLinker() const override; |
313 | |
314 | /// \name ToolChain Implementation Helper Functions |
315 | /// @{ |
316 | |
317 | /// Check whether the target triple's architecture is 64-bits. |
318 | bool isTarget64Bit() const { return getTriple().isArch64Bit(); } |
319 | |
320 | /// Check whether the target triple's architecture is 32-bits. |
321 | bool isTarget32Bit() const { return getTriple().isArch32Bit(); } |
322 | |
323 | void PushPPaths(ToolChain::path_list &PPaths); |
324 | void AddMultilibPaths(const Driver &D, const std::string &SysRoot, |
325 | const std::string &OSLibDir, |
326 | const std::string &MultiarchTriple, |
327 | path_list &Paths); |
328 | void AddMultiarchPaths(const Driver &D, const std::string &SysRoot, |
329 | const std::string &OSLibDir, path_list &Paths); |
330 | void AddMultilibIncludeArgs(const llvm::opt::ArgList &DriverArgs, |
331 | llvm::opt::ArgStringList &CC1Args) const; |
332 | |
333 | // FIXME: This should be final, but the CrossWindows toolchain does weird |
334 | // things that can't be easily generalized. |
335 | void AddClangCXXStdlibIncludeArgs( |
336 | const llvm::opt::ArgList &DriverArgs, |
337 | llvm::opt::ArgStringList &CC1Args) const override; |
338 | |
339 | virtual void |
340 | addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, |
341 | llvm::opt::ArgStringList &CC1Args) const; |
342 | virtual void |
343 | addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, |
344 | llvm::opt::ArgStringList &CC1Args) const; |
345 | |
346 | bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, |
347 | llvm::opt::ArgStringList &CC1Args, |
348 | StringRef DebianMultiarch) const; |
349 | |
350 | bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, |
351 | Twine IncludeSuffix, |
352 | const llvm::opt::ArgList &DriverArgs, |
353 | llvm::opt::ArgStringList &CC1Args, |
354 | bool DetectDebian = false) const; |
355 | |
356 | /// @} |
357 | |
358 | private: |
359 | mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess; |
360 | mutable std::unique_ptr<tools::gcc::Compiler> Compile; |
361 | }; |
362 | |
363 | class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { |
364 | virtual void anchor(); |
365 | |
366 | public: |
367 | Generic_ELF(const Driver &D, const llvm::Triple &Triple, |
368 | const llvm::opt::ArgList &Args) |
369 | : Generic_GCC(D, Triple, Args) {} |
370 | |
371 | void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, |
372 | llvm::opt::ArgStringList &CC1Args, |
373 | Action::OffloadKind DeviceOffloadKind) const override; |
374 | |
375 | virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const { |
376 | return {}; |
377 | } |
378 | |
379 | virtual void (llvm::opt::ArgStringList &CmdArgs) const {} |
380 | }; |
381 | |
382 | } // end namespace toolchains |
383 | } // end namespace driver |
384 | } // end namespace clang |
385 | |
386 | #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H |
387 | |