459 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H10#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H11 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 20namespace clang {21namespace driver {22 23struct 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 when31 /// targeting the non-default multilib. Otherwise, it is empty.32 std::optional<Multilib> BiarchSibling;33};34 35bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple,36 StringRef Path, const llvm::opt::ArgList &Args,37 DetectedMultilibs &Result);38 39namespace tools {40 41/// Directly call GNU Binutils' assembler and linker.42namespace gnutools {43class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {44public: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 55class LLVM_LIBRARY_VISIBILITY Linker : public Tool {56public: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 68class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool {69public: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 gnutools82 83/// gcc - Generic GCC tool implementations.84namespace gcc {85class LLVM_LIBRARY_VISIBILITY Common : public Tool {86public: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 an91 // object. Let it use that assembler so that we don't have to deal with92 // 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 force100 /// the particular tool mode.101 virtual void RenderExtraToolArgs(const JobAction &JA,102 llvm::opt::ArgStringList &CmdArgs) const = 0;103};104 105class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common {106public: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 RenderExtraToolArgs(const JobAction &JA,114 llvm::opt::ArgStringList &CmdArgs) const override;115};116 117class LLVM_LIBRARY_VISIBILITY Compiler : public Common {118public: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 RenderExtraToolArgs(const JobAction &JA,125 llvm::opt::ArgStringList &CmdArgs) const override;126};127 128class LLVM_LIBRARY_VISIBILITY Linker : public Common {129public: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 RenderExtraToolArgs(const JobAction &JA,136 llvm::opt::ArgStringList &CmdArgs) const override;137};138} // end namespace gcc139} // end namespace tools140 141namespace toolchains {142 143/// Generic_GCC - A tool chain using the 'gcc' command to perform144/// all subcommands; this relies on gcc translating the majority of145/// command line options.146class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {147public:148 /// Struct to store and manipulate GCC versions.149 ///150 /// We rely on assumptions about the form and structure of GCC version151 /// numbers: they consist of at most three '.'-separated components, and each152 /// component is a non-negative integer except for the last component. For153 /// the last component we are very flexible in order to tolerate release154 /// candidates or 'x' wildcards.155 ///156 /// Note that the ordering established among GCCVersions is based on the157 /// preferred version string to use. For example we prefer versions without158 /// 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 patches161 /// in the way that (for example) Debian's version format does. If that ever162 /// 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(RHS.Major, RHS.Minor, RHS.Patch, 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 Multilib209 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 to221 /// use.222 ///223 /// This class tries to find a GCC installation on the system, and report224 /// information about it. It starts from the host information provided to the225 /// 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 when234 /// 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 in238 // 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. The249 /// toolchains use this to adjust the target specific component of250 /// 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 into262 // std::optional<SelectedInstallation>263 // and move all accessors for fields of GCCInstallCandidate into264 // 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 Multilib289 const Multilib &getMultilib() const {290 return SelectedInstallation.SelectedMultilib;291 }292 293 /// Get the whole MultilibSet294 const MultilibSet &getMultilibs() const { return Multilibs; }295 296 /// Get the biarch sibling multilib (if it exists).297 /// \return true iff such a sibling exists298 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 void310 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++ include322 /// 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 and328 /// 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 356protected:357 GCCInstallationDetector GCCInstallation;358 LazyDetector<CudaInstallationDetector> CudaInstallation;359 LazyDetector<RocmInstallationDetector> RocmInstallation;360 LazyDetector<SYCLInstallationDetector> SYCLInstallation;361 362public: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 UnwindTableLevel370 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 379protected:380 Tool *getTool(Action::ActionClass AC) const override;381 Tool *buildAssembler() const override;382 Tool *buildLinker() const override;383 384 /// \name ToolChain Implementation Helper Functions385 /// @{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 weird404 // 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 void413 addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,414 llvm::opt::ArgStringList &CC1Args) const;415 virtual void416 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 430private:431 mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess;432 mutable std::unique_ptr<tools::gcc::Compiler> Compile;433};434 435class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {436 virtual void anchor();437 438public: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 addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {}452};453 454} // end namespace toolchains455} // end namespace driver456} // end namespace clang457 458#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H459