blob: e31cf8ab84a1d27bfb75dd27669da92f1bee29a3 [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/unification/global_variables.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.
#
# * If `is_kernel` is true, which means when building part of the kernel:
# The template will assert if the `kernel` argument is not set to true.
# It will create a source_set() if building part of the kernel, or
# a static_library() for any other Zircon artefact. 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.
#
# * If `is`_kernel` is false, which means that the library is built either as a
# Fuchsia user binary or a host binary, then the `kernel` parameter is
# ignored, and `sdk` must be set to determine the shape of the library,
# as well as `sdk_headers to list the library's public headers, relative to
# its `include` sub-directory.
#
# If `sdk_publishable` is true, the library will be part of the Fuchsia SDK.
#
# 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
#
# kernel
# Optional: True if this library can be used in the kernel.
# Type: bool
# Default: false
#
# 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 if the global `is_kernel` is true. Note that
# this name is confusing for historical reasons, because using
# this parameter does not make this library exported to the Fuchsia SDK
# (see `sdk_publishable` below for this).
# Type: "static" or "shared" or "source"
#
# sdk_publishable
# Optional: Indicates that this library can be added to the Fuchsia SDK.
# When false, the library is not added to the SDK. When true, it is added
# to the SDK with a "partner" category. Otherwise, a string value may be
# used to specify another category (e.g. `sdk_publishable` = "cts"`).
# Type: bool, or a string indicating an SDK category.
# Default: false
#
# 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
#
# See source_set() for other parameters.
#
# The following parameters are ignored by this implementation. They are here
# to support zx_library() calls that are shared by BUILD.zircon.gn and BUILD.gn
# file. Support for these may be removed after build unification completes.
#
# host
# Optional: Was set to true if this library can be used in
# host-side code, e.g. to be a dependency of a host_tool().
# Type: bool
# Default: false
#
# static
# Optional: True if this library can be statically linked in user code.
# Type: bool
# Default: !$kernel
#
# shared
# Optional: True if this library can be made a shared library for user code.
# Type: bool
# Default: false
#
# sdk_migrated
# Optional: Indicates that this library is built directly by the Fuchsia
# build, and no longer needs to be exported as a legacy target. This is
# used to ease build unification, and will disappear once it is completed.
# Type: bool
# Default: false
#
template("zx_library") {
template_params = [
"host",
"kernel",
"sdk",
"sdk_headers",
"sdk_publishable",
"shared",
"static",
]
# `sdk_migrated` is only used by the Zircon build system.
not_needed(invoker, [ "sdk_migrated" ])
if (zircon_toolchain != false) {
_library_name = target_name
assert(
!is_kernel || (defined(invoker.kernel) && invoker.kernel),
"This zx_library() cannot be built with a Zircon-specific toolchain! " +
"Consider adding `kernel = true` to its declaration.")
if (defined(invoker.shared) && invoker.shared) {
kernel_library_target_type = "shared_library"
} else 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 us 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}" ]
}
config(_headers_config_target) {
include_dirs = [ "include" ]
}
} else {
# The following parameters are just ignored, as in the GN build the shape of
# a library is driven by the value of the "sdk" parameter.
not_needed(invoker,
[
"kernel",
"host",
"static",
"shared",
])
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) && invoker.sdk_publishable != false
if (sdkable) {
if (invoker.sdk_publishable == true) {
sdk_category = "partner"
} else {
sdk_category = invoker.sdk_publishable
}
}
extra_target_args = {
}
if (shape == "source") {
if (sdkable) {
target_type = "sdk_source_set"
extra_target_args = {
category = sdk_category
api = "//sdk/lib/$target_name/$target_name.api"
sdk_name = target_name
build_as_static = true
}
} else {
target_type = "static_library"
}
} else if (shape == "static") {
if (sdkable) {
target_type = "sdk_static_library"
extra_target_args = {
category = sdk_category
api = "//sdk/lib/$target_name/$target_name.api"
sdk_name = target_name
libcxx_linkage = "static"
}
} else {
target_type = "static_library"
}
} else if (shape == "shared") {
if (sdkable) {
target_type = "sdk_shared_library"
extra_target_args = {
category = sdk_category
api = "//sdk/lib/$target_name/$target_name.api"
symbols_api = "//sdk/lib/$target_name/$target_name.symbols.api"
sdk_name = target_name
libcxx_linkage = "static"
}
} else {
target_type = "shared_library"
}
} else {
assert(false, "Unknown library type: $shape")
}
main_target_name = target_name
if (defined(invoker.sdk_name)) {
main_target_name = invoker.sdk_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" ]
}
} else if (defined(invoker.sdk_headers) && sdkable) {
# Add the headers to `sources` to ensure sdk_atom checks the API properly.
extra_headers = []
foreach(header, invoker.sdk_headers) {
extra_headers += [ "include/$header" ]
}
}
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
}