Overview of GN toolchains
The GN build tool allows one build to compile the same target in different ways, using multiple toolchains.
Each toolchain()
instance corresponds to:
A unique name, expressed as a GN label.
For example '//build/toolchain/fuchsia:x64' names the toolchain instance defined in the
//build/toolchain/fuchsia/BUILD.gn
file, with atoolchain("x64")
definition.A set of commands and build flags used to compile the source code and link binaries.
For example, using one toolchain to invoke Clang, and another one to invoke Microsoft Visual C++, allows a single build to generate binaries using both compiler suites.
A build graph node namespace.
Separating targets with the same GN path, but compiled with different toolchain instances. This is reflected in the format of fully-qualified GN labels, that look like
"//<dir>:<target>(<toolchain_dir>:<toolchain_target>)"
.For example
//src/foo:bar(//toolchain:debug)
corresponds to thebar
target defined in//src/foo/BUILD.gn
, when it is compiled with the commands of the//toolchain:debug
toolchain.A separate GN execution context.
Each toolchain instance executes its own parse of the GN buildconfig file, which sets up global variables and default values for all rules defining targets in that toolchain.
In practice, if the same target is built with two different toolchains, the corresponding
BUILD.gn
file will be parsed twice, but each time with a different set of global variables, default configs and custom templates defined inBUILDCONFIG.gn
.A separate root directory for target outputs.
While the targets built in the default toolchain are placed under
root_build_dir
, the ones that are built with a//<toolchain_dir>:<toolchain_name>
instance are placed under${root_build_dir}/<toolchain_name>
instead.This location is available at GN gen time through the
root_out_dir
variable.
There is always at least one toolchain, called the default toolchain, which
is determined by calling
set_default_toolchain()
from the buildconfig file.
For more information read the toolchain()
reference documentation.
How the Fuchsia build uses GN toolchains
The Fuchsia build uses GN toolchains in several ways:
To build host and device executables.
The build currently defines
//build/toolchain/fuchsia:x64
and//build/toolchain/fuchsia:arm64
to build Fuchsia executable binaries for the 64-bit Intel and ARM architectures.It also defines
//build/toolchain:host_x64
to build code for the host machine (i.e. the one where the build happens).It also defines
//build/toolchain:linux_x64
and//build/toolchain:linux_arm64
to generate Linux 64-bit code as well, even if the host is not running one of these architectures.There are also a number of specialized toolchains used to compile bootloaders and parts of the kernel, described later.
To build ELF shared libraries.
On Fuchsia, machine code that goes into shared objects (i.e.
shared_library()
andloadable_module()
instances in GN speak) must be built with the-fPIC
compiler and linker option.This is unlike executable code, that uses
-fPIE
instead.To deal with this, separate toolchain instances are defined to compile code for shared librarie.
See ELF Shared Library Redirection for more details.
To build different variants (e.g. instrumented or optimized) of binaries.
The Fuchsia build supports a number of "build variants" which allow building machine code in a slightly different way, for example:
The
asan
andubsan
variants are used to build machine code with Clang's Address Sanitizer, and Undefined Behaviour Sanitizer, respectively. There is even anasan-ubsan
variant that combines both.The
coverage
variant is used to build machine code with Clang's instrumentation-based profiling enabled, to support code coverage collection.The
profile
variant is used to build instrumented code as well, but to support profile-guided optimization.The
thinlto
andlto
variants are used to build binaries with link-time optimization enabled.The
gcc
variant is used to build certain pieces of the Zircon kernel with the GCC compiler instead of Clang (which has been useful to weed out subtle machine code generation issues that can affect the kernel in very important ways).
There are many other variants defined in the build's
BUILDCONFIG.gn
file as well.To generate (or process) source files.
The build requires generating source files to be used in other targets in many places. For example, FIDL protocol definition files are processed to generate bindings for various languages (C++, Rust, Go and Dart), which are later used by other
source_set()
, or similar, targets.Because the targets that use these sources can be defined in different toolchain instances, it is useful to ensure that this generation is only performed once, instead of once per toolchain instance, since the output will be exactly the same in all cases.
The Fuchsia build thus defines the
fidling
toolchain to perform FIDL bindings generation. Note that this toolchain is only used to run a few scripts usingaction()
targets, never to actually compile them.Similarly, a number of other "basic" toolchains are defined in the build to perform processing tasks that should not be repeated needlessly.
How the Fuchsia build defines toolchain()
instances.
The Fuchsia build provides these templates that define toolchain()
instances
with various features:
basic_toolchain()
defines a "basic" toolchain, i.e. one that does onlycopy()
oraction()
target, and never needs to use GN's builtin support for C++ and Rust compilation.These are used to generate outputs that are used by other targets in several other toolchains (e.g. language bindings) to avoid duplicate work.
Note that one basic toolchain is used to build Go binaries, and another one for Dart ones, since GN doesn't support these languages at all.
clang_toolchain()
defines a toolchain instances that invokes the Clang compiler. It provides support for building C++ and Rust sources using GN's builtin rules.Supported target platforms are Fuchsia, Linux, Win32 PE/COFF (as required by the UEFI bootloader) and even WebAssembly!
clang_toolchain_suite()
defines one more toolchain instances based on the current build variant configuration. It is preferred over callingclang_toolchain()
directly because this is what allows build variants to work.clang_host_toolchain_suite()
is used for toolchains that generate host machine code.zircon_toolchain()
defines a toolchain instances that can be used to build part of the Zircon kernel, bootloaders or even the C library. These binaries typically require non-standard compile and linker commands (e.g. a different ABI, or lack of standard link environment).NOTE: Toolchains created by `zircon_toolchain() do not support the Rust programming language.
One notable feature of this template is that it also supports building binaries using the GCC compiler, instead of Clang. This has proven useful to find low-level code generation issues that the kernel is very sensitive about, by its nature.
NOTE: There is no plan to support building the rest of the platform with GCC.
zircon_toolchain_suite()
is used to define one or more toolchain instances based on the current build variant configuration. It is preferred over callingzircon_toolchain()
directly.
Note that the distinction between zircon_toolchain()
and
clang_toolchain()
is mostly historical, they might be merged into
a common template in the future.