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