Swift Compiler Driver
本文基于Swift 5.5的源码: https://github.com/apple/swift/tree/release/5.5
1. Driver Tool
Ref[2] 是Driver命令行工具的CMakeLists.txt文件。
add_swift_host_tool(swift-frontend driver.cpp autolink_extract_main.cpp modulewrap_main.cpp swift_api_digester_main.cpp swift_indent_main.cpp swift_symbolgraph_extract_main.cpp swift_api_extract_main.cpp SWIFT_COMPONENT compiler ) target_link_libraries(swift-frontend PRIVATE swiftAPIDigester swiftDriver swiftFrontendTool swiftSymbolGraphGen LLVMBitstreamReader)
1.1 Driver Tool Source Files
Main函数
通过add_swift_host_tool()来定义Driver Tool的源文件,其中driver.cpp为源文件的"入口",该文件中定义了main()函数。
main()函数的主体逻辑如下所示:
1 int main(int argc_, const char **argv_) { 2 // ... ... 3 4 // Check if this invocation should execute a subcommand. 5 StringRef ExecName = llvm::sys::path::stem(argv[0]); 6 SmallString<256> SubcommandName; 7 bool isRepl = false; 8 if (shouldRunAsSubcommand(ExecName, SubcommandName, argv, isRepl)) { // Branch-A 9 // ... ... 10 11 return 2; 12 } 13 14 if (isRepl) { 15 // Preserve argv for the stack trace. 16 SmallVector<const char *, 256> replArgs(argv.begin(), argv.end()); 17 replArgs.erase(&replArgs[1]); 18 return run_driver(ExecName, replArgs); // Branch-B 19 } else { 20 return run_driver(ExecName, argv); // Branch-C 21 } 22 23 }
当以"/usr/bin/swiftc --driver-mode=swift -L /Users/zhangchong/SpareTime/DangerUsage/.build/debug -I /Users/zhangchong/SpareTime/DangerUsage/.build/debug -lDanger /var/folders/g0/wz34vwx54616p8q9thj8yyd00000gp/T/_tmp_dangerfile.swift runner"调用swiftc时, main函数会进入到Branch-C。
run_driver函数
在执行"/usr/bin/swiftc --driver-mode=swift -L /Users/zhangchong/SpareTime/DangerUsage/.build/debug -I /Users/zhangchong/SpareTime/DangerUsage/.build/debug -lDanger /var/folders/g0/wz34vwx54616p8q9thj8yyd00000gp/T/_tmp_dangerfile.swift runner"时,run_driver函数实际上执行Part-D部分。
1 static int run_driver(StringRef ExecName, 2 const ArrayRef<const char *> argv) { 3 4 // Part-A: Check the first argument. 5 // Handle integrated tools. 6 if (argv.size() > 1) { 7 StringRef FirstArg(argv[1]); 8 if (FirstArg == "-frontend") { 9 return performFrontend(llvm::makeArrayRef(argv.data()+2, 10 argv.data()+argv.size()), 11 argv[0], (void *)(intptr_t)getExecutablePath); 12 } 13 if (FirstArg == "-modulewrap") { 14 return modulewrap_main(llvm::makeArrayRef(argv.data()+2, 15 argv.data()+argv.size()), 16 argv[0], (void *)(intptr_t)getExecutablePath); 17 } 18 19 // Run the integrated Swift frontend when called as "swift-frontend" but 20 // without a leading "-frontend". 21 if (!FirstArg.startswith("--driver-mode=") 22 && ExecName == "swift-frontend") { 23 return performFrontend(llvm::makeArrayRef(argv.data()+1, 24 argv.data()+argv.size()), 25 argv[0], (void *)(intptr_t)getExecutablePath); 26 } 27 } 28 29 30 // ... ... 31 32 // Part-B: Should we disable the new swift-driver? 33 if (!shouldDisallowNewDriver(ExecName, argv)) { 34 SmallString<256> NewDriverPath(llvm::sys::path::parent_path(Path)); 35 if (appendSwiftDriverName(NewDriverPath) && 36 llvm::sys::fs::exists(NewDriverPath)) { 37 38 // ... ... 39 return 2; 40 } 41 } 42 43 // Part-C: Select the different tools based on the kind of Driver instance. 44 Driver TheDriver(Path, ExecName, argv, Diags); 45 switch (TheDriver.getDriverKind()) { 46 case Driver::DriverKind::AutolinkExtract: 47 return autolink_extract_main( 48 TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), 49 argv[0], (void *)(intptr_t)getExecutablePath); 50 case Driver::DriverKind::SwiftIndent: 51 return swift_indent_main( 52 TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), 53 argv[0], (void *)(intptr_t)getExecutablePath); 54 case Driver::DriverKind::SymbolGraph: 55 return swift_symbolgraph_extract_main(TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], (void *)(intptr_t)getExecutablePath); 56 case Driver::DriverKind::APIExtract: 57 return swift_api_extract_main( 58 TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], 59 (void *)(intptr_t)getExecutablePath); 60 case Driver::DriverKind::APIDigester: 61 return swift_api_digester_main( 62 TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], 63 (void *)(intptr_t)getExecutablePath); 64 default: 65 break; 66 } 67 68 // Part-D: Do the real compilation. (ignore the error check.) 69 // Parse the arguments that from the command line. 70 std::unique_ptr<llvm::opt::InputArgList> ArgList = 71 TheDriver.parseArgStrings(ArrayRef<const char*>(argv).slice(1)); 72 // Build a ToolChain instance. 73 std::unique_ptr<ToolChain> TC = TheDriver.buildToolChain(*ArgList); 74 // Build a Compilation instance. 75 std::unique_ptr<Compilation> C = 76 TheDriver.buildCompilation(*TC, std::move(ArgList)); 77 if (C) { 78 // Build the task queue from the Compilation instance. 79 std::unique_ptr<sys::TaskQueue> TQ = TheDriver.buildTaskQueue(*C); 80 if (!TQ) 81 return 1; 82 // Run the jobs which are generated from the task queue. 83 return C->performJobs(std::move(TQ)).exitCode; 84 } 85 86 return 0; 87 88 }
1.2 Driver Tool Dependencies
2. swiftDriver library
Ref[1] 是swiftDriver库的CMakeLists.txt文件。
3. Driver Mode
`--driver-mode`的定义在Options.inc文件中, Options.inc文件是生成的。
TODO: 如何生成Options.inc文件?
从https://gist.github.com/vitonzhangtt/7f6f6feaa0e61373d90bbf9291d2b66b#file-options-inc-L322 可以看出
`--driver-mode`的值可以为: swift, 或者swiftc。
3.1 Driver Kind
Driver是整个编译过程的"驱动器",Driver Kind保存Driver的类型。
Driver Kind有一些作用:
1. 决定Driver对命令行参数的解析
2. 影响OutputInput的生成
https://github1s.com/apple/swift/blob/release/5.5/lib/Driver/Driver.cpp#L1472-L1475
1 2 // OutputInfo &OI 3 OI.CompilerOutputType = driverKind == DriverKind::Interactive 4 ? file_types::TY_Nothing 5 : CompilerOutputType;
3. 影响Compiler Mode
https://github1s.com/apple/swift/blob/release/5.5/lib/Driver/Driver.cpp#L1854-L1857
// const InputFileList &Inputs if (driverKind == Driver::DriverKind::Interactive) return Inputs.empty() ? OutputInfo::Mode::REPL : OutputInfo::Mode::Immediate;
4. 影响-help选项的输出
https://github1s.com/apple/swift/blob/release/5.5/lib/Driver/Driver.cpp#L3535-L3540
3.2 DriverKind的计算
Driver Mode决定了部分DriverKind的取值。
在Driver的构造函数中,首先进行DriverKind的计算:
1 Driver::Driver(StringRef DriverExecutable, 2 StringRef Name, 3 ArrayRef<const char *> Args, 4 DiagnosticEngine &Diags) 5 : Opts(createSwiftOptTable()), Diags(Diags), 6 Name(Name), DriverExecutable(DriverExecutable), 7 DefaultTargetTriple(llvm::sys::getDefaultTargetTriple()) { 8 9 // The driver kind must be parsed prior to parsing arguments, since that 10 // affects how arguments are parsed. 11 parseDriverKind(Args.slice(1)); 12 } 13 14 void Driver::parseDriverKind(ArrayRef<const char *> Args) { 15 // The default driver kind is determined by Name. 16 StringRef DriverName = Name; 17 18 std::string OptName; 19 // However, the driver kind may be overridden if the first argument is 20 // --driver-mode. 21 if (!Args.empty()) { 22 OptName = getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); 23 24 StringRef FirstArg(Args[0]); 25 if (FirstArg.startswith(OptName)) 26 DriverName = FirstArg.drop_front(OptName.size()); 27 } 28 29 Optional<DriverKind> Kind = 30 llvm::StringSwitch<Optional<DriverKind>>(DriverName) 31 .Case("swift", DriverKind::Interactive) // --driver-mode=swift 32 .Case("swiftc", DriverKind::Batch). // --driver-mode=swiftc 33 .Case("swift-autolink-extract", DriverKind::AutolinkExtract) 34 .Case("swift-indent", DriverKind::SwiftIndent) 35 .Case("swift-symbolgraph-extract", DriverKind::SymbolGraph) 36 .Case("swift-api-extract", DriverKind::APIExtract) 37 .Case("swift-api-digester", DriverKind::APIDigester) 38 .Default(None); 39 40 if (Kind.hasValue()) 41 driverKind = Kind.getValue(); // driverKind is member of Driver Class. 42 else if (!OptName.empty()) 43 Diags.diagnose({}, diag::error_invalid_arg_value, OptName, DriverName); 44 }
Interactive: swift --driver-mode=swift
Batch: swift --driver-mode=swiftc
1. --driver-mode=swiftc
swiftc --driver-mode=swiftc hello.swift
编译hello.swift文件,生成可执行文件hello。
2. --driver-mode=swift
swiftc --driver-mode=swift hello.swift
编译并执行hello.swift文件。
Next: swift-driver
Reference
1. CMakeLists.txt for swiftDriver
https://github.com/apple/swift/blob/release/5.5/lib/Driver/CMakeLists.txt
2. CMakeLists.txt for swift-frontend
https://github.com/apple/swift/blob/release/5.5/tools/driver/CMakeLists.txt
3. Headers file for swiftDriver
https://github.com/apple/swift/tree/release/5.5/include/swift/Driver
4. Options.inc
https://gist.github.com/vitonzhangtt/7f6f6feaa0e61373d90bbf9291d2b66b