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