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

Clang的Tool最終會調用ConstructJob來爲Compilation添加job。根據源碼中的註釋,Tool中保存的是一個特定編譯工具的信息(Tool - Information on a specific compilation tool.,clang/include/clang/Driver/Tool.h)。而job則是通過Command類去進行具體實現,同時還有一個相關類JobList。本文將分析Command和JobList的實現,以及其相關的調用關係。

一、Command和JobList的實現

1、Command和JobList的定義和實現都位於clang/include/clang/Driver/Job.h和clang/lib/Driver/Job.cpp。

2、Command類其實是job概念的對應實現。它表示的是一個將要執行的可執行路徑/名字和參數。源碼中的註釋爲: Command - An executable path/name and argument vector to execute.(clang/include/clang/Driver/Job.h)

3、Command類中包含了其所對應的Tool、Action以及可執行文件。從其源碼中可以明確看出(clang/include/clang/Driver/Job.h):

/// Command - An executable path/name and argument vector to
/// execute.
class Command {
  /// Source - The action which caused the creation of this job.
  const Action &Source;

  /// Tool - The tool which caused the creation of this job.
  const Tool &Creator;

  /// The executable to run.
  const char *Executable;

  /// The list of program arguments (not including the implicit first
  /// argument, which will be the executable).
  llvm::opt::ArgStringList Arguments;

  /// The list of program arguments which are inputs.
  llvm::opt::ArgStringList InputFilenames;

Command有其對應的Tool和Action。成員變量Creator,就是導致這個job(Command)被創建的Tool。成員變量Source,是導致這個job(Command)被創建的Action,有關Action的內容,在後續的部分進行介紹。成員變量Executable是要運行的可執行文件。

同時,Command還有一個重要的成員函數Execute,它的子類都會重載該函數,該函數爲:

  virtual int Execute(ArrayRef<Optional<StringRef>> Redirects,
                      std::string *ErrMsg, bool *ExecutionFailed) const;

4、Command類有兩個子類:CC1Command、FallbackCommand和ForceSuccessCommand。CC1Command是在可能的情況下使用CC1 tool進行回調,而避免新建一個進程。FallbackCommand比Command多提供一個回退,是爲了萬一出現最初的Command崩潰的時候使用。ForceSuccessCommand總是假裝wrapped command succeeded。具體代碼爲(clang/include/clang/Driver/Job.h):

/// Use the CC1 tool callback when available, to avoid creating a new process
class CC1Command : public Command {

/// Like Command, but with a fallback which is executed in case
/// the primary command crashes.
class FallbackCommand : public Command {

/// Like Command, but always pretends that the wrapped command succeeded.
class ForceSuccessCommand : public Command {

5、JobList類是用來表示一系列的job,也就是用來表示Command列表。其具體實現如下:

(clang/include/clang/Driver/Job.h)

/// JobList - A sequence of jobs to perform.
class JobList {
public:
  using list_type = SmallVector<std::unique_ptr<Command>, 4>;
  using size_type = list_type::size_type;
  using iterator = llvm::pointee_iterator<list_type::iterator>;
  using const_iterator = llvm::pointee_iterator<list_type::const_iterator>;

private:
  list_type Jobs;

public:
  void Print(llvm::raw_ostream &OS, const char *Terminator,
             bool Quote, CrashReportInfo *CrashInfo = nullptr) const;

  /// Add a job to the list (taking ownership).
  void addJob(std::unique_ptr<Command> J) { Jobs.push_back(std::move(J)); }

JobList的實現,主要就是維護了Jobs這個列表,並且提供了對該列表的相關操作,包括添加、清空、迭代器等。

二、Command和JobList的調用關係

1、Clang的Tool最終會調用ConstructJob來爲Compilation添加job(Command)。以RISCV::Linker::ConstructJob(clang/lib/Driver/ToolChains/RISCVToolchain.cpp)爲例,其最終調用了Compilation的addCommand來爲Compilation添加job(Command),具體源碼如下(clang/lib/Driver/ToolChains/RISCVToolchain.cpp):

  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
                                          CmdArgs, Inputs));

這裏其實是構建除了一個Command對象,並且通過addCommand來爲Compilation添加job(Command)。

Compilation的addCommand實現如下(clang/include/clang/Driver/Compilation.h):

  void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(std::move(C)); }

其中Jobs的定義爲(clang/include/clang/Driver/Compilation.h):

  /// The root list of jobs.
  JobList Jobs;

至此,Tool對於Command以及JobList的調用及其關係就已經就很清晰了。

發佈於 2020-05-14

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