| 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 "clang/Driver/CudaInstallationDetector.h" |
| 13 | #include "clang/Driver/LazyDetector.h" |
| 14 | #include "clang/Driver/RocmInstallationDetector.h" |
| 15 | #include "clang/Driver/SyclInstallationDetector.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 | struct GCCInstallCandidate { |
| 188 | // FIXME: These might be better as path objects. |
| 189 | std::string GCCInstallPath; |
| 190 | std::string GCCParentLibPath; |
| 191 | |
| 192 | llvm::Triple GCCTriple; |
| 193 | |
| 194 | /// The primary multilib appropriate for the given flags. |
| 195 | Multilib SelectedMultilib; |
| 196 | |
| 197 | GCCVersion Version; |
| 198 | |
| 199 | /// Get the GCC triple for the detected install. |
| 200 | const llvm::Triple &getTriple() const { return GCCTriple; } |
| 201 | |
| 202 | /// Get the detected GCC installation path. |
| 203 | StringRef getInstallPath() const { return GCCInstallPath; } |
| 204 | |
| 205 | /// Get the detected GCC parent lib path. |
| 206 | StringRef getParentLibPath() const { return GCCParentLibPath; } |
| 207 | |
| 208 | /// Get the detected Multilib |
| 209 | const Multilib &getMultilib() const { return SelectedMultilib; } |
| 210 | |
| 211 | /// Get the detected GCC version string. |
| 212 | const GCCVersion &getVersion() const { return Version; } |
| 213 | |
| 214 | bool addGCCLibStdCxxIncludePaths(llvm::vfs::FileSystem &vfs, |
| 215 | const llvm::opt::ArgList &DriverArgs, |
| 216 | llvm::opt::ArgStringList &CC1Args, |
| 217 | StringRef DebianMultiarch) const; |
| 218 | }; |
| 219 | |
| 220 | /// This is a class to find a viable GCC installation for Clang to |
| 221 | /// use. |
| 222 | /// |
| 223 | /// This class tries to find a GCC installation on the system, and report |
| 224 | /// information about it. It starts from the host information provided to the |
| 225 | /// Driver, and has logic for fuzzing that where appropriate. |
| 226 | class GCCInstallationDetector { |
| 227 | bool IsValid; |
| 228 | |
| 229 | const Driver &D; |
| 230 | |
| 231 | GCCInstallCandidate SelectedInstallation; |
| 232 | |
| 233 | /// On Biarch systems, this corresponds to the default multilib when |
| 234 | /// targeting the non-default multilib. Otherwise, it is empty. |
| 235 | std::optional<Multilib> BiarchSibling; |
| 236 | |
| 237 | // We retain the list of install paths that were considered and rejected in |
| 238 | // order to print out detailed information in verbose mode. |
| 239 | std::set<std::string> CandidateGCCInstallPaths; |
| 240 | |
| 241 | /// The set of multilibs that the detected installation supports. |
| 242 | MultilibSet Multilibs; |
| 243 | |
| 244 | // Gentoo-specific toolchain configurations are stored here. |
| 245 | const std::string GentooConfigDir = "/etc/env.d/gcc" ; |
| 246 | |
| 247 | public: |
| 248 | /// Function for converting a triple to a Debian multiarch. The |
| 249 | /// toolchains use this to adjust the target specific component of |
| 250 | /// include paths for Debian. |
| 251 | std::function<StringRef(const llvm::Triple &)> TripleToDebianMultiarch = |
| 252 | [](const llvm::Triple &T) { |
| 253 | StringRef S = T.str(); |
| 254 | return S; |
| 255 | }; |
| 256 | |
| 257 | explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} |
| 258 | |
| 259 | void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); |
| 260 | |
| 261 | // TODO Replace isValid by changing SelectedInstallation into |
| 262 | // std::optional<SelectedInstallation> |
| 263 | // and move all accessors for fields of GCCInstallCandidate into |
| 264 | // that struct. |
| 265 | |
| 266 | /// Check whether we detected a valid GCC install. |
| 267 | bool isValid() const { return IsValid; } |
| 268 | |
| 269 | const GCCInstallCandidate &getSelectedInstallation() const { |
| 270 | return SelectedInstallation; |
| 271 | } |
| 272 | |
| 273 | /// Get the GCC triple for the detected install. |
| 274 | const llvm::Triple &getTriple() const { |
| 275 | return SelectedInstallation.GCCTriple; |
| 276 | } |
| 277 | |
| 278 | /// Get the detected GCC installation path. |
| 279 | StringRef getInstallPath() const { |
| 280 | return SelectedInstallation.GCCInstallPath; |
| 281 | } |
| 282 | |
| 283 | /// Get the detected GCC parent lib path. |
| 284 | StringRef getParentLibPath() const { |
| 285 | return SelectedInstallation.GCCParentLibPath; |
| 286 | } |
| 287 | |
| 288 | /// Get the detected Multilib |
| 289 | const Multilib &getMultilib() const { |
| 290 | return SelectedInstallation.SelectedMultilib; |
| 291 | } |
| 292 | |
| 293 | /// Get the whole MultilibSet |
| 294 | const MultilibSet &getMultilibs() const { return Multilibs; } |
| 295 | |
| 296 | /// Get the biarch sibling multilib (if it exists). |
| 297 | /// \return true iff such a sibling exists |
| 298 | bool getBiarchSibling(Multilib &M) const; |
| 299 | |
| 300 | /// Get the detected GCC version string. |
| 301 | const GCCVersion &getVersion() const { |
| 302 | return SelectedInstallation.Version; |
| 303 | } |
| 304 | |
| 305 | /// Print information about the detected GCC installation. |
| 306 | void print(raw_ostream &OS) const; |
| 307 | |
| 308 | private: |
| 309 | static void |
| 310 | CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, |
| 311 | const llvm::Triple &BiarchTriple, |
| 312 | SmallVectorImpl<StringRef> &LibDirs, |
| 313 | SmallVectorImpl<StringRef> &TripleAliases, |
| 314 | SmallVectorImpl<StringRef> &BiarchLibDirs, |
| 315 | SmallVectorImpl<StringRef> &BiarchTripleAliases); |
| 316 | |
| 317 | void AddDefaultGCCPrefixes(const llvm::Triple &TargetTriple, |
| 318 | SmallVectorImpl<std::string> &Prefixes, |
| 319 | StringRef SysRoot); |
| 320 | |
| 321 | /// Checks if the \p GCCInstallation has libstdc++ include |
| 322 | /// directories. |
| 323 | bool GCCInstallationHasLibStdcxxIncludePaths( |
| 324 | const GCCInstallCandidate &GCCInstallation, |
| 325 | const llvm::opt::ArgList &DriverArgs) const; |
| 326 | |
| 327 | /// Select a GCC installation directory from \p Installations and |
| 328 | /// set \p SelectedInstallation accordingly. |
| 329 | bool SelectGCCInstallationDirectory( |
| 330 | const SmallVector<GCCInstallCandidate, 3> &Installations, |
| 331 | const llvm::opt::ArgList &Args, |
| 332 | GCCInstallCandidate &SelectedInstallation) const; |
| 333 | |
| 334 | bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, |
| 335 | const llvm::opt::ArgList &Args, StringRef Path, |
| 336 | bool NeedsBiarchSuffix = false); |
| 337 | |
| 338 | void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, |
| 339 | const llvm::opt::ArgList &Args, |
| 340 | const std::string &LibDir, |
| 341 | StringRef CandidateTriple, |
| 342 | bool NeedsBiarchSuffix, bool GCCDirExists, |
| 343 | bool GCCCrossDirExists); |
| 344 | |
| 345 | bool ScanGentooConfigs(const llvm::Triple &TargetTriple, |
| 346 | const llvm::opt::ArgList &Args, |
| 347 | const SmallVectorImpl<StringRef> &CandidateTriples, |
| 348 | const SmallVectorImpl<StringRef> &BiarchTriples); |
| 349 | |
| 350 | bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, |
| 351 | const llvm::opt::ArgList &Args, |
| 352 | StringRef CandidateTriple, |
| 353 | bool NeedsBiarchSuffix = false); |
| 354 | }; |
| 355 | |
| 356 | protected: |
| 357 | GCCInstallationDetector GCCInstallation; |
| 358 | LazyDetector<CudaInstallationDetector> CudaInstallation; |
| 359 | LazyDetector<RocmInstallationDetector> RocmInstallation; |
| 360 | LazyDetector<SYCLInstallationDetector> SYCLInstallation; |
| 361 | |
| 362 | public: |
| 363 | Generic_GCC(const Driver &D, const llvm::Triple &Triple, |
| 364 | const llvm::opt::ArgList &Args); |
| 365 | ~Generic_GCC() override; |
| 366 | |
| 367 | void printVerboseInfo(raw_ostream &OS) const override; |
| 368 | |
| 369 | UnwindTableLevel |
| 370 | getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; |
| 371 | bool isPICDefault() const override; |
| 372 | bool isPIEDefault(const llvm::opt::ArgList &Args) const override; |
| 373 | bool isPICDefaultForced() const override; |
| 374 | bool IsIntegratedAssemblerDefault() const override; |
| 375 | llvm::opt::DerivedArgList * |
| 376 | TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, |
| 377 | Action::OffloadKind DeviceOffloadKind) const override; |
| 378 | |
| 379 | protected: |
| 380 | Tool *getTool(Action::ActionClass AC) const override; |
| 381 | Tool *buildAssembler() const override; |
| 382 | Tool *buildLinker() const override; |
| 383 | |
| 384 | /// \name ToolChain Implementation Helper Functions |
| 385 | /// @{ |
| 386 | |
| 387 | /// Check whether the target triple's architecture is 64-bits. |
| 388 | bool isTarget64Bit() const { return getTriple().isArch64Bit(); } |
| 389 | |
| 390 | /// Check whether the target triple's architecture is 32-bits. |
| 391 | bool isTarget32Bit() const { return getTriple().isArch32Bit(); } |
| 392 | |
| 393 | void PushPPaths(ToolChain::path_list &PPaths); |
| 394 | void AddMultilibPaths(const Driver &D, const std::string &SysRoot, |
| 395 | const std::string &OSLibDir, |
| 396 | const std::string &MultiarchTriple, |
| 397 | path_list &Paths); |
| 398 | void AddMultiarchPaths(const Driver &D, const std::string &SysRoot, |
| 399 | const std::string &OSLibDir, path_list &Paths); |
| 400 | void AddMultilibIncludeArgs(const llvm::opt::ArgList &DriverArgs, |
| 401 | llvm::opt::ArgStringList &CC1Args) const; |
| 402 | |
| 403 | // FIXME: This should be final, but the CrossWindows toolchain does weird |
| 404 | // things that can't be easily generalized. |
| 405 | void AddClangCXXStdlibIncludeArgs( |
| 406 | const llvm::opt::ArgList &DriverArgs, |
| 407 | llvm::opt::ArgStringList &CC1Args) const override; |
| 408 | |
| 409 | void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, |
| 410 | llvm::opt::ArgStringList &CC1Args) const override; |
| 411 | |
| 412 | virtual void |
| 413 | addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, |
| 414 | llvm::opt::ArgStringList &CC1Args) const; |
| 415 | virtual void |
| 416 | addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, |
| 417 | llvm::opt::ArgStringList &CC1Args) const; |
| 418 | |
| 419 | bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, |
| 420 | llvm::opt::ArgStringList &CC) const; |
| 421 | |
| 422 | bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, |
| 423 | Twine IncludeSuffix, |
| 424 | const llvm::opt::ArgList &DriverArgs, |
| 425 | llvm::opt::ArgStringList &CC1Args, |
| 426 | bool DetectDebian = false) const; |
| 427 | |
| 428 | /// @} |
| 429 | |
| 430 | private: |
| 431 | mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess; |
| 432 | mutable std::unique_ptr<tools::gcc::Compiler> Compile; |
| 433 | }; |
| 434 | |
| 435 | class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { |
| 436 | virtual void anchor(); |
| 437 | |
| 438 | public: |
| 439 | Generic_ELF(const Driver &D, const llvm::Triple &Triple, |
| 440 | const llvm::opt::ArgList &Args) |
| 441 | : Generic_GCC(D, Triple, Args) {} |
| 442 | |
| 443 | void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, |
| 444 | llvm::opt::ArgStringList &CC1Args, |
| 445 | Action::OffloadKind DeviceOffloadKind) const override; |
| 446 | |
| 447 | virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const { |
| 448 | return {}; |
| 449 | } |
| 450 | |
| 451 | virtual void (llvm::opt::ArgStringList &CmdArgs) const {} |
| 452 | }; |
| 453 | |
| 454 | } // end namespace toolchains |
| 455 | } // end namespace driver |
| 456 | } // end namespace clang |
| 457 | |
| 458 | #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H |
| 459 | |