The GN build tool allows one build to compile the same target in different ways, using multiple toolchains{:.external}.
Each toolchain()
instance corresponds to:
A unique name, expressed as a GN label{:.external}.
For example ‘//build/toolchain/fuchsia:x64’ names the toolchain instance defined in the //build/toolchain/fuchsia/BUILD.gn
file, with a toolchain("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 the bar
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{:.external}, 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 in BUILDCONFIG.gn
.
A separate root directory for target outputs.
While the targets built in the default toolchain are placed under root_build_dir
{:.external}, 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
{:.external} variable.
There is always at least one toolchain, called the default toolchain, which is determined by calling set_default_toolchain()
{:.external} from the buildconfig file{:.external}.
For more information read the toolchain()
{:.external} reference documentation.
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()
and loadable_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
and ubsan
variants are used to build machine code with Clang's Address Sanitizer, and Undefined Behaviour Sanitizer, respectively. There is even an asan-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
and lto
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 using action()
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.
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 only copy()
or action()
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, MacOS, 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 calling clang_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).
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 calling zircon_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.