Option Parsing in the Swift Compiler

This article contains some content especially for patrons. Although it reads coherently as-is, to read the full article, please consider supporting me on Patreon, or click here if you are already a patron. $10/month gives you access to all content I will ever write on this website.

The last article in this series explained how libswiftDriver split up swift executable invocations into smaller sub-jobs. Parsing command-line arguments is a big part of that work, but I didn't go into much detail about it. This article will now explain command-line argument parsing in depth.

Specifically, this article describes how:

  1. Within the Swift build system, LLVM TableGen is used to transform the options specified in swift/include/swift/Option/Options.td. The transformed output is written to a file named Options.inc.
  2. A libswiftOption header includes the Options.inc file in order to define an enum named swift::options::ID. By defining a macro before including Options.inc file, it's able to define an enum case for each option defined in the original Options.td file: swift::options::ID::OPT_driver_print_jobs, swift::options::ID::OPT_driver_print_actions, and so on.
  3. In its implementation, libswiftOption defines a macro, then includes the Options.inc file a second time, this time in order to initialize an llvm::opt::OptTable. The OptTable class is defined in libLLVMOption and provides argument parsing utilities.
  4. In its swift::Driver::buildCompilation method, libswiftDriver calls the llvm::opt::OptTable::ParseArgs method. This takes the array of strings passed into the swift compiler executable's main function as an argument, and it returns an llvm::opt::InputArgList. This class defines the methods used throughout the Swift compiler codebase. The InputArgList::hasArg method, which checks for the presence of an argument, is perhaps the most common.

Many contributions to the Swift compiler involve modifying or adding command-line options. Understanding how these options are parsed has helped me make such contributions.

An introduction to LLVM TableGen

$10+ patron-only content

An explanation of LLVM TableGen: how to invoke it, and why the LLVM and Swift projects use it.

I am a patronBecome a patron

Stage 1: Swift's CMake instructs TableGen to transform Options.td into Options.inc

$10+ patron-only content

An explanation of the Swift CMake that defines how to invoke llvm-tblgen, in order to transform the Swift Options.td file into C macro invocations.

I am a patronBecome a patron

Stage 2: The libswiftOption headers declare an enum containing a case for each of the options

$10+ patron-only content

An explanation of how libswiftOption consumes the tablegenerated options in order to define an enum.

I am a patronBecome a patron

Stage 3: libswiftOption instantiates an llvm::opt::OptTable, with an llvm::opt::OptTable::Info element for each of the options

$10+ patron-only content

An explanation of libLLVMOption data structures such as llvm::opt::OptTable, as well as how libswiftOption instantiates these structures.

I am a patronBecome a patron

Stage 4: libswiftDriver calls the llvm::opt::OptTable::ParseArgs method

$10+ patron-only content

An explanation of how libswiftOption parses arguments from within libswiftDriver. This shows some of the libLLVMOption API in action, such as llvm::opt::InputArgList::hasArg. If you've peeked at the Swift compiler source code, chances are you've seen calls to this method!

I am a patronBecome a patron

Sorry, no magic here

I enjoy looking into the details of the Swift compiler because – and maybe this sounds silly – it helps me better understand that it's "just a program".

Because I was unfamilar with the LLVM TableGen utility, and with the C/C++ macros that the Swift compiler uses to define its options, it seemed like magic to me that modifying the Options.td file would result in changes to Swift's command-line options. But it's not magic – as this article described, it's a four-stage process in which:

  1. The Options.td file is transformed by TableGen.
  2. The transformed file, Options.inc, is included such that it defines a large enum with all the Swift options as values.
  3. The transformed file is included again, this time to intiialize an LLVM OptTable. This class is capable of searching command-line arguments for option values.
  4. The rest of the Swift compiler codebase uses the LLVM OptTable class to check for arguments as necessary.

I hope this article has helped you learn about option parsing in the Swift compiler. If you enjoyed this article and would like to read more like it, please consider supporting me on Patreon. I wouldn't be able to write these articles were it not for the support I receive.