blob: 5d56a10b977a22cbd185c6c24aaa3861d6705345 [file] [log] [blame]
# Copyright 2020 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.
# Use this template to create a group() that redirects to a shared_library()
# target built in the appropriate build variant toolchain.
#
# This is seldom needed, typically when a non-linkable GN target needs to
# depend on a shared_library() instance directly. Let's consider the example
# of a component that contains a prebuilt ELF binary, which depends on libfdio.so
# defined by the //sdk/lib/fdio target. To achieve this, one would use something
# like the following:
#
# variant_shared_library_redirect("my_fdio") {
# library = "//sdk/lib/fdio"
# }
#
# fuchsia_component("my_component") {
# deps = [
# ":my_prebuilt_binary",
# ":my_fdio",
# ]
# ...
# }
#
# This ensures that the version of libfdio.so installed in the component corresponds
# to the appropriate variant selection for this build.
#
# This template should not be used for when executable(), loadable_module() or other
# linkable GN targets are defined, and depend on other shared_library() instances.
# That's because these templates perform variant selection first, to determine the
# right GN toolchain() to build them, then all their dependencies, including
# shared_library() ones, will be built in it as well.
#
# Arguments:
# library: (required)
# [GN label] A GN label, without toolchain, pointing to a shared_library()
# instance.
#
# exclude_toolchain_tags: (optional)
# [list of strings]
#
# extra_manifest: (optional)
# [GN path] If specified, this must be the path to an output file to be used
# with the extra_manifest argument of the deprecated package() template. This
# ensures that the library will be installed into any package() that depends
# on it. Note that creating a package with fuchsia_package() doesn't need
# this because it relies instead on normal metadata entries to retrieve the
# install locations of all binaries it depends on.
#
# output_dir, output_name, output_extension, testonly (optional)
# [string] or [boolean]: These must match the target library's definition, if
# it happens to set these arguments. This will ensure that variant selectors
# based on the target's output name and testonly flag work correctly.
#
template("variant_shared_library_redirect") {
assert(defined(invoker.library),
"'library' must be defined when calling this template!")
_library_label = get_label_info(invoker.library, "label_no_toolchain")
assert(
_library_label != get_label_info(_library_label, "label_with_toolchain"),
"'library' label must not contain a toolchain when calling this template: $_library_label")
# Keep this in sync with variant_target() in //build/config/BUILDCONFIG.gn
#
_exclude_toolchain_tags = []
if (defined(invoker.exclude_toolchain_tags)) {
_exclude_toolchain_tags += invoker.exclude_toolchain_tags
}
if (defined(toolchain_variant.exclude_variant_tags)) {
_exclude_toolchain_tags += toolchain_variant.exclude_variant_tags
}
# Compute library output name, keep this in sync with shared_library()
if (defined(invoker.output_name)) {
_output_name = invoker.output_name
} else {
_output_name = get_label_info(_library_label, "name")
}
_prefixless = string_replace("###$_output_name", "###lib", "")
if (_prefixless != "###$_output_name") {
_output_name = _prefixless
}
if (defined(invoker.output_extension)) {
_output_extension = invoker.output_extension
} else {
if (current_os == "mac") {
_output_extension = "dylib"
} else if (current_os == "win") {
_output_extension = "dll"
} else {
_output_extension = "so"
}
}
_output_name = "lib${_output_name}"
if (_output_extension != "") {
_output_name += "." + _output_extension
}
if (defined(invoker.output_dir)) {
_output_dir = invoker.output_dir
} else {
_output_dir = target_out_dir
}
testonly = false
forward_variables_from(invoker, [ "testonly" ])
_select = {
host = is_host
testonly = testonly
target_type = [ "shared_library" ]
output_name = [ _output_name ]
label = [ _library_label ]
name = [ get_label_info(_library_label, "name") ]
dir = [ get_label_info(_library_label, "dir") ]
exclude_toolchain_tags = _exclude_toolchain_tags
}
not_needed([ "_select" ])
_variant = false
if (select_variant_canonical != []) {
_selected = false
foreach(selector, select_variant_canonical) {
if (_variant == false) {
_selector = {
}
_selector = {
target_type = []
output_name = []
label = []
name = []
dir = []
forward_variables_from(selector, "*")
}
_selected = true
if (_selected && defined(_selector.host)) {
_selected = _selector.host == _select.host
}
if (_selected && defined(_selector.testonly)) {
_selected = _selector.testonly == _select.testonly
}
if (_selected && _selector.target_type != []) {
_selected = _selector.target_type + _select.target_type -
_select.target_type != _selector.target_type
}
if (_selected && _selector.output_name != []) {
_selected = _selector.output_name + _select.output_name -
_select.output_name != _selector.output_name
}
if (_selected && _selector.label != []) {
_selected =
_selector.label + _select.label - _select.label != _selector.label
}
if (_selected && _selector.name != []) {
_selected =
_selector.name + _select.name - _select.name != _selector.name
}
if (_selected && _selector.dir != []) {
_selected = _selector.dir + _select.dir - _select.dir != _selector.dir
}
if (_selected && _select.exclude_toolchain_tags != []) {
_selected = _select.exclude_toolchain_tags + _selector.variant_tags -
_selector.variant_tags == _select.exclude_toolchain_tags
}
if (_selected && _selector.variant != false) {
_variant = "-${_selector.variant}"
}
}
}
}
if (_variant == false) {
_library_toolchain = current_toolchain
} else {
_library_toolchain = "${toolchain_variant.base}${_variant}"
}
_final_target = "${_library_label}(${_library_toolchain})"
if (defined(invoker.output_dir)) {
_output_dir = invoker.output_dir
} else if (_library_toolchain == default_toolchain) {
_output_dir =
get_label_info("${_library_label}($shlib_toolchain)", "root_out_dir")
} else {
_output_dir = get_label_info(_final_target, "root_out_dir") + "-shared"
}
group(target_name) {
testonly = testonly
public_deps = [ _final_target ]
}
if (defined(invoker.extra_manifest)) {
generated_file("$target_name.extra_manifest_args") {
contents = [
"--entry-manifest=${_final_target}",
"--entry=lib/${_output_name}=" +
rebase_path("${_output_dir}/${_output_name}", root_build_dir),
]
deps = [ _final_target ]
outputs = [ invoker.extra_manifest ]
}
}
}