blob: 81c2086fea40d69a6c9872a2126d29baa7389b96 [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.
import("//build/cpp/sdk_shared_library.gni")
import("//build/cpp/sdk_source_set.gni")
import("//build/cpp/sdk_static_library.gni")
import("//build/toolchain/toolchain_environment.gni")
# Build a zircon-specific library, possibly in several ways.
#
# This template should be used by Zircon build rules exclusively, and follows
# most of the conventions of the Zircon build `library()` template, which
# differ significantly from those of `library()` in the Fuchsia build.
#
# IMPORTANT NOTE: Due to historical reasons, its behaviour is very different,
# depending on the value of the `is_kernel` global variable.
#
# * When building with a Zircon-specific toolchain, it will create a source_set()
# if the global `is_kernel` is true (meaning building part of the kernel), or
# a static_library() target otherwise. The values of `sdk`, `sdk_publishable`
# and `sdk_headers` will be ignored entirely.
#
# This will also create a :headers sub-target, a group used to give access
# to the library's include directory from any dependent. Note that this
# does *not* make the library's headers, listed in `sdk_headers` public.
#
# This behaviour is needed to replicate the Zircon build's behaviour when
# compiling Zircon artefacts.
#
# * When not using a Zircon-specific toolchain, which means the library is built
# either as a Fuchsia user binary or a host binary, `sdk` must be set to determine
# the shape of the library, as must `sdk_headers to list the library's public
# headers, relative to its `include` sub-directory.
#
# If `sdk_publishable` is present, an sdk_*() template will be used, enabling
# the library to be part of the Fuchsia SDK. The value of `sdk_publishable`
# must be a valid SDK category.
#
# Any :headers sub-targets that appear in public_deps will be rewritten into
# a dependency to the library itself, e.g.:
#
# public_deps = [ "//zircon/system/ulib/foo:headers" ]
#
# will be replaced by:
#
# public_deps = [ "//zircon/system/ulib/foo" ]
#
# Because the Fuchsia build doesn't support :headers sub-targets in
# non-kernel libraries for several technical reasons.
#
# Parameters
#
# sdk
# Optional: A value that indicates whether to build this library as a
# source set, static library or shared library with the Fuchsia build.
# This is required, except when building with Zircon-specific toolchains.
# Note that this name is confusing for historical reasons, because using
# this parameter does not alone make this library exported to the Fuchsia
# SDK (see `sdk_publishable` below for this).
# TODO(https://fxbug.dev/333125197): Rename this parameter.
# Values: "static" or "shared" or "source"
#
# sdk_publishable
# Optional: Indicates that this library can be added to the Fuchsia SDK
# and in which SDK category.
# Type: string indicating an SDK category.
#
# sdk_area (optional)
# [string] The API area responsible for maintaining this library.
# See //build/sdk/sdk_atom.gni.
#
# sdk_headers
# Optional: Required, except if the global `is_kernel` is true.
# This must list all the public header files in the library's `include/`
# directory; names should be relative to `include/`.
# Type: list(string)
#
# sdk_name
# Optional: Name under which the library is published. This can be used
# when $target_name is already used by another target in the Fuchsia build.
# Type: string
# Default: target_name
#
# sdk_headers_for_internal_use
# Optional: This is always forwarded to the corresponding `sdk_*` template.
# See `sdk_source_set` for example about its significance.
#
# See source_set() for other parameters.
#
template("zx_library") {
template_params = [
"sdk",
"sdk_headers",
"sdk_publishable",
]
# TODO(https://fxbug.dev/333125197): Move this such that it is only applied
# when needed and does not silently ignore parameters that will never be used
# (i.e., for non-sdkable targets). Update the documentation above to indicate
# when it is supported.
not_needed(invoker,
[
"sdk_name",
# Not all template expansion paths use this variable, don't
# error out in those paths.
"sdk_headers_for_internal_use",
])
if (zircon_toolchain != false) {
_library_name = target_name
if (toolchain_environment == "kernel") {
# In the kernel proper, zx_library() is always a source_set().
# Everything goes into the kernel and anything unused gets linker GC.
kernel_library_target_type = "source_set"
} else {
kernel_library_target_type = "static_library"
}
# If the library has the same name as its directory, just create
# :headers and :headers.config sub-targets. Otherwise, create
# :foo.headers and :foo.headers.config
if (get_label_info(":$_library_name", "name") ==
get_path_info(get_label_info(":$_library_name", "dir"), "file")) {
_headers_target = "headers"
_headers_config_target = "headers.config"
} else {
_headers_target = "$_library_name.headers"
_headers_config_target = "$_library_name.headers.config"
}
target(kernel_library_target_type, _library_name) {
if (kernel_library_target_type == "static_library") {
complete_static_lib = true
}
forward_variables_from(invoker, "*", template_params)
if (!defined(public_deps)) {
public_deps = []
}
public_deps += [ ":$_headers_target" ]
}
group(_headers_target) {
# Used to represent header dependencies.
# Direct use of public_configs should be rare but is sometimes needed.
forward_variables_from(invoker,
[
"public_configs",
"public_deps",
"testonly",
"visibility",
])
if (!defined(public_configs)) {
public_configs = []
}
public_configs += [ ":${_headers_config_target}" ]
if (!defined(public_deps)) {
public_deps = []
}
public_deps += [ "//zircon/system/public" ]
}
config(_headers_config_target) {
include_dirs = [ "include" ]
}
} else {
assert(
defined(invoker.sdk),
"The `sdk` argument is needed to build a zx_library() with a Fuchsia or host toolchain ($current_toolchain)")
shape = invoker.sdk
sdkable = defined(invoker.sdk_publishable)
if (sdkable) {
assert(
invoker.sdk_publishable == "${invoker.sdk_publishable}",
"Must be an SDK category name if specified - received: ${invoker.sdk_publishable}")
sdk_category = invoker.sdk_publishable
}
extra_target_args = {
}
if (shape == "source") {
if (sdkable) {
name = target_name
if (defined(invoker.sdk_name)) {
name = invoker.sdk_name
}
target_type = "sdk_source_set"
if (sdk_category == "public" || sdk_category == "partner") {
# API version checks are only relevant for public or partner APIs.
# Here, and in the similar code below.
extra_target_args = {
api = "//sdk/lib/$target_name/$target_name.api"
build_as_static = true
category = sdk_category
sdk_name = name
forward_variables_from(invoker,
[
"sdk_headers_for_internal_use",
"sdk_area",
])
}
} else {
extra_target_args = {
category = sdk_category
sdk_name = name
build_as_static = true
forward_variables_from(invoker,
[
"sdk_headers_for_internal_use",
"sdk_area",
])
}
}
} else {
target_type = "static_library"
}
} else if (shape == "static") {
if (sdkable) {
target_type = "sdk_static_library"
if (sdk_category == "public" || sdk_category == "partner") {
extra_target_args = {
api = "//sdk/lib/$target_name/$target_name.api"
category = sdk_category
libcxx_linkage = "static"
sdk_name = target_name
forward_variables_from(invoker,
[
"sdk_headers_for_internal_use",
"sdk_area",
])
}
} else {
extra_target_args = {
category = sdk_category
sdk_name = target_name
libcxx_linkage = "static"
forward_variables_from(invoker,
[
"sdk_headers_for_internal_use",
"sdk_area",
])
}
}
} else {
target_type = "static_library"
}
} else if (shape == "shared") {
if (sdkable) {
target_type = "sdk_shared_library"
if (sdk_category == "public" || sdk_category == "partner") {
extra_target_args = {
api = "//sdk/lib/$target_name/$target_name.api"
category = sdk_category
libcxx_linkage = "static"
sdk_name = target_name
symbols_api = "//sdk/lib/$target_name/$target_name.ifs"
forward_variables_from(invoker,
[
"sdk_headers_for_internal_use",
"sdk_area",
])
}
} else {
extra_target_args = {
category = sdk_category
sdk_name = target_name
libcxx_linkage = "static"
forward_variables_from(invoker,
[
"sdk_headers_for_internal_use",
"sdk_area",
])
}
}
} else {
target_type = "shared_library"
}
} else {
assert(false, "Unknown library type: $shape")
}
main_target_name = target_name
config_target_name = "$target_name.config"
config(config_target_name) {
include_dirs = [ "include" ]
}
# IMPORTANT: Rewrite header dependencies in public_deps
#
# For each zx_library(), the Zircon build used to produce a 'headers'
# group that adds a 'headers.config' public config. This is done to allow
# other targets to depend on the library's headers, but not the library
# itself.
#
# In practice, this means it is common for targets to list these headers
# groups in their public_deps, as in:
#
# public_deps = [ "//sdk/lib/fit:headers" ]
#
# However, these groups do not mix well with the Fuchsia build, and
# especially with sdk_source_set() or sdk_static_library().
#
# To work around this, rewrite the headers public dependencies into
# regular dependencies into the libraries themselves.
#
lib_deps = []
if (defined(invoker.deps)) {
lib_deps = invoker.deps
}
lib_public_deps = []
if (defined(invoker.public_deps)) {
foreach(dep, invoker.public_deps) {
if (get_label_info(dep, "name") == "headers") {
# Format //zircon/.../foo:headers -> //zircon/.../foo
dep = get_label_info(dep, "dir")
} else if (get_path_info(get_label_info(dep, "name"), "extension") ==
"headers") {
# Format //zircon/.../foo:bar.headers -> //zircon/.../foo:bar
dep = get_label_info(dep, "dir") + ":" +
get_path_info(get_label_info(dep, "name"), "name")
}
lib_public_deps += [ dep ]
}
}
# Remove references to a libzircon dependency, as it is provided by the
# sysroot in the present build.
lib_libs = []
if (defined(invoker.libs)) {
lib_libs = invoker.libs
}
if (!is_fuchsia) {
lib_public_deps += [ "//zircon/system/public" ]
}
_has_public_headers =
defined(invoker.sdk_headers) && invoker.sdk_headers != []
target(target_type, main_target_name) {
forward_variables_from(invoker,
"*",
template_params + [
"deps",
"libs",
"public_deps",
])
deps = lib_deps
libs = lib_libs
public_deps = lib_public_deps
forward_variables_from(extra_target_args, "*")
if (_has_public_headers) {
public = []
foreach(header, invoker.sdk_headers) {
public += [ "include/$header" ]
}
if (sdkable && sdk_category == "internal") {
# By default, templates like sdk_source_set() set the `include_base` value to "//" for
# targets in the 'internal' category. Set if to the correct value here to avoid
# issues later when trying to use the library from the SDK.
# See https://fxbug.dev/42066095 for details.
include_base = "include"
}
}
if (!defined(public_configs)) {
public_configs = []
}
public_configs += [ ":$config_target_name" ]
if (!defined(defines)) {
defines = []
}
defines += [ "_ALL_SOURCE" ]
if (!defined(data_deps)) {
data_deps = []
}
# Add allowlist to data_deps rather than deps to not trigger SDK deps logic
data_deps += [ "//build:deprecated_zx_wrapper_allowlist" ]
}
}
# Uncomment the below to generate the allowlist
#print("\"" + get_label_info(":$target_name", "dir") + "/*\",")
}
set_defaults("zx_library") {
configs = default_common_binary_configs
}