深入研究Clang(十七) Clang Driver庫的Tool

Tool也是Clang的Driver庫裏的一個類,它是具體編譯工具的信息,代碼註釋中的原文是:Tool - Information on a specific compilation tool.(clang/include/clang/Driver/Tool.h)本文將對Tool的實現以及其相關調用關係做一個簡單的分析。

一、Tool的實現和繼承關係

1、Tool的定義和實現都位於clang/include/clang/Driver/Tool.h和clang/lib/Driver/Tool.cpp之中。

2、Tool的成員變量(Tool.h中)很能說明Tool的相關信息:

  /// The tool name (for debugging).

  const char *Name;

  /// The human readable name for the tool, for use in diagnostics.

  const char *ShortName;

  /// The tool chain this tool is a part of.

  const ToolChain &TheToolChain;

這裏可以看到每個tool都有一個名字,還有一個短名字,同時還是構成一個tool chain的一部分。這裏也能看到,Tool和ToolChain是雙向關聯的,Tool中通過TheToolChain關聯到它所在的ToolChain,ToolChain通過如下列表和Tool關聯:

  mutable std::unique_ptr<Tool> Clang;
  mutable std::unique_ptr<Tool> Flang;
  mutable std::unique_ptr<Tool> Assemble;
  mutable std::unique_ptr<Tool> Link;
  mutable std::unique_ptr<Tool> IfsMerge;
  mutable std::unique_ptr<Tool> OffloadBundler;
  mutable std::unique_ptr<Tool> OffloadWrapper;

3、Tool在clang/lib/Driver/ToolChains目錄之下具有一系列的子類,以Clang.h爲例。Clang.h 之中定義了:

namespace clang {
class ObjCRuntime;
namespace driver {
namespace tools {

/// Clang compiler tool.
class LLVM_LIBRARY_VISIBILITY Clang : public Tool {

/// Clang integrated assembler tool.
class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {

/// Offload bundler tool.
class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool {

/// Offload wrapper tool.
class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool {

這裏面的Clang和ClangAs有AddRISCVTargetArgs 這樣的成員函數,爲Clang或者是ClangAs添加RISCV這樣的目標參數:

void Clang::AddRISCVTargetArgs(const ArgList &Args,
                               ArgStringList &CmdArgs) const {
  const llvm::Triple &Triple = getToolChain().getTriple();
  StringRef ABIName = riscv::getRISCVABI(Args, Triple);

  CmdArgs.push_back("-target-abi");
  CmdArgs.push_back(ABIName.data());

  SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs);
}

void ClangAs::AddRISCVTargetArgs(const ArgList &Args,
                               ArgStringList &CmdArgs) const {
  const llvm::Triple &Triple = getToolChain().getTriple();
  StringRef ABIName = riscv::getRISCVABI(Args, Triple);

  CmdArgs.push_back("-target-abi");
  CmdArgs.push_back(ABIName.data());
}

其中的riscv::getRISCVABI這個函數,就是在clang/lib/Driver/ToolChains/Arch/RISCV.h中聲明,在clang/lib/Driver/ToolChains/Arch/RISCV.cpp實現的。

4、clang/lib/Driver/ToolChains/Gun.h之中也定義了一系列的子類:

namespace tools {

/// Base class for all GNU tools that provide the same behavior when
/// it comes to response files support
class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool {

/// Directly call GNU Binutils' assembler and linker.
namespace gnutools {
class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {

class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {

/// gcc - Generic GCC tool implementations.
namespace gcc {
class LLVM_LIBRARY_VISIBILITY Common : public GnuTool {

class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common {

class LLVM_LIBRARY_VISIBILITY Compiler : public Common {

class LLVM_LIBRARY_VISIBILITY Linker : public Common {

這裏基於Tool,定義了子類GunTool,並且爲GunTool定義了子類Assembler 、Linker 和Common,又基於gcc::Common定義了Preprocessor和gcc::Preprocessor、gcc::Compiler 和gcc::Linker。

同時,本文件中還定義了toolchains的子類:

namespace toolchains {

/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {

class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {

Generic_ELF 是Generic_GCC 的子類,Generic_GCC 又是ToolChain 的子類。

二、Tool的調用關係

1、上一部分內容在介紹Tool的子類的同時,在Gun.h順便介紹了Generic_ELF類,它其實還是一部分類的父類。clang/lib/Driver/ToolChains/Linux.h中的Linux類,是操作系統相關類的典型,它繼承於Generic_ELF:

class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {

clang/lib/Driver/ToolChains/RISCVToolchain.h中的RISCVToolchain累,是硬件平臺相關類的典型,它也繼承於Generic_ELF:

classLLVM_LIBRARY_VISIBILITY RISCVToolChain : public Generic_ELF {

2、ToolChain對Tool的調用關係,比較顯然易見的是通過getXXX系列函數,對成員函數做操作的。其中還包含了buildAssembler和buildLinker。(clang/lib/Driver/ToolChain.cpp)

Tool *ToolChain::getClang() const {
  if (!Clang)
    Clang.reset(new tools::Clang(*this));
  return Clang.get();
}

Tool *ToolChain::getFlang() const {
  if (!Flang)
    Flang.reset(new tools::Flang(*this));
  return Flang.get();
}

Tool *ToolChain::buildAssembler() const {
  return new tools::ClangAs(*this);
}

Tool *ToolChain::buildLinker() const {
  llvm_unreachable("Linking is not supported by this toolchain");
}

Tool *ToolChain::getAssemble() const {
  if (!Assemble)
    Assemble.reset(buildAssembler());
  return Assemble.get();
}

Tool *ToolChain::getClangAs() const {
  if (!Assemble)
    Assemble.reset(new tools::ClangAs(*this));
  return Assemble.get();
}

Tool *ToolChain::getLink() const {
  if (!Link)
    Link.reset(buildLinker());
  return Link.get();
}

Tool *ToolChain::getIfsMerge() const {
  if (!IfsMerge)
    IfsMerge.reset(new tools::ifstool::Merger(*this));
  return IfsMerge.get();
}

Tool *ToolChain::getOffloadBundler() const {
  if (!OffloadBundler)
    OffloadBundler.reset(new tools::OffloadBundler(*this));
  return OffloadBundler.get();
}

Tool *ToolChain::getOffloadWrapper() const {
  if (!OffloadWrapper)
    OffloadWrapper.reset(new tools::OffloadWrapper(*this));
  return OffloadWrapper.get();
}

這些成員函數會在其子類中根據需要去進行重載。以RISCV相關的RISCVToolchain爲例(clang/lib/Driver/ToolChains/RISCVToolchain.cpp):

Tool *RISCVToolChain::buildLinker() const {
  return new tools::RISCV::Linker(*this);
}

其重載了buildLinker。

3、Tool對job的調用關係,主要體現在通過ConstructJob (clang/include/clang/Driver/Tool.h):

  /// ConstructJob - Construct jobs to perform the action \p JA,
  /// writing to \p Output and with \p Inputs, and add the jobs to
  /// \p C.
  ///
  /// \param TCArgs - The argument list for this toolchain, with any
  /// tool chain specific translations applied.
  /// \param LinkingOutput - If this output will eventually feed the
  /// linker, then this is the final output name of the linked image.
  virtual void ConstructJob(Compilation &C, const JobAction &JA,
                            const InputInfo &Output,
                            const InputInfoList &Inputs,
                            const llvm::opt::ArgList &TCArgs,
                            const char *LinkingOutput) const = 0;

這個成員函數,也在其子類之中進行重載。以RISCV相關的RISCV::Linker 爲例(clang/lib/Driver/ToolChains/RISCVToolchain.h):

namespace RISCV {
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
  Linker(const ToolChain &TC) : GnuTool("RISCV::Linker", "ld", TC) {}
  bool hasIntegratedCPP() const override { return false; }
  bool isLinkJob() const override { return true; }
  void ConstructJob(Compilation &C, const JobAction &JA,
                    const InputInfo &Output, const InputInfoList &Inputs,
                    const llvm::opt::ArgList &TCArgs,
                    const char *LinkingOutput) const override;
};

三、總結

1、Tool作爲一個概念,其上接ToolChain,下接job。

2、Tool作爲一個具體的類,其具有龐大的子類羣體,這些子類羣體包含了軟件因素相關的子類和硬件因素相關的子類。

3、Tool和ToolChain這兩個類本身都是獨立文件保存的,但是Tool的子類羣體和ToolChain的子類羣體,在很多情況下共存在頭文件和CPP文件之中的。

 

 

編輯於 2020-05-14

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章