blob: 3de37432fcc878eb0396ce7c91e0f90b5ba689dd [file] [log] [blame]
# Copyright 2016 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.
# The GN files in //third_party/flutter all use $flutter_root/
# in place of // to refer to the root of the flutter source tree.
flutter_root = "//third_party/flutter"
declare_args() {
# Debug build.
is_debug = true
}
if (target_os == "") {
target_os = "fuchsia"
}
if (target_cpu == "") {
target_cpu = host_cpu
}
target_platform = "${target_os}-${target_cpu}"
if (current_cpu == "") {
current_cpu = target_cpu
}
if (current_os == "") {
current_os = target_os
}
current_platform = "${current_os}-${current_cpu}"
host_platform = "${host_os}-${host_cpu}"
if (target_os == "fuchsia") {
target_toolchain = "//build/toolchain/fuchsia:${target_cpu}"
} else {
assert(false, "Target OS not supported")
}
if (host_os == "linux" || host_os == "mac") {
host_toolchain = "//build/toolchain:host_${host_cpu}"
} else {
assert(false, "Host OS not supported")
}
set_default_toolchain(target_toolchain)
# Some projects expect a default value for sources_assignment_filter.
sources_assignment_filter = []
declare_args() {
# *This should never be set as a build argument.*
# It exists only to be set in `toolchain_args`.
# See //build/toolchain/clang_toolchain.gni for details.
# This variable is a scope giving details about the current toolchain:
# `toolchain_variant.base`
# [label] The "base" toolchain for this variant, *often the
# right thing to use in comparisons, not `current_toolchain`.*
# This is the toolchain actually referenced directly in GN
# source code. If the current toolchain is not
# `shlib_toolchain` or a variant toolchain, this is the same
# as `current_toolchain`. In one of those derivative
# toolchains, this is the toolchain the GN code probably
# thought it was in. This is the right thing to use in a test
# like `toolchain_variant.base == target_toolchain`, rather
# rather than comparing against `current_toolchain`.
# `toolchain_variant.name`
# [string] The name of this variant, as used in `variant` fields
# in [`select_variant`](#select_variant) clauses. In the base
# toolchain and its `shlib_toolchain`, this is `""`.
# `toolchain_variant.suffix`
# [string] This is "-${toolchain_variant.name}", "" if name is empty.
# `toolchain_variant.is_pic_default`
# [bool] This is true in `shlib_toolchain`.
# The other fields are the variant's effects as defined in
# [`known_variants`](#known_variants).
toolchain_variant = {
base = target_toolchain # default toolchain
}
}
if (!defined(toolchain_variant.name)) {
# Default values describe the "null variant".
# All the optional fields (except `toolchain_args`) are canonicalized
# to their default/empty values so the code below doesn't need to have
# `defined(toolchain_variant.field)` checks all over.
toolchain_variant.name = ""
toolchain_variant.suffix = ""
toolchain_variant.configs = []
toolchain_variant.remove_common_configs = []
toolchain_variant.remove_shared_configs = []
toolchain_variant.deps = []
toolchain_variant.is_pic_default = false
toolchain_variant.with_shared = true
}
is_android = false
is_chromeos = false
is_fuchsia = false
is_fuchsia_host = false
is_ios = false
is_linux = false
is_mac = false
is_win = false
is_clang = true
is_component_build = false
is_official_build = false
# This is set to allow third party projects to configure their GN build based
# on the knowledge that they're being built in the Fuchsia tree. In the
# subproject this can be tested with
# `if (defined(is_fuchsia_tree) && is_fuchsia_tree) { ... }`
# thus allowing configuration without requiring all users of the subproject to
# set this variable.
is_fuchsia_tree = true
if (current_os == "fuchsia") {
is_fuchsia = true
} else if (current_os == "linux") {
is_linux = true
} else if (current_os == "mac") {
is_mac = true
}
# Some library targets may be built as different type depending on the target
# platform. This variable specifies the default library type for each target.
if (is_fuchsia) {
default_library_type = "shared_library"
} else {
default_library_type = "static_library"
}
# When we are in a variant of host_toolchain, change the value of
# host_toolchain so that `if (current_toolchain == host_toolchain)` tests
# still match, since that is the conventional way to detect being in host
# context. This means that any "...($host_toolchain)" label references
# from inside a variant of host_toolchain will refer to the variant
# (current_toolchain rather than host_toolchain). To handle this, the
# `executable()` template below will define its target in other variant
# toolchains as a copy of the real executable.
if (toolchain_variant.base == host_toolchain) {
is_fuchsia_host = true
host_toolchain += toolchain_variant.suffix
}
# References should use `"label($shlib_toolchain)"` rather than
# `"label(${target_toolchain}-shared)"` or anything else.
shlib_toolchain = "${toolchain_variant.base}${toolchain_variant.suffix}-shared"
# All binary targets will get this list of configs by default.
default_common_binary_configs = [
"//build/config:compiler",
"//build/config:relative_paths",
"//build/config:default_frame_pointers",
"//build/config:default_include_dirs",
"//build/config:default_symbols",
"//build/config:default_warnings",
"//build/config:no_exceptions",
"//build/config:no_rtti",
"//build/config:symbol_visibility_hidden",
]
if (is_debug) {
default_common_binary_configs += [ "//build/config:debug" ]
} else {
default_common_binary_configs += [ "//build/config:release" ]
}
if (is_fuchsia) {
default_common_binary_configs += [
"//build/config/fuchsia:auto_var_init",
"//build/config/fuchsia:icf",
"//build/config/fuchsia:thread_safety_annotations",
"//build/config/fuchsia:werror",
# TODO(mcgrathr): Perhaps restrict this to only affected code.
# For now, safest to do it everywhere.
"//build/config/fuchsia:zircon_asserts",
]
}
default_common_binary_configs += [ "//build/config/lto:default" ]
# Add and remove configs specified by the variant.
default_common_binary_configs += toolchain_variant.configs
default_common_binary_configs -= toolchain_variant.remove_common_configs
default_shared_library_configs = default_common_binary_configs + [
"//build/config:shared_library_config",
"//build/config:symbol_no_undefined",
]
default_shared_library_configs -= toolchain_variant.remove_shared_configs
default_executable_configs = default_common_binary_configs + [
"//build/config:executable_config",
"//build/config:default_libs",
]
default_executable_deps = [ "//build/config/scudo:default_for_executable" ]
if (toolchain_variant.is_pic_default) {
default_common_binary_configs += [ "//build/config:shared_library_config" ]
}
# Apply that default list to the binary target types.
set_defaults("source_set") {
configs = default_common_binary_configs
}
set_defaults("static_library") {
configs = default_common_binary_configs
}
set_defaults("shared_library") {
configs = default_shared_library_configs
}
set_defaults("loadable_module") {
configs = default_shared_library_configs
}
set_defaults("executable") {
configs = default_executable_configs
}
if (toolchain_variant.with_shared) {
if (!toolchain_variant.is_pic_default) {
# In the main toolchain, shared_library just redirects to the same
# target in the -shared toolchain.
template("shared_library") {
group(target_name) {
public_deps = [
":$target_name(${current_toolchain}-shared)",
]
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
# Mark all variables as not needed to suppress errors for unused
# variables. The other variables normally passed to shared_library
# are actually used by the shared_library instantiation in the
# -shared toolchain, so any going truly unused will be caught there.
not_needed(invoker, "*")
}
}
} else {
# In the -shared toolchain, shared_library is just its normal self,
# but if the invoker constrained the visibility, we must make sure
# the dependency from the main toolchain is still allowed.
template("shared_library") {
shared_library(target_name) {
# Explicitly forward visibility, implicitly forward everything
# else. Forwarding "*" doesn't recurse into nested scopes (to
# avoid copying all globals into each template invocation), so
# won't pick up file-scoped variables. Normally this isn't too
# bad, but visibility is commonly defined at the file scope.
# Explicitly forwarding visibility and then excluding it from the
# "*" set works around this problem. See http://crbug.com/594610
# for rationale on why this GN behavior is not considered a bug.
forward_variables_from(invoker, [ "visibility" ])
forward_variables_from(invoker, "*", [ "visibility" ])
if (defined(visibility)) {
visibility += [ ":$target_name" ]
}
}
}
}
}
# This is the basic "asan" variant. Others start with this and modify.
# See `known_variants` (below) for the meaning of fields in this scope.
_asan_variant = {
configs = [ "//build/config/sanitizers:asan" ]
if (host_os != "fuchsia") {
host_only = {
# On most systems (not Fuchsia), the sanitizer runtimes are normally
# linked statically and so `-shared` links do not include them.
# Using `-shared --no-undefined` with sanitized code will get
# undefined references for the sanitizer runtime calls generated by
# the compiler. It shouldn't do much harm, since the non-variant
# builds will catch the real undefined reference bugs.
remove_shared_configs = [ "//build/config:symbol_no_undefined" ]
}
}
toolchain_args = {
# -fsanitize=scudo is incompatible with -fsanitize=address.
use_scudo = false
}
}
declare_args() {
# List of variants that will form the basis for variant toolchains.
# To make use of a variant, set [`select_variant`](#select_variant).
#
# Normally this is not set as a build argument, but it serves to
# document the available set of variants.
# See also [`universal_variants`](#universal_variants).
# Only set this to remove all the default variants here.
# To add more, set [`extra_variants`](#extra_variants) instead.
#
# Each element of the list is one variant, which is a scope defining:
#
# `configs` (optional)
# [list of labels] Each label names a config that will be
# automatically used by every target built in this variant.
# For each config `${label}`, there must also be a target
# `${label}_deps`, which each target built in this variant will
# automatically depend on. The `variant()` template is the
# recommended way to define a config and its `_deps` target at
# the same time.
#
# `remove_common_configs` (optional)
# `remove_shared_configs` (optional)
# [list of labels] This list will be removed (with `-=`) from
# the `default_common_binary_configs` list (or the
# `default_shared_library_configs` list, respectively) after
# all other defaults (and this variant's configs) have been
# added.
#
# `deps` (optional)
# [list of labels] Added to the deps of every target linked in
# this variant (as well as the automatic `${label}_deps` for
# each label in configs).
#
# `name` (required if configs is omitted)
# [string] Name of the variant as used in
# [`select_variant`](#select_variant) elements' `variant` fields.
# It's a good idea to make it something concise and meaningful when
# seen as e.g. part of a directory name under `$root_build_dir`.
# If name is omitted, configs must be nonempty and the simple names
# (not the full label, just the part after all `/`s and `:`s) of these
# configs will be used in toolchain names (each prefixed by a "-"),
# so the list of config names forming each variant must be unique
# among the lists in `known_variants + extra_variants`.
#
# `toolchain_args` (optional)
# [scope] Each variable defined in this scope overrides a
# build argument in the toolchain context of this variant.
#
# `host_only` (optional)
# `target_only` (optional)
# [scope] This scope can contain any of the fields above.
# These values are used only for host or target, respectively.
# Any fields included here should not also be in the outer scope.
#
known_variants = [
{
configs = [ "//build/config/lto" ]
},
{
configs = [ "//build/config/lto:thinlto" ]
},
{
configs = [ "//build/config/profile" ]
},
{
configs = [ "//build/config/scudo" ]
},
{
configs = [ "//build/config/sanitizers:ubsan" ]
},
{
configs = [
"//build/config/sanitizers:ubsan",
"//build/config/sanitizers:sancov",
]
},
_asan_variant,
{
forward_variables_from(_asan_variant, "*")
configs += [ "//build/config/sanitizers:sancov" ]
},
{
name = "asan_no_detect_leaks"
forward_variables_from(_asan_variant, "*", [ "toolchain_args" ])
toolchain_args = {
forward_variables_from(_asan_variant.toolchain_args, "*")
asan_default_options = "detect_leaks=0"
}
},
# Fuzzer variants for various sanitizers, -fsanitize=fuzzer results
# in undefined symbols in shared objects that are satisfied in the final,
# statically linked fuzzer.
{
# TODO(aarongreen): TC-264: Clang emits new/new[]/delete/delete[] into
# libfuzzer's static libc++. Remove this when fixed.
forward_variables_from(_asan_variant, "*", [ "toolchain_args" ])
toolchain_args = {
forward_variables_from(_asan_variant.toolchain_args, "*")
asan_default_options = "alloc_dealloc_mismatch=0"
}
configs += [ "//build/config/sanitizers:fuzzer" ]
remove_shared_configs = [ "//build/config:symbol_no_undefined" ]
},
{
configs = [
"//build/config/sanitizers:ubsan",
"//build/config/sanitizers:fuzzer",
]
remove_shared_configs = [ "//build/config:symbol_no_undefined" ]
},
]
# Additional variant toolchain configs to support.
# This is just added to [`known_variants`](#known_variants).
extra_variants = []
# List of "universal" variants, in addition to
# [`known_variants`](#known_variants). Normally this is not set as a
# build argument, but it serves to document the available set of
# variants. These are treated just like
# [`known_variants`](#known_variants), but as well as being variants by
# themselves, these are also combined with each of
# [`known_variants`](#known_variants) to form additional variants,
# e.g. "asan-debug" or "ubsan-sancov-release".
universal_variants = []
# Only one of "debug" and "release" is really available as a universal
# variant in any given build (depending on the global setting of
# `is_debug`). But this gets evaluated separately in every toolchain, so
# e.g. in the "release" toolchain the sense of `if (is_debug)` tests is
# inverted and this would list only "debug" as an available variant. The
# selection logic in `variant_target()` can only work if the value of
# `universal_variants` it sees includes the current variant.
if (is_debug) {
universal_variants += [
{
name = "release"
configs = []
toolchain_args = {
is_debug = false
}
},
]
} else {
universal_variants += [
{
name = "debug"
configs = []
toolchain_args = {
is_debug = true
}
},
]
}
# List of short names for commonly-used variant selectors. Normally this
# is not set as a build argument, but it serves to document the available
# set of short-cut names for variant selectors. Each element of this list
# is a scope where `.name` is the short name and `.select_variant` is a
# a list that can be spliced into [`select_variant`](#select_variant).
select_variant_shortcuts = [
{
name = "host_asan"
select_variant = []
select_variant = [
{
variant = "asan_no_detect_leaks"
host = true
dir = [
# TODO(TO-565): The yasm host tools have leaks.
"//third_party/yasm",
# TODO(TO-666): replace futiltiy & cgpt with 1p tools
"//third_party/vboot_reference",
"//garnet/tools/vboot_reference",
# TODO(INTK-998): update spirv-tools and glslang
"//third_party/shaderc/third_party/spirv-tools",
]
},
{
variant = "asan"
host = true
},
]
},
# TODO(TC-241): Remove this when TC-241 is fixed. For now, don't
# apply ASan to drivers because all drivers (and nothing else)
# use -static-libstdc++ and so hit the TC-241 problem.
{
name = "asan"
select_variant = []
select_variant = [
{
target_type = [ "driver_module" ]
variant = false
},
{
variant = "asan"
host = false
},
]
},
]
}
# Now elaborate the fixed shortcuts with implicit shortcuts for
# each known variant. The shortcut is just the name of the variant
# and selects for `host=false`.
_select_variant_shortcuts = select_variant_shortcuts
foreach(variant, known_variants) {
if (defined(variant.name)) {
variant = variant.name
} else {
# This is how GN spells "let".
foreach(configs, [ variant.configs ]) {
variant = ""
foreach(config, configs) {
config = get_label_info(config, "name")
if (variant == "") {
variant = config
} else {
variant += "-$config"
}
}
}
}
_select_variant_shortcuts += [
{
name = variant
select_variant = []
select_variant = [
{
variant = name
host = false
},
]
},
]
foreach(universal_variant, universal_variants) {
_select_variant_shortcuts += [
{
name = "${variant}-${universal_variant.name}"
select_variant = []
select_variant = [
{
variant = name
host = false
},
]
},
]
}
}
foreach(variant, universal_variants) {
variant = variant.name
_select_variant_shortcuts += [
{
name = variant
select_variant = []
select_variant = [
{
variant = name
host = false
},
]
},
]
}
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.
#
# Each selector is either a string or a scope. A shortcut selector is
# a string; it gets expanded to a full selector. A full selector is a
# scope, described below.
#
# A string selector can match a name in
# [`select_variant_shortcuts`](#select_variant_shortcuts). If it's not a
# specific shortcut listed there, then it can be the name of any variant
# described in [`known_variants`](#known_variants) and
# [`universal_variants`](#universal_variants) (and combinations thereof).
# A `selector` that's a simple variant name selects for every binary
# built in the target toolchain: `{ host=false variant=selector }`.
#
# If a string selector contains a slash, then it's `"shortcut/filename"`
# and selects only the binary in the target toolchain whose `output_name`
# matches `"filename"`, i.e. it adds `output_name=["filename"]` to each
# selector scope that the shortcut's name alone would yield.
#
# The scope that forms a full selector defines some of these:
#
# variant (required)
# [string or `false`] The variant that applies if this selector
# matches. This can be `false` to choose no variant, or a string
# that names the variant. See
# [`known_variants`](#known_variants) and
# [`universal_variants`](#universal_variants).
#
# The rest below are matching criteria. All are optional.
# The selector matches if and only if all of its criteria match.
# If none of these is defined, then the selector always matches.
#
# The first selector in the list to match wins and then the rest of
# the list is ignored. So construct more complex rules by using a
# "blacklist" selector with `variant=false` before a catch-all or
# "whitelist" selector that names a variant.
#
# Each "[strings]" criterion is a list of strings, and the criterion
# is satisfied if any of the strings matches against the candidate string.
#
# host
# [boolean] If true, the selector matches in the host toolchain.
# If false, the selector matches in the target toolchain.
#
# testonly
# [boolean] If true, the selector matches targets with testonly=true.
# If false, the selector matches in targets without testonly=true.
#
# target_type
# [strings]: `"executable"`, `"loadable_module"`, or `"driver_module"`
#
# output_name
# [strings]: target's `output_name` (default: its `target name`)
#
# label
# [strings]: target's full label with `:` (without toolchain suffix)
#
# name
# [strings]: target's simple name (label after last `/` or `:`)
#
# dir
# [strings]: target's label directory (`//dir` for `//dir:name`).
select_variant = []
# *This should never be set as a build argument.*
# It exists only to be set in `toolchain_args`.
# See //build/toolchain/clang_toolchain.gni for details.
select_variant_canonical = []
}
# Do this only once, in the default toolchain context. Then
# clang_toolchain_suite will just pass the results through to every
# other toolchain via toolchain_args so the work is not repeated.
if (toolchain_variant.base == target_toolchain && current_cpu == target_cpu &&
current_os == target_os && toolchain_variant.name == "" &&
!toolchain_variant.is_pic_default) {
assert(select_variant_canonical == [],
"`select_variant_canonical` cannot be set as a build argument")
foreach(selector, select_variant) {
if (selector != "$selector") {
# It's a scope, not a string. Just use it as is.
select_variant_canonical += [ selector ]
} else if (selector == "gcc" || selector == "clang") {
# Ignore these as special cases. They're just here to be
# passed through in zircon_args.
} else {
# It's a string, not a scope. Expand the shortcut.
# If there is a slash, this is "shortcut/output_name".
# If not, it's just "shortcut".
foreach(file, [ get_path_info(selector, "file") ]) {
if (file == selector) {
file = ""
} else {
selector = get_path_info(selector, "dir")
}
foreach(shortcut, _select_variant_shortcuts) {
# file=true stands in for "break".
if (file != true && selector == shortcut.name) {
# Found the matching shortcut.
if (file == "") {
# It applies to everything, so just splice it in directly.
select_variant_canonical += shortcut.select_variant
} else {
# Add each of the shortcut's clauses amended with the
# output_name constraint.
foreach(clause, shortcut.select_variant) {
select_variant_canonical += [
{
forward_variables_from(clause, "*")
output_name = [ file ]
},
]
}
}
file = true
}
}
assert(file == true,
"unknown shortcut `${selector}` used in `select_variant`")
}
}
}
}
template("variant_target") {
target_type = target_name
target_name = invoker.target_name
target_invoker = {
# Explicitly forward visibility, implicitly forward everything else.
# See comment in template("shared_library") above for details.
forward_variables_from(invoker, [ "visibility" ])
forward_variables_from(invoker,
"*",
[
"_target_type",
"target_name",
"visibility",
])
if (!defined(output_name)) {
output_name = target_name
}
}
# target_type is the real GN target type that builds the thing.
# selector_target_type is the name matched against target_type selectors.
if (defined(invoker._target_type)) {
selector_target_type = invoker._target_type
} else {
selector_target_type = target_type
}
target_label = get_label_info(":$target_name", "label_no_toolchain")
# These are not actually used in all possible if branches below,
# so defang GN's extremely sensitive "unused variable" errors.
not_needed([
"selector_target_type",
"target_invoker",
"target_label",
"target_type",
])
target_variant = false
if (select_variant_canonical != []) {
# See if there is a selector that matches this target.
selected = false
foreach(selector, select_variant_canonical) {
# The first match wins.
# GN's loops don't have "break", so do nothing on later iterations.
if (!selected) {
# Expand the selector so we don't have to do a lot of defined(...)
# tests below.
select = {
}
select = {
target_type = []
output_name = []
label = []
name = []
dir = []
forward_variables_from(selector, "*")
}
selected = true
if (selected && defined(selector.host)) {
selected = current_toolchain == host_toolchain == selector.host
}
if (selected && defined(selector.testonly)) {
selected = (defined(target_invoker.testonly) &&
target_invoker.testonly) == selector.testonly
}
if (selected && select.target_type != []) {
selected = false
candidate = selector_target_type
foreach(try, select.target_type) {
if (try == candidate) {
selected = true
}
}
}
if (selected && select.output_name != []) {
selected = false
candidate = target_invoker.output_name
foreach(try, select.output_name) {
if (try == candidate) {
selected = true
}
}
}
if (selected && select.label != []) {
selected = false
candidate = target_label
foreach(try, select.label) {
if (try == candidate) {
selected = true
}
}
}
if (selected && select.name != []) {
selected = false
candidate = get_label_info(target_label, "name")
foreach(try, select.name) {
if (try == candidate) {
selected = true
}
}
}
if (selected && select.dir != []) {
selected = false
candidate = get_label_info(target_label, "dir")
foreach(try, select.dir) {
if (try == candidate) {
selected = true
}
}
}
if (selected && selector.variant != false) {
target_variant = "-${selector.variant}"
}
}
}
}
if (target_variant == false) {
target_variant = ""
}
builder_toolchain = toolchain_variant.base + target_variant
if (invoker._variant_shared) {
builder_toolchain += "-shared"
}
if (current_toolchain == builder_toolchain) {
# This is the toolchain selected to actually build this target.
target(target_type, target_name) {
deps = []
forward_variables_from(target_invoker, "*")
deps += toolchain_variant.deps
foreach(config, toolchain_variant.configs) {
# Expand the label so it always has a `:name` part.
config = get_label_info(config, "label_no_toolchain")
deps += [ "${config}_deps" ]
}
if (defined(visibility)) {
# Other toolchains will define this target as a group or copy
# rule that depends on this toolchain's definition. If the
# invoker constrained the visibility, make sure those
# dependencies from other toolchains are still allowed.
visibility += [ ":${target_name}" ]
}
}
} else if (current_toolchain == shlib_toolchain) {
# Don't copy from a variant into a -shared toolchain, because nobody
# looks for an executable or loadable_module there. Instead, just
# forward any deps to the real target.
group(target_name) {
forward_variables_from(target_invoker,
[
"testonly",
"visibility",
])
if (defined(visibility)) {
visibility += [ ":${target_name}" ]
}
deps = [
":${target_name}(${builder_toolchain})",
]
}
} else {
# When some variant was selected, then this target in all other
# toolchains is actually just this copy rule. The target is built in
# the selected variant toolchain, but then copied to its usual name in
# $root_out_dir so that things can find it there.
copy_vars = {
forward_variables_from(target_invoker,
[
"testonly",
"visibility",
])
if (defined(visibility)) {
visibility += [ ":${target_name}" ]
}
deps = [
":${target_name}(${builder_toolchain})",
]
variant_out_dir = get_label_info(deps[0], "root_out_dir")
full_output_name = target_invoker.output_name
if (defined(target_invoker.output_extension) &&
target_invoker.output_extension != "") {
full_output_name += ".${target_invoker.output_extension}"
}
sources = [
"$variant_out_dir/$full_output_name",
]
outputs = [
"$root_out_dir/$full_output_name",
]
}
# In the host toolchain, make a symlink rather than a hard link
# (which is what "copy" rules really do). Host tools are built with
# an embedded shared library lookup path based on $ORIGIN on Linux
# (//build/config/linux:compiler) and the equivalent @loader_path on
# macOS (//build/config/mac:mac_dynamic_flags). The dynamic linker
# translates this to "the directory containing the executable".
# With hard links, this gets the directory used to invoke the
# executable, which is host_toolchain's $root_out_dir. With
# symlinks, it instead gets the directory containing the actual
# executable file, which is builder_toolchain's $root_out_dir.
# Hence the program uses the variant builds of shared libraries that
# go with the variant build of the executable, rather using than the
# vanilla host_toolchain builds with the variant executable.
if (current_toolchain == host_toolchain) {
action(target_name) {
forward_variables_from(copy_vars, "*")
script = "/bin/ln"
args = [
"-snf",
rebase_path(sources[0], get_path_info(outputs[0], "dir")),
rebase_path(outputs[0]),
]
}
} else {
# For Fuchsia, //build/gn/variant.py depends on hard links to
# identify the variants.
copy(target_name) {
forward_variables_from(copy_vars, "*")
}
}
}
}
template("executable") {
_executable_name = target_name
_variant_shared = false
variant_target("executable") {
deps = []
target_name = _executable_name
# TODO(aarongreen): This shouldn't be required, but without it the
# fuzzers fail to link. Investigate and remove when resolved.
if (defined(invoker._target_type)) {
_target_type = invoker._target_type
}
# Explicitly forward visibility, implicitly forward everything else.
# See comment in template("shared_library") above for details.
forward_variables_from(invoker, [ "visibility" ])
forward_variables_from(invoker, "*", [ "visibility" ])
deps += default_executable_deps
}
}
template("loadable_module") {
_module_name = target_name
_variant_shared = true
variant_target("loadable_module") {
target_name = _module_name
if (defined(invoker._target_type)) {
_target_type = invoker._target_type
}
# Explicitly forward visibility, implicitly forward everything else.
# See comment in template("shared_library") above for details.
forward_variables_from(invoker, [ "visibility" ])
forward_variables_from(invoker, "*", [ "visibility" ])
if (!defined(output_extension)) {
output_extension = "so"
}
}
}
# Some targets we share with Chromium declare themselves to be components,
# which means they can build either as shared libraries or as static libraries.
# We build them as static libraries.
template("component") {
if (!defined(invoker.sources)) {
# When there are no sources defined, use a source set to avoid creating
# an empty static library (which generally don't work).
_component_mode = "source_set"
} else {
_component_mode = "static_library"
}
target(_component_mode, target_name) {
# Explicitly forward visibility, implicitly forward everything else.
# See comment in template("shared_library") above for details.
forward_variables_from(invoker, [ "visibility" ])
forward_variables_from(invoker, "*", [ "visibility" ])
}
}
set_defaults("component") {
configs = default_common_binary_configs
}