深入研究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

©️2020 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值