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

Posted snsn1984

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入研究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

以上是关于深入研究Clang(十七) Clang Driver库的Tool的主要内容,如果未能解决你的问题,请参考以下文章

深入研究Clang(十六) Clang Driver库的ToolChain

深入研究Clang(十六) Clang Driver库的ToolChain

深入研究Clang(十八) Clang Driver库的job

深入研究Clang(十八) Clang Driver库的job

深入研究Clang(十四) clang-tidy的使用

深入研究Clang(十九) Clang的RISCV支持2