401 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			401 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
=========================
 | 
						|
Driver Design & Internals
 | 
						|
=========================
 | 
						|
 | 
						|
.. contents::
 | 
						|
   :local:
 | 
						|
 | 
						|
Introduction
 | 
						|
============
 | 
						|
 | 
						|
This document describes the Clang driver. The purpose of this document
 | 
						|
is to describe both the motivation and design goals for the driver, as
 | 
						|
well as details of the internal implementation.
 | 
						|
 | 
						|
Features and Goals
 | 
						|
==================
 | 
						|
 | 
						|
The Clang driver is intended to be a production quality compiler driver
 | 
						|
providing access to the Clang compiler and tools, with a command line
 | 
						|
interface which is compatible with the gcc driver.
 | 
						|
 | 
						|
Although the driver is part of and driven by the Clang project, it is
 | 
						|
logically a separate tool which shares many of the same goals as Clang:
 | 
						|
 | 
						|
.. contents:: Features
 | 
						|
   :local:
 | 
						|
 | 
						|
GCC Compatibility
 | 
						|
-----------------
 | 
						|
 | 
						|
The number one goal of the driver is to ease the adoption of Clang by
 | 
						|
allowing users to drop Clang into a build system which was designed to
 | 
						|
call GCC. Although this makes the driver much more complicated than
 | 
						|
might otherwise be necessary, we decided that being very compatible with
 | 
						|
the gcc command line interface was worth it in order to allow users to
 | 
						|
quickly test clang on their projects.
 | 
						|
 | 
						|
Flexible
 | 
						|
--------
 | 
						|
 | 
						|
The driver was designed to be flexible and easily accommodate new uses
 | 
						|
as we grow the clang and LLVM infrastructure. As one example, the driver
 | 
						|
can easily support the introduction of tools which have an integrated
 | 
						|
assembler; something we hope to add to LLVM in the future.
 | 
						|
 | 
						|
Similarly, most of the driver functionality is kept in a library which
 | 
						|
can be used to build other tools which want to implement or accept a gcc
 | 
						|
like interface.
 | 
						|
 | 
						|
Low Overhead
 | 
						|
------------
 | 
						|
 | 
						|
The driver should have as little overhead as possible. In practice, we
 | 
						|
found that the gcc driver by itself incurred a small but meaningful
 | 
						|
overhead when compiling many small files. The driver doesn't do much
 | 
						|
work compared to a compilation, but we have tried to keep it as
 | 
						|
efficient as possible by following a few simple principles:
 | 
						|
 | 
						|
-  Avoid memory allocation and string copying when possible.
 | 
						|
-  Don't parse arguments more than once.
 | 
						|
-  Provide a few simple interfaces for efficiently searching arguments.
 | 
						|
 | 
						|
Simple
 | 
						|
------
 | 
						|
 | 
						|
Finally, the driver was designed to be "as simple as possible", given
 | 
						|
the other goals. Notably, trying to be completely compatible with the
 | 
						|
gcc driver adds a significant amount of complexity. However, the design
 | 
						|
of the driver attempts to mitigate this complexity by dividing the
 | 
						|
process into a number of independent stages instead of a single
 | 
						|
monolithic task.
 | 
						|
 | 
						|
Internal Design and Implementation
 | 
						|
==================================
 | 
						|
 | 
						|
.. contents::
 | 
						|
   :local:
 | 
						|
   :depth: 1
 | 
						|
 | 
						|
Internals Introduction
 | 
						|
----------------------
 | 
						|
 | 
						|
In order to satisfy the stated goals, the driver was designed to
 | 
						|
completely subsume the functionality of the gcc executable; that is, the
 | 
						|
driver should not need to delegate to gcc to perform subtasks. On
 | 
						|
Darwin, this implies that the Clang driver also subsumes the gcc
 | 
						|
driver-driver, which is used to implement support for building universal
 | 
						|
images (binaries and object files). This also implies that the driver
 | 
						|
should be able to call the language specific compilers (e.g. cc1)
 | 
						|
directly, which means that it must have enough information to forward
 | 
						|
command line arguments to child processes correctly.
 | 
						|
 | 
						|
Design Overview
 | 
						|
---------------
 | 
						|
 | 
						|
The diagram below shows the significant components of the driver
 | 
						|
architecture and how they relate to one another. The orange components
 | 
						|
represent concrete data structures built by the driver, the green
 | 
						|
components indicate conceptually distinct stages which manipulate these
 | 
						|
data structures, and the blue components are important helper classes.
 | 
						|
 | 
						|
.. image:: DriverArchitecture.png
 | 
						|
   :align: center
 | 
						|
   :alt: Driver Architecture Diagram
 | 
						|
 | 
						|
Driver Stages
 | 
						|
-------------
 | 
						|
 | 
						|
The driver functionality is conceptually divided into five stages:
 | 
						|
 | 
						|
#. **Parse: Option Parsing**
 | 
						|
 | 
						|
   The command line argument strings are decomposed into arguments
 | 
						|
   (``Arg`` instances). The driver expects to understand all available
 | 
						|
   options, although there is some facility for just passing certain
 | 
						|
   classes of options through (like ``-Wl,``).
 | 
						|
 | 
						|
   Each argument corresponds to exactly one abstract ``Option``
 | 
						|
   definition, which describes how the option is parsed along with some
 | 
						|
   additional metadata. The Arg instances themselves are lightweight and
 | 
						|
   merely contain enough information for clients to determine which
 | 
						|
   option they correspond to and their values (if they have additional
 | 
						|
   parameters).
 | 
						|
 | 
						|
   For example, a command line like "-Ifoo -I foo" would parse to two
 | 
						|
   Arg instances (a JoinedArg and a SeparateArg instance), but each
 | 
						|
   would refer to the same Option.
 | 
						|
 | 
						|
   Options are lazily created in order to avoid populating all Option
 | 
						|
   classes when the driver is loaded. Most of the driver code only needs
 | 
						|
   to deal with options by their unique ID (e.g., ``options::OPT_I``),
 | 
						|
 | 
						|
   Arg instances themselves do not generally store the values of
 | 
						|
   parameters. In many cases, this would simply result in creating
 | 
						|
   unnecessary string copies. Instead, Arg instances are always embedded
 | 
						|
   inside an ArgList structure, which contains the original vector of
 | 
						|
   argument strings. Each Arg itself only needs to contain an index into
 | 
						|
   this vector instead of storing its values directly.
 | 
						|
 | 
						|
   The clang driver can dump the results of this stage using the
 | 
						|
   ``-ccc-print-options`` flag (which must precede any actual command
 | 
						|
   line arguments). For example:
 | 
						|
 | 
						|
   .. code-block:: console
 | 
						|
 | 
						|
      $ clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c
 | 
						|
      Option 0 - Name: "-Xarch_", Values: {"i386", "-fomit-frame-pointer"}
 | 
						|
      Option 1 - Name: "-Wa,", Values: {"-fast"}
 | 
						|
      Option 2 - Name: "-I", Values: {"foo"}
 | 
						|
      Option 3 - Name: "-I", Values: {"foo"}
 | 
						|
      Option 4 - Name: "<input>", Values: {"t.c"}
 | 
						|
 | 
						|
   After this stage is complete the command line should be broken down
 | 
						|
   into well defined option objects with their appropriate parameters.
 | 
						|
   Subsequent stages should rarely, if ever, need to do any string
 | 
						|
   processing.
 | 
						|
 | 
						|
#. **Pipeline: Compilation Job Construction**
 | 
						|
 | 
						|
   Once the arguments are parsed, the tree of subprocess jobs needed for
 | 
						|
   the desired compilation sequence are constructed. This involves
 | 
						|
   determining the input files and their types, what work is to be done
 | 
						|
   on them (preprocess, compile, assemble, link, etc.), and constructing
 | 
						|
   a list of Action instances for each task. The result is a list of one
 | 
						|
   or more top-level actions, each of which generally corresponds to a
 | 
						|
   single output (for example, an object or linked executable).
 | 
						|
 | 
						|
   The majority of Actions correspond to actual tasks, however there are
 | 
						|
   two special Actions. The first is InputAction, which simply serves to
 | 
						|
   adapt an input argument for use as an input to other Actions. The
 | 
						|
   second is BindArchAction, which conceptually alters the architecture
 | 
						|
   to be used for all of its input Actions.
 | 
						|
 | 
						|
   The clang driver can dump the results of this stage using the
 | 
						|
   ``-ccc-print-phases`` flag. For example:
 | 
						|
 | 
						|
   .. code-block:: console
 | 
						|
 | 
						|
      $ clang -ccc-print-phases -x c t.c -x assembler t.s
 | 
						|
      0: input, "t.c", c
 | 
						|
      1: preprocessor, {0}, cpp-output
 | 
						|
      2: compiler, {1}, assembler
 | 
						|
      3: assembler, {2}, object
 | 
						|
      4: input, "t.s", assembler
 | 
						|
      5: assembler, {4}, object
 | 
						|
      6: linker, {3, 5}, image
 | 
						|
 | 
						|
   Here the driver is constructing seven distinct actions, four to
 | 
						|
   compile the "t.c" input into an object file, two to assemble the
 | 
						|
   "t.s" input, and one to link them together.
 | 
						|
 | 
						|
   A rather different compilation pipeline is shown here; in this
 | 
						|
   example there are two top level actions to compile the input files
 | 
						|
   into two separate object files, where each object file is built using
 | 
						|
   ``lipo`` to merge results built for two separate architectures.
 | 
						|
 | 
						|
   .. code-block:: console
 | 
						|
 | 
						|
      $ clang -ccc-print-phases -c -arch i386 -arch x86_64 t0.c t1.c
 | 
						|
      0: input, "t0.c", c
 | 
						|
      1: preprocessor, {0}, cpp-output
 | 
						|
      2: compiler, {1}, assembler
 | 
						|
      3: assembler, {2}, object
 | 
						|
      4: bind-arch, "i386", {3}, object
 | 
						|
      5: bind-arch, "x86_64", {3}, object
 | 
						|
      6: lipo, {4, 5}, object
 | 
						|
      7: input, "t1.c", c
 | 
						|
      8: preprocessor, {7}, cpp-output
 | 
						|
      9: compiler, {8}, assembler
 | 
						|
      10: assembler, {9}, object
 | 
						|
      11: bind-arch, "i386", {10}, object
 | 
						|
      12: bind-arch, "x86_64", {10}, object
 | 
						|
      13: lipo, {11, 12}, object
 | 
						|
 | 
						|
   After this stage is complete the compilation process is divided into
 | 
						|
   a simple set of actions which need to be performed to produce
 | 
						|
   intermediate or final outputs (in some cases, like ``-fsyntax-only``,
 | 
						|
   there is no "real" final output). Phases are well known compilation
 | 
						|
   steps, such as "preprocess", "compile", "assemble", "link", etc.
 | 
						|
 | 
						|
#. **Bind: Tool & Filename Selection**
 | 
						|
 | 
						|
   This stage (in conjunction with the Translate stage) turns the tree
 | 
						|
   of Actions into a list of actual subprocess to run. Conceptually, the
 | 
						|
   driver performs a top down matching to assign Action(s) to Tools. The
 | 
						|
   ToolChain is responsible for selecting the tool to perform a
 | 
						|
   particular action; once selected the driver interacts with the tool
 | 
						|
   to see if it can match additional actions (for example, by having an
 | 
						|
   integrated preprocessor).
 | 
						|
 | 
						|
   Once Tools have been selected for all actions, the driver determines
 | 
						|
   how the tools should be connected (for example, using an inprocess
 | 
						|
   module, pipes, temporary files, or user provided filenames). If an
 | 
						|
   output file is required, the driver also computes the appropriate
 | 
						|
   file name (the suffix and file location depend on the input types and
 | 
						|
   options such as ``-save-temps``).
 | 
						|
 | 
						|
   The driver interacts with a ToolChain to perform the Tool bindings.
 | 
						|
   Each ToolChain contains information about all the tools needed for
 | 
						|
   compilation for a particular architecture, platform, and operating
 | 
						|
   system. A single driver invocation may query multiple ToolChains
 | 
						|
   during one compilation in order to interact with tools for separate
 | 
						|
   architectures.
 | 
						|
 | 
						|
   The results of this stage are not computed directly, but the driver
 | 
						|
   can print the results via the ``-ccc-print-bindings`` option. For
 | 
						|
   example:
 | 
						|
 | 
						|
   .. code-block:: console
 | 
						|
 | 
						|
      $ clang -ccc-print-bindings -arch i386 -arch ppc t0.c
 | 
						|
      # "i386-apple-darwin9" - "clang", inputs: ["t0.c"], output: "/tmp/cc-Sn4RKF.s"
 | 
						|
      # "i386-apple-darwin9" - "darwin::Assemble", inputs: ["/tmp/cc-Sn4RKF.s"], output: "/tmp/cc-gvSnbS.o"
 | 
						|
      # "i386-apple-darwin9" - "darwin::Link", inputs: ["/tmp/cc-gvSnbS.o"], output: "/tmp/cc-jgHQxi.out"
 | 
						|
      # "ppc-apple-darwin9" - "gcc::Compile", inputs: ["t0.c"], output: "/tmp/cc-Q0bTox.s"
 | 
						|
      # "ppc-apple-darwin9" - "gcc::Assemble", inputs: ["/tmp/cc-Q0bTox.s"], output: "/tmp/cc-WCdicw.o"
 | 
						|
      # "ppc-apple-darwin9" - "gcc::Link", inputs: ["/tmp/cc-WCdicw.o"], output: "/tmp/cc-HHBEBh.out"
 | 
						|
      # "i386-apple-darwin9" - "darwin::Lipo", inputs: ["/tmp/cc-jgHQxi.out", "/tmp/cc-HHBEBh.out"], output: "a.out"
 | 
						|
 | 
						|
   This shows the tool chain, tool, inputs and outputs which have been
 | 
						|
   bound for this compilation sequence. Here clang is being used to
 | 
						|
   compile t0.c on the i386 architecture and darwin specific versions of
 | 
						|
   the tools are being used to assemble and link the result, but generic
 | 
						|
   gcc versions of the tools are being used on PowerPC.
 | 
						|
 | 
						|
#. **Translate: Tool Specific Argument Translation**
 | 
						|
 | 
						|
   Once a Tool has been selected to perform a particular Action, the
 | 
						|
   Tool must construct concrete Jobs which will be executed during
 | 
						|
   compilation. The main work is in translating from the gcc style
 | 
						|
   command line options to whatever options the subprocess expects.
 | 
						|
 | 
						|
   Some tools, such as the assembler, only interact with a handful of
 | 
						|
   arguments and just determine the path of the executable to call and
 | 
						|
   pass on their input and output arguments. Others, like the compiler
 | 
						|
   or the linker, may translate a large number of arguments in addition.
 | 
						|
 | 
						|
   The ArgList class provides a number of simple helper methods to
 | 
						|
   assist with translating arguments; for example, to pass on only the
 | 
						|
   last of arguments corresponding to some option, or all arguments for
 | 
						|
   an option.
 | 
						|
 | 
						|
   The result of this stage is a list of Jobs (executable paths and
 | 
						|
   argument strings) to execute.
 | 
						|
 | 
						|
#. **Execute**
 | 
						|
 | 
						|
   Finally, the compilation pipeline is executed. This is mostly
 | 
						|
   straightforward, although there is some interaction with options like
 | 
						|
   ``-pipe``, ``-pass-exit-codes`` and ``-time``.
 | 
						|
 | 
						|
Additional Notes
 | 
						|
----------------
 | 
						|
 | 
						|
The Compilation Object
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
The driver constructs a Compilation object for each set of command line
 | 
						|
arguments. The Driver itself is intended to be invariant during
 | 
						|
construction of a Compilation; an IDE should be able to construct a
 | 
						|
single long lived driver instance to use for an entire build, for
 | 
						|
example.
 | 
						|
 | 
						|
The Compilation object holds information that is particular to each
 | 
						|
compilation sequence. For example, the list of used temporary files
 | 
						|
(which must be removed once compilation is finished) and result files
 | 
						|
(which should be removed if compilation fails).
 | 
						|
 | 
						|
Unified Parsing & Pipelining
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
Parsing and pipelining both occur without reference to a Compilation
 | 
						|
instance. This is by design; the driver expects that both of these
 | 
						|
phases are platform neutral, with a few very well defined exceptions
 | 
						|
such as whether the platform uses a driver driver.
 | 
						|
 | 
						|
ToolChain Argument Translation
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
In order to match gcc very closely, the clang driver currently allows
 | 
						|
tool chains to perform their own translation of the argument list (into
 | 
						|
a new ArgList data structure). Although this allows the clang driver to
 | 
						|
match gcc easily, it also makes the driver operation much harder to
 | 
						|
understand (since the Tools stop seeing some arguments the user
 | 
						|
provided, and see new ones instead).
 | 
						|
 | 
						|
For example, on Darwin ``-gfull`` gets translated into two separate
 | 
						|
arguments, ``-g`` and ``-fno-eliminate-unused-debug-symbols``. Trying to
 | 
						|
write Tool logic to do something with ``-gfull`` will not work, because
 | 
						|
Tool argument translation is done after the arguments have been
 | 
						|
translated.
 | 
						|
 | 
						|
A long term goal is to remove this tool chain specific translation, and
 | 
						|
instead force each tool to change its own logic to do the right thing on
 | 
						|
the untranslated original arguments.
 | 
						|
 | 
						|
Unused Argument Warnings
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
The driver operates by parsing all arguments but giving Tools the
 | 
						|
opportunity to choose which arguments to pass on. One downside of this
 | 
						|
infrastructure is that if the user misspells some option, or is confused
 | 
						|
about which options to use, some command line arguments the user really
 | 
						|
cared about may go unused. This problem is particularly important when
 | 
						|
using clang as a compiler, since the clang compiler does not support
 | 
						|
anywhere near all the options that gcc does, and we want to make sure
 | 
						|
users know which ones are being used.
 | 
						|
 | 
						|
To support this, the driver maintains a bit associated with each
 | 
						|
argument of whether it has been used (at all) during the compilation.
 | 
						|
This bit usually doesn't need to be set by hand, as the key ArgList
 | 
						|
accessors will set it automatically.
 | 
						|
 | 
						|
When a compilation is successful (there are no errors), the driver
 | 
						|
checks the bit and emits an "unused argument" warning for any arguments
 | 
						|
which were never accessed. This is conservative (the argument may not
 | 
						|
have been used to do what the user wanted) but still catches the most
 | 
						|
obvious cases.
 | 
						|
 | 
						|
Relation to GCC Driver Concepts
 | 
						|
-------------------------------
 | 
						|
 | 
						|
For those familiar with the gcc driver, this section provides a brief
 | 
						|
overview of how things from the gcc driver map to the clang driver.
 | 
						|
 | 
						|
-  **Driver Driver**
 | 
						|
 | 
						|
   The driver driver is fully integrated into the clang driver. The
 | 
						|
   driver simply constructs additional Actions to bind the architecture
 | 
						|
   during the *Pipeline* phase. The tool chain specific argument
 | 
						|
   translation is responsible for handling ``-Xarch_``.
 | 
						|
 | 
						|
   The one caveat is that this approach requires ``-Xarch_`` not be used
 | 
						|
   to alter the compilation itself (for example, one cannot provide
 | 
						|
   ``-S`` as an ``-Xarch_`` argument). The driver attempts to reject
 | 
						|
   such invocations, and overall there isn't a good reason to abuse
 | 
						|
   ``-Xarch_`` to that end in practice.
 | 
						|
 | 
						|
   The upside is that the clang driver is more efficient and does little
 | 
						|
   extra work to support universal builds. It also provides better error
 | 
						|
   reporting and UI consistency.
 | 
						|
 | 
						|
-  **Specs**
 | 
						|
 | 
						|
   The clang driver has no direct correspondent for "specs". The
 | 
						|
   majority of the functionality that is embedded in specs is in the
 | 
						|
   Tool specific argument translation routines. The parts of specs which
 | 
						|
   control the compilation pipeline are generally part of the *Pipeline*
 | 
						|
   stage.
 | 
						|
 | 
						|
-  **Toolchains**
 | 
						|
 | 
						|
   The gcc driver has no direct understanding of tool chains. Each gcc
 | 
						|
   binary roughly corresponds to the information which is embedded
 | 
						|
   inside a single ToolChain.
 | 
						|
 | 
						|
   The clang driver is intended to be portable and support complex
 | 
						|
   compilation environments. All platform and tool chain specific code
 | 
						|
   should be protected behind either abstract or well defined interfaces
 | 
						|
   (such as whether the platform supports use as a driver driver).
 |