blob: 6a592152ccf505dcd47dac8dd88e1191c632cb60 [file] [log] [blame]
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("$zx/public/gn/config/standard.gni")
import("c_toolchain.gni")
declare_args() {
# List of "selectors" to request variant builds of certain targets. Each
# selector specifies matching criteria and a chosen variant. The first
# selector in the list to match a given target determines which variant is
# used for that target.
#
# The $default_variants list is appended to the list set here. So if no
# selector set in $variants matches (e.g. if the list is empty, as is the
# default), then the first match in $default_variants chooses the variant.
#
# Each selector is either a string or a scope. A selector that's a string
# is a shorthand that gets expanded to a full selector (a scope); the full
# selector form is described below.
#
# If a string selector contains a slash, then it's "shorthand/filename".
# This is like the plain "shorthand" selector, but further constrained to
# apply only to a binary whose `output_name` exactly matches "filename".
#
# The "shorthand" string (a whole string selector or the part before slash)
# is first looked up in $variant_shorthands, which see. If it doesn't match
# a name defined there, then it must be the name of a variant. In that case,
# it's equivalent to `{ variant = "..." host = false }`, meaning it applies
# to every binary not built to be a host tool.
#
# A full selector is a scope with the following fields. All the fields
# other than `.variant` are matching criteria. A selector matches if all of
# its matching criteria match. Hence, a selector with no criteria defined
# always matches and is referred to as a "catch-all". The $default_variants
# list ends with a catch-all, so each target always chooses some variant.
#
# Selector scope parameters
#
# * variant
# - Required: The variant to use when this selector matches. If this is a
# string then it must match a fully-defined variant elsewhere in the
# list (or in $default_variants + $standard_variants, which is appended
# implicitly to the $variants list). If it's a scope then it defines a
# new variant (see details below).
# - Type: string or scope, described below
#
# * cpu
# - Optional: If nonempty, match only when $current_cpu is one in the list.
# - Type: list(string)
#
# * os
# - Optional: If nonempty, match only when $current_os is one in the list.
# - Type: list(string)
#
# * host
# - Optional: If present, match only in host environments if true or
# non-host environments if false. This means a context in which
# $is_host is true, not specifically the build host. For example, it
# would be true when cross-compiling host tools for an SDK build but
# would be false when compiling code for a hypervisor guest system
# that happens to be the same CPU and OS as the build host.
# - Type: bool
#
# * kernel
# - Optional: If present, match only in kernel environments if true or
# non-kernel environments if false. This means a context in which
# $is_kernel is true, not just the "kernel" environment itself.
# For different machine architectures there may be multiple different
# specialized environments that set $is_kernel, e.g. for boot loaders
# and for special circumstances used within the kernel. See also the
# $tags field in $variant, described below.
# - Type: bool
#
# * environment
# - Optional: If nonempty, a list of environment names that match. This
# looks at ${toolchain.environment}, which is the simple name (no
# directories) in an environment label defined by environment(). Each
# element can match either the whole environment name, or just the
# "base" environment, which is the part of the name before a `.` if it
# has one. For example, "host" would match both "host" and "host.fuzz".
# - Type: list(string)
#
# * target_type
# - Optional: If nonempty, a list of target types to match. This is one of
# "executable", "host_tool", "loadable_module", "driver", or "test".
# Note, test_driver() matches as "driver".
# - Type: list(string)
#
# * label
# - Optional: If nonempty, match only when the canonicalized target label
# (as returned by `get_label_info(..., "label_no_toolchain")`) is one in
# the list.
# - Type: list(label_no_toolchain)
#
# * dir
# - Optional: If nonempty, match only when the directory part of the
# target label (as returned by `get_label_info(..., "dir")`) is one in
# the list.
# - Type: list(label_no_toolchain)
#
# * name
# - Optional: If nonempty, match only when the name part of the target
# label (as returned by `get_label_info(..., "name")`) is one in the
# list.
# - Type: list(label_no_toolchain)
#
# * output_name
# - Optional: If nonempty, match only when the `output_name` of the target
# is one in the list. Note `output_name` defaults to `target_name`,
# and does not include prefixes or suffixes like ".so" or ".exe".
# - Type: list(string)
#
# An element with a scope for `.variant` defines a new variant. Each
# variant name used in a selector must be defined exactly once. Other
# selectors can refer to the same variant by using the name string in the
# `.variant` field. Definitions in $variants take precedence over the same
# name defined in $standard_variants, but it would probably cause confusion
# to use the name of a standard variant with a non-standard definition.
#
# Variant scope parameters
#
# * name
# - Required: Name for the variant. This must be unique among all
# variants used with the same environment. It becomes part of the GN
# toolchain names defined for the environment, which in turn forms part
# of directory names used in $root_build_dir; so it must meet Ninja's
# constraints on file names (sticking to `[a-z0-9_-]` is a good idea).
#
# * globals
# - Optional: Variables in this scope are introduced as globals visible
# to all GN code in the toolchain. For example, the standard "gcc"
# variant sets `is_gcc = true` in $globals. This should be used
# sparingly and is safest when restricted to variables that
# $zx/public/gn/BUILDCONFIG.gn sets defaults for.
# - Type: scope
#
# * toolchain_args
# - Optional: See toolchain(). Variables in this scope must match GN
# build arguments defined somewhere in the build with declare_args().
# Use this when the variant should change something that otherwise is a
# manual tuning variable to set via `gn args`. *Do not* define
# variables in declare_args() just for the purpose of setting them here,
# i.e. if they should not *also* be available to set via `gn args` to
# affect other variants that don't override them here. Instead, use
# either $globals (above) or $toolchain_vars (below).
# - Type: scope
#
# * toolchain_vars
# - Optional: Variables in this scope are visible in the scope-typed
# $toolchain global variable seen in toolchains for this variant.
# Use this to pass along interesting information without cluttering
# the global scope via $globals.
# - Type: scope
#
# * configs
# - Optional: List of changes to the pre-set $configs variable in targets
# being defined in toolchains for this variant. This is the same as in
# the $configs parameter to environment(). Each element is either a
# string or a scope. A string element is simply appended to the default
# $configs list: it's equivalent to a scope element of `{add=["..."]}`.
# The string is the GN label (without toolchain) for a config() target.
# A scope element can be more selective, as described below.
# - Type: list(label_no_toolchain or scope)
# * shlib
# - Optional: If present, this element applies only when
# `current_toolchain == toolchain.shlib` (if true) or
# `current_toolchain != toolchain.shlib` (if false). That is, it
# applies only in (not ni) the companion toolchain used to compile
# shared_library() and loadable_module() (including driver()) code.
# - Type: bool
#
# * types
# - Optional: If present, this element applies only to a target whose
# type is one in this list (same as `target_type` in a selector,
# described above).
# - Type: list(string)
#
# * add
# - Optional: List of labels to append to $configs.
# - Type: list(label_no_toolchain)
#
# * remove
# - Optional: List of labels to remove from $configs. This does
# exactly `configs -= remove` so it has the normal GN semantics that
# it's an error if any element in the $remove list is not present in
# the $configs list beforehand.
# - Type: list(label_no_toolchain)
#
# * implicit_deps
# - Optional: List of changes to the list added to $deps of all linking
# targets in toolchains for this variant. This is the same as in the
# $implicit_deps parameter to environment().
# - Type: See $configs
#
# * tags
# - Optional: List of tags that describe this variant. This list will be
# visible within the variant's toolchains as ${toolchain.tags}. Its main
# purpose is to match the $exclude_variant_tags list in an environment()
# definition. For example, several of the standard variants listed in
# $standard_variants use the "useronly" tag. The environment() defining
# the kernel toolchains uses `exclude_variant_tags = [ "useronly" ]`.
# Then $variants selectors that choose variants that are incompatible
# with the kernel are automatically ignored in the kernel toolchains,
# so there's no need to add `kernel = false` to every such selector.
# - Type: list(string)
#
# * bases
# - Optional: A list of other variant names that this one inherits from.
# This is a very primitive mechanism for deriving a new variant from an
# existing variant. All of fields from all the bases except for `name`
# and `bases` are combined with the fields defined explicitly for the
# new variant. The fields of list type are just concatenated in order
# (each $bases variant in the order listed, then this variant). The
# fields of scope type are merged in the same order, with a variant
# later in the list overriding values set earlier (so this variant's
# values override all the bases). There is *only one* level of
# inheritance: a base variant listed in $bases cannot have $bases itself.
# - Type: list(string)
#
variants = []
}
# Define toolchains for a compilation environment.
#
# A compilation environment is the combination of a particular CPU, OS, and
# "execution environment". The $target_name in environment() is the
# name of the execution environment, which identifies the circumstances in
# which code built with these toolchains runs. Examples are:
# * `host` for programs run during the build or by developers in an SDK
# * `kernel` for the Zircon kernel
# * `user` for user-mode programs running on top of Zircon/Fuchsia
# Additional environments are defined for more specialized purposes.
#
# The expansion of ":$target_name" is the ${toolchain.environment_label}
# value seen in these toolchains. This is what must be suppled in
# environment_redirect()'s `environment_label` parameter. The toolchains
# that make up the environment have labels that begin with this prefix
# and then append "-${variant}" or "-${variant}.shlib".
#
# Parameters
#
# * cpu
# - Required: $current_cpu value in the new toolchains.
# - Type: string
#
# * os
# - Optional: $current_os value in the new toolchains.
# - Type: string
# - Default: "fuchsia"
#
# * shlib
# - Optional: If this environment will supported shared_library() and
# loadable_module() targets via `.shlib` companion toolchains.
# - Type: bool
# - Default: false
#
# * solink
# - Optional: If this environment will be used *only* for shared_library()
# and/or loadable_module() targets. Mutually exclusive with $shlib.
# - Type: bool
# - Default: false
#
# * configs
# - Preset: $standard_configs
# - Required: List of config() labels or scopes.
# These are the default $configs preset in all compiling targets.
# Elements are the same as $configs in a $variant scope in $variants.
# Each element is usually a label (string), which means it's
# in the preset $configs for all target scopes. It can instead
# be a scope that defines:
# * shlib
# - Optional: Boolean. If defined, this element only takes effect
# in the ${toolchain.shlib} toolchain (if true) or in the non-shlib
# toolchain if false.
# * types
# - Optional: List of strings, e.g. ["driver", "source_set"].
# This element only takes effect for targets of these types.
# * add, remove
# - Optional: List of labels, usually config() targets.
# The preset $configs gets `+=` and then `-=` these, respectively.
#
# * implicit_deps
# - Optional: List of labels or scopes. This controls the list forcibly
# added to the $deps list of every linking target built in this
# environment. Elements are the same as $implicit_deps in a @variant
# scope in $variants.
# - Type: list(label)
# - Default: []
#
# * globals
# - Optional: A scope imported into the global scope in these toolchains.
# This is the place to define `is_...` variables.
#
# * toolchain_args
# - Optional: A scope of build argument overrides for these toolchains.
# This is just like $toolchain_args passed to toolchain() in bare GN.
#
# * toolchain_vars
# - Optional: A scope imported into the $toolchain scope in these toolchains.
# This can store useful toolchain-specific variables that should be
# available within the toolchain. $toolchain automatically contains
# `tool_dir`, `tool_prefix`, `cc, and `cxx`, from c_toolchain().
# If `variant_suffix` is defined here, terminal targets in the environment
# will have "$target_name$variant_suffix" aliases that get the same thing
# but in that particular variant installed under the suffixed name.
# The default `variant_suffix` is ".$variant" in each variant.
#
# * variant_selectors
# - Optional: A list in the schema of the $variants build argument. This
# controls which variant is used to build each individual target. Just
# having a selector with `.variant = "..."` makes the "..." variant
# toolchain exist in this environment, even if the selector doesn't
# match anything. Each `variant` scope can have its own $configs,
# $implicit_deps, $globals, $toolchain_args, and $toolchain_vars that
# are merged with the environment's (potentially overriding their
# individual elements). Note: environment_redirect() with
# `environment_label` set to this environment may not work if this does
# not include $default_variants. Default: $variants +
# $default_variants + $standard_variants
#
# * exclude_variant_tags
# - Optional: A list of strings that might appear in the .tags list of a
# .variant scope. If any of these strings appears in a .variant scope,
# then $variant_selectors elements using that variant will be silently
# ignored in this environment's toolchains. e.g. an environment that is
# incompatbile with instrumentation could list the "instrumentation" tag
# and variants that enable instrumentation will be defined with that tag.
# Then simple `variants=["asan"]` user configurations that would apply
# ordinarily to all targets don't break the special-case execution
# environments (vdso, bootloader, etc).
#
template("environment") {
assert(current_toolchain == default_toolchain,
"environment() should only be used in $default_toolchain")
# These are seen by c_toolchain(), below.
environment = target_name
environment_label = get_label_info(":$target_name", "label_no_toolchain")
# For "host.fuzz", the base is "host".
base_environment = get_path_info(environment, "name")
# Name construction logic must match environment_redirect.gni.
toolchain_base_name = "${environment}-${invoker.cpu}"
# For host environments include the OS to distinguish one from another.
# For other environments, the OS is implicit (i.e. "fuchsia" modulo EFI).
if (base_environment == "host") {
toolchain_base_name += "-${invoker.os}"
}
# These will be seen by c_toolchain() below.
shlib = defined(invoker.shlib) && invoker.shlib
# The canonicalized list of selectors. Each element is in the schema of
# $variant elements, but canonicalized to simplify the matching code: all
# fields are present (defaults of []); .variant is always a simple string
# (of those in $_variant_names, below).
variant_selectors = []
# The environment can have its own list of selectors.
# Most environments use the globally-configured $variants list.
if (defined(invoker.variant_selectors)) {
raw_selectors = invoker.variant_selectors
} else {
raw_selectors = variants + default_variants + standard_variants
}
# First expand the plain-string shorthand selectors to full scopes.
selectors = []
foreach(selector, raw_selectors) {
if (selector == "$selector") {
# A string selector is a shorthand.
# First check for a simple shorthand from the global list.
foreach(shorthand, variant_shorthands) {
if (selector == shorthand.name) {
selectors += shorthand.selectors
selector = false
}
}
}
if (selector == "$selector") {
selector = {
host = false
if (selector == get_path_info(selector, "file")) {
# No slash in the name. Just a trivial non-host catch-all.
variant = selector
} else {
# "$variant/$output_name"
variant = get_path_info(selector, "dir")
output_name = [ get_path_info(selector, "file") ]
}
}
}
if (selector != false) {
selectors += [ selector ]
}
}
# Needed below because a.b.c doesn't work in GN.
g = {
}
if (defined(invoker.globals)) {
g = invoker.globals
}
# This pass canonicalizes the selectors and collects the variant specs.
defined_variant_names = []
variant_names = []
variant_specs = []
foreach(selector, selectors) {
assert(defined(selector.variant),
"`variants` selector missing `.variant`: $selector")
foreach(variant, [ selector.variant ]) {
if (variant != false && variant != "$variant") {
# This selector is defining a variant. Record the variant spec and
# name and then update the selector to use just the name.
assert(defined(variant.name),
"`variants` element .variant scope missing .name: $selector")
assert(
defined_variant_names + [ variant.name ] - [ variant.name ] ==
defined_variant_names,
"`variants` element overrides variant ${variant.name}: $selector")
defined_variant_names += [ variant.name ]
variant_names += [ variant.name ]
variant_specs += [ variant ]
sel_variant = variant.name
} else {
sel_variant = variant
# Add this to the list of needed variants if it's not there already.
variant_names += [ variant ]
variant_names -= [ variant ]
variant_names += [ variant ]
}
}
sel = {
# Clear from previous iteration.
}
sel = {
# Set defaults for all the list fields and then clobber a subset of
# those with whatever the selector actually included. The boolean
# fields are not defaulted this way because for them neither false
# nor true means the same thing as the field being omitted.
cpu = []
dir = []
environment = []
label = []
name = []
os = []
output_name = []
target_type = []
forward_variables_from(selector,
"*",
[
"toolchain",
"variant",
])
}
# If the selector filters on environment, then don't bother including
# it if it will never match in the environment we're defining.
if (sel.environment != [] && (sel.environment + [ environment ] -
[ environment ] == sel.environment ||
sel.environment + [ base_environment ] -
[ base_environment ] == sel.environment)) {
sel = {
}
}
# Same for standard shorthands.
if ((defined(sel.host) && sel.host != (defined(g.is_host) && g.is_host)) ||
(defined(sel.kernel) &&
sel.kernel != (defined(g.is_kernel) && g.is_kernel))) {
sel = {
}
}
if (sel != {
}) {
sel.variant = sel_variant
# When the selector matches, redirect to this toolchain.
sel.toolchain = get_label_info(":${toolchain_base_name}-${sel_variant}",
"label_no_toolchain")
if (shlib) {
sel.shlib_toolchain = "${sel.toolchain}.shlib"
}
variant_selectors += [ sel ]
}
}
# variant_names now lists all the variants that might be needed in this
# environment. toolchain_variants will collect all the canonicalized
# variant specs that control which toolchains actually get defined below.
toolchain_variants = []
# In the first pass, each variant spec is canonicalized, and then
# appended to toolchain_variants if it's complete. An incomplete variant
# has a nonempty .bases list that will be resolved in the second pass;
# these are appended to incomplete_variants instead.
incomplete_variants = []
foreach(raw_spec, variant_specs) {
spec = {
# Clear from previous iteration.
}
spec = {
bases = []
configs = []
implicit_deps = []
tags = []
globals = {
}
toolchain_args = {
}
toolchain_vars = {
}
forward_variables_from(raw_spec, "*")
}
if (spec.bases == []) {
toolchain_variants += [ spec ]
} else {
incomplete_variants += [ spec ]
variant_names += spec.bases
}
}
# In the final pass, the incomplete variants are expanded with
# reference to the complete variants.
foreach(incomplete, incomplete_variants) {
bases = [] # Clear from previous iteration.
foreach(base, incomplete.bases) {
assert(base == "$base",
".variant.base elements must be strings: $incomplete")
assert(toolchain_variants + [ base ] - [ base ] == toolchain_variants,
".variant.base elements must be complete themselves: $incomplete")
foreach(complete, toolchain_variants) {
if (base == complete.name) {
bases += [ complete ]
}
}
}
bases += [ incomplete ]
toolchain_variants += [
{
name = incomplete.name
# Append each list from all the bases.
configs = []
implicit_deps = []
tags = []
foreach(base, bases) {
configs += base.configs
implicit_deps += base.implicit_deps
tags += base.tags
tags -= base.tags
tags += base.tags
}
# Merge each scope from all the bases.
globals = {
foreach(base, bases) {
forward_variables_from(base.globals, "*")
}
}
toolchain_args = {
foreach(base, bases) {
forward_variables_from(base.toolchain_args, "*")
}
}
toolchain_vars = {
foreach(base, bases) {
forward_variables_from(base.toolchain_vars, "*")
}
}
},
]
}
# Now we have toolchain_variants and variant_selectors in canonical form.
# See if there are any we should cull from the list.
exclude_variant_tags = []
if (defined(invoker.exclude_variant_tags)) {
exclude_variant_tags += invoker.exclude_variant_tags
}
if (defined(g.is_kernel) && g.is_kernel) {
exclude_variant_tags += [ "useronly" ]
} else {
exclude_variant_tags += [ "kernel" ]
}
if (exclude_variant_tags != []) {
# Weed out the variants that this environment silently excludes.
excluded_variants = []
foreach(variant, toolchain_variants) {
if (exclude_variant_tags + variant.tags - variant.tags !=
exclude_variant_tags) {
excluded_variants += [ variant.name ]
toolchain_variants -= [ variant ]
}
}
if (excluded_variants != []) {
# Weed out the selectors that would choose an excluded variant.
excluded_selectors = []
foreach(selector, variant_selectors) {
if (excluded_variants + [ selector.variant ] - [ selector.variant ] !=
excluded_variants) {
excluded_selectors += [ selector ]
excluded_selectors -= [ selector ]
excluded_selectors += [ selector ]
}
}
variant_selectors -= excluded_selectors
}
}
if (excluded_variants != []) {
# Now excluded_variants lists toolchain names we know we never actually
# want to compile anything in. However, environment_redirect() has to
# pick a default to redirect through even though it has no way to see
# exclude_variant_tags or the other factors that make this environment
# actually exclude a variant. So, the first likely-looking one in
# variants + default_variants has to exist so it can redirect to the
# right one. When the one it would choose is in excluded_variants, we
# need to make that toolchain exist as a dummy for those redirects.
redirect_default = ""
# This must be kept in synch with the loop in environment_redirect().
foreach(default, variants + default_variants) {
if (redirect_default == "") {
if (default == "$default") {
foreach(shorthand, variant_shorthands) {
if (default != "" &&
(default == shorthand.name ||
get_path_info(default, "dir") == shorthand.name)) {
default = ""
}
}
if (default != "") {
default = {
variant = default
}
}
}
if (default != "" &&
(!defined(default.environment) || default.environment == [] ||
default.environment + [ environment ] - [ environment ] !=
default.environment ||
default.environment + [ base_environment ] -
[ base_environment ] != default.environment)) {
redirect_default = default.variant
}
}
}
if (redirect_default != "" && excluded_variants + [ redirect_default ] -
[ redirect_default ] == excluded_variants) {
# It's not excluded, so we don't have to do anything.
redirect_default = ""
}
if (redirect_default != "") {
# Define an additional toolchain under the expected name. It may wind
# up instantiating a lot of targets, which is unfortunate since its
# only purpose is to resolve redirect group() targets. But to make
# sure nothing goes awry because the code evaluated is confused by
# wrong toolchain definitions, make it a copy in all by name of a
# variant where we actually do expect to instantiate and build targets.
toolchain_variants += [
{
forward_variables_from(toolchain_variants[0], "*", [ "name" ])
name = redirect_default
},
]
}
}
# Reuse the selectors local so we can shadow variant_selectors below.
# Also annotate each selector with its variant's tags for the
# $exclude_variant_tags parameter to _variant_target() to match against.
selectors = []
foreach(selector, variant_selectors) {
selectors += [
{
forward_variables_from(selector, "*")
foreach(variant, toolchain_variants) {
if (variant.name == selector.variant) {
tags = variant.tags
}
}
},
]
}
variant_selectors = []
# Define a primary toolchain, and possibly also a shlib toolchain, for each
# variant. If there are two, both toolchains get a ${toolchain.shlib} value
# pointing to the shlib toolchain. Any ${toolchain.configs} elements that
# use `.shlib = true` will affect the preset configs in ${toolchain.shlib}
# differently and then both shared_library() and loadable_module() in the
# primary toolchain redirect to the shlib toolchain.
foreach(variant, toolchain_variants) {
toolchains = [] # Clear from previous iteration.
tc_name = "${toolchain_base_name}-${variant.name}"
toolchains = [
{
name = tc_name
if (shlib) {
shlib_name = "${name}.shlib"
}
},
]
if (shlib) {
toolchains += [
{
name = "${tc_name}.shlib"
shlib_name = name
},
]
}
foreach(tc, toolchains) {
# Canonicalize the ${toolchain.configs} list.
#
# This is used by $zx/public/gn/BUILDCONFIG.gn for set_defaults().
# The labels must be absolute since they will be used all over in
# the new toolchain, not just where the environment() is.
#
tc_configs = []
foreach(config, invoker.configs + variant.configs) {
if (config == "$config") {
tc_configs += [ get_label_info(config, "label_no_toolchain") ]
} else {
# It's actually a scope. Check if its shlib constraint matches.
# Testing the inverted expression against !config.shlib
# constitutes an assert that config.shlib is a proper Boolean.
if (!defined(config.shlib) ||
!config.shlib ==
!(defined(tc.shlib_name) && tc.name == tc.shlib_name)) {
# Expand its add and remove lists.
tc_configs += [
{
forward_variables_from(config, [ "types" ])
add = []
if (defined(config.add)) {
foreach(label, config.add) {
add += [ get_label_info(label, "label_no_toolchain") ]
}
}
remove = []
if (defined(config.remove)) {
foreach(label, config.remove) {
remove += [ get_label_info(label, "label_no_toolchain") ]
}
}
assert(add != [] || remove != [], "useless $config")
},
]
}
}
}
# Likewise for the ${toolchain.implicit_deps} list. This is used by
# the various linking target types, where it's forcibly appended to
# $deps rather than pre-set via set_defaults() as $configs is.
raw_implicit_deps = []
if (defined(invoker.implicit_deps)) {
raw_implicit_deps += invoker.implicit_deps
}
raw_implicit_deps += variant.implicit_deps
tc_implicit_deps = []
foreach(dep, raw_implicit_deps) {
if (dep == "$dep") {
tc_implicit_deps += [ get_label_info(dep, "label_no_toolchain") ]
} else if (!defined(dep.shlib) || !dep.shlib ||
(defined(tc.shlib_name) && tc.name == tc.shlib_name)) {
# It's actually a scope.
# Expand its add and remove lists.
tc_implicit_deps += [
{
forward_variables_from(dep, [ "types" ])
add = []
if (defined(dep.add)) {
foreach(label, dep.add) {
add += [ get_label_info(label, "label_no_toolchain") ]
}
}
remove = []
if (defined(dep.remove)) {
foreach(label, dep.remove) {
remove += [ get_label_info(label, "label_no_toolchain") ]
}
}
assert(add != [] || remove != [], "useless $dep")
},
]
}
}
# Merge the $globals scopes from the invoker and the variant.
tc_globals = {
}
tc_globals = {
forward_variables_from(g, "*")
if (defined(variant.globals)) {
forward_variables_from(variant.globals, "*")
}
}
c_toolchain(tc.name) {
cpu = invoker.cpu
if (defined(invoker.os)) {
os = invoker.os
} else {
os = "fuchsia"
}
shlib = shlib || (defined(invoker.solink) && invoker.solink)
toolchain_args = {
if (defined(invoker.toolchain_args)) {
forward_variables_from(invoker.toolchain_args,
"*",
[
"current_cpu",
"current_os",
"toolchain",
])
}
if (defined(variant.toolchain_args)) {
forward_variables_from(variant.toolchain_args,
"*",
[
"current_cpu",
"current_os",
"toolchain",
])
}
}
toolchain_vars = {
# ${toolchain.environment} and ${toolchain.environment_label}
# will identify the environment within its own toolchains.
base_environment = base_environment
environment = environment
environment_label = environment_label
if (defined(tc.shlib_name)) {
shlib = get_label_info(":${tc.shlib_name}", "label_no_toolchain")
# Override the .label set by c_toolchain(), so it refers
# to the base toolchain, not the shlib toolchain.
label = get_label_info(":$tc_name", "label_no_toolchain")
}
configs = tc_configs
implicit_deps = tc_implicit_deps
globals = tc_globals
# Both the invoker and the variant can supply a $toolchain_vars
# scope for whatever they want to see in $toolchain, but they
# cannot set the things we set directly.
if (defined(invoker.toolchain_vars)) {
forward_variables_from(invoker.toolchain_vars,
"*",
[
"configs",
"base_environment",
"environment",
"environment_label",
"globals",
"implicit_deps",
"label",
"shlib",
"strip",
"variant",
"variant_selectors",
])
}
if (defined(variant.toolchain_vars)) {
forward_variables_from(variant.toolchain_vars,
"*",
[
"configs",
"base_environment",
"environment",
"environment_label",
"globals",
"implicit_deps",
"label",
"shlib",
"strip",
"variant",
"variant_selectors",
])
}
# Plumb through the canonicalized $variants list for
# _variant_target() to match against.
variant_selectors = selectors
# Plumb through the list of tags from this variant.
tags = variant.tags
# Finally, set .variant to the simple name string for the
# variant. (This now shadows the template-scope variable
# `variant`, so it can't be used any more in this block.)
variant = variant.name
# Plumb through the suffix of this variant and the list of others.
if (!defined(variant_suffix)) {
variant_suffix = ".$variant"
}
if (!defined(libprefix)) {
libprefix = ""
}
other_variants = []
foreach(other_variant, toolchain_variants) {
if (other_variant.name != variant) {
other_variants += [
{
label = get_label_info(
":${toolchain_base_name}-${other_variant.name}",
"label_no_toolchain")
if (defined(other_variant.variant_suffix)) {
suffix = other_variant.variant_suffix
} else {
suffix = ".${other_variant.name}"
}
},
]
}
}
}
# Translate in-toolchain settings to toolchain-defining settings.
gcc = defined(tc_globals.is_gcc) && tc_globals.is_gcc
if (defined(toolchain_args.use_goma)) {
use_goma = toolchain_args.use_goma
}
forward_variables_from(invoker, [ "strip" ])
if (gcc && defined(strip) && strip == "--strip-sections") {
# GNU strip/objcopy doesn't support --strip-sections.
strip = true
}
host = defined(g.is_host) && g.is_host
}
}
}
}
set_defaults("environment") {
configs = standard_configs
}
# Define environments based on $standard_environments.
#
# $target_name is a suffix on the `name` fields in $standard_environments
# elements and must start with ".". Parameters are generally as for
# environment() except $cpu and $os cannot be set and $configs has
# $standard_configs (and others) prepended rather than being preset.
#
template("standard_environments") {
assert(target_name == "" || get_path_info(target_name, "extension") != "",
"standard_environments() name must start with `.`")
foreach(env, standard_environments) {
foreach(target, env.targets) {
environment("${env.name}${target_name}") {
forward_variables_from(target, "*")
forward_variables_from(env,
"*",
[
"configs",
"name",
"targets",
])
# Let the invoker clobber most settings.
forward_variables_from(invoker,
"*",
[
"configs",
"cpu",
"os",
])
# The invoker can have used `configs -=` to remove some of the
# default configs set above. Now append the base environment's
# configs and the invoker's.
if (defined(env.configs)) {
configs += env.configs
}
if (defined(invoker.configs)) {
configs += invoker.configs
}
}
}
}
}