blob: 02bb54da78170cc0524cd53c7cbb3cbe333de3c4 [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("//build/config/fuchsia/zircon.gni")
import("//build/cpp/extract_public_symbols.gni")
import("//build/cpp/verify_pragma_once.gni")
import("//build/cpp/verify_public_symbols.gni")
import("//build/fidl/wireformat.gni")
import("//build/sdk/sdk_atom.gni")
# Define a library in //zircon/public/lib/$target_name/BUILD.gn.
#
# zircon_library() is invoked by files copied from lib_template.gn based on
# "$zircon_root_build_dir/legacy-$target_cpu.json" entries generated by
# Zircon library() targets with $sdk set. They provide the deps API for
# Fuchsia targets to depend on Zircon libraries, which are either used as
# binaries previously built by Zircon, or built in Fuchsia from source.
#
# Parameters
#
# deps, public_deps
# Optional: Dependencies for the target. $deps is only relevant for
# source libraries. $public_deps reflects header dependencies.
# Type: list(label matching "//zircon/public/lib/*")
#
# dir
# Required: Source-absolute path to library's source directory in //zircon.
# Type: dir
#
# sources
# Optional: If present, publish library as source with these files.
# Type: list(file)
#
# libs
# Optional: If present, publish library as prebuilt with these files.
# Type: list(path relative to $zircon_root_build_dir)
#
# include_dirs
# Required: The directory prefix where $headers are found.
# Type: singleton list(path relative to $zircon_root_build_dir)
#
# headers
# Required: List of header files to copy into the SDK.
# Type: list(path relative to ${include_dirs[0]})
#
# publishable
# Optional: Whether the library is eligible for addition to SDKs.
# Type: bool
# Default: false
#
# Either $sources or $libs must be present.
#
template("zircon_library") {
library = target_name
include = rebase_path(invoker.include_dirs, ".", zircon_root_build_dir)
assert(include == [ include[0] ])
library_headers = rebase_path(invoker.headers, ".", include[0])
# Zircon targets depend explicitly on $zx/system/ulib/zircon, but in
# legacy Fuchsia GN there is no //zircon/public/lib/zircon and instead
# it's available implicitly in the sysroot via `libs = [ "zircon" ]`.
library_deps = []
library_public_deps = []
library_libs = []
if (defined(invoker.deps)) {
library_deps = invoker.deps
}
if (defined(invoker.public_deps)) {
library_public_deps = invoker.public_deps
}
# Remove references to a libzircon dependency, as it is provided by the
# sysroot in the present build.
if (library_deps + [ "//zircon/public/lib/zircon" ] -
[ "//zircon/public/lib/zircon" ] != library_deps) {
library_deps -= [ "//zircon/public/lib/zircon" ]
if (is_fuchsia) {
library_libs += [ "zircon" ]
} else {
library_deps += [
"//zircon/public/lib/zircon-headers",
"//zircon/system/public",
]
}
}
if (library_public_deps + [ "//zircon/public/lib/zircon" ] -
[ "//zircon/public/lib/zircon" ] != library_public_deps) {
library_public_deps -= [ "//zircon/public/lib/zircon" ]
if (is_fuchsia) {
library_libs += [ "zircon" ]
} else {
library_public_deps += [
"//zircon/public/lib/zircon-headers",
"//zircon/system/public",
]
}
}
# Update dependency on libdriver, whose implementation is provided by the
# present build.
if (library_deps + [ "//zircon/public/lib/driver" ] -
[ "//zircon/public/lib/driver" ] != library_deps) {
library_deps -= [ "//zircon/public/lib/driver" ]
library_deps += [ "//src/devices/lib/driver" ]
}
if (library_public_deps + [ "//zircon/public/lib/driver" ] -
[ "//zircon/public/lib/driver" ] != library_public_deps) {
library_public_deps -= [ "//zircon/public/lib/driver" ]
library_public_deps += [ "//src/devices/lib/driver" ]
}
# Update references to boringssl.
foreach(prefix,
[
"",
"u",
]) {
if (library_deps + [ "//zircon/public/lib/${prefix}boringssl" ] -
[ "//zircon/public/lib/${prefix}boringssl" ] != library_deps) {
library_deps -= [ "//zircon/public/lib/${prefix}boringssl" ]
library_deps += [ "//third_party/boringssl" ]
}
if (library_public_deps + [ "//zircon/public/lib/${prefix}boringssl" ] -
[ "//zircon/public/lib/${prefix}boringssl" ] != library_public_deps) {
library_public_deps -= [ "//zircon/public/lib/${prefix}boringssl" ]
library_public_deps += [ "//third_party/boringssl" ]
}
}
# Update reference to zstd libraries, for which there exist targets under
# //third_party/zstd.
foreach(library,
[
"zstd",
"zstdseek",
]) {
if (library_deps + [ "//zircon/public/lib/$library" ] -
[ "//zircon/public/lib/$library" ] != library_deps) {
library_deps -= [ "//zircon/public/lib/$library" ]
library_deps += [ "//third_party/zstd:$library" ]
}
if (library_public_deps + [ "//zircon/public/lib/$library" ] -
[ "//zircon/public/lib/$library" ] != library_public_deps) {
library_public_deps -= [ "//zircon/public/lib/$library" ]
library_public_deps += [ "//third_party/zstd:$library" ]
}
}
is_prebuilt = defined(invoker.libs)
zx_lib_dirs = []
zx_libs = []
if (is_prebuilt) {
# A prebuilt binary (either static .a or shared .so, doesn't matter)
# has nothing to do but bring in the config() for its `libs`.
type = "group"
# Rust targets use -L... -lfoo instead of explicit files. So they
# need to collect the -L list via metadata, and directories on that
# list needs to hold exact names libfoo.so or libfoo.a for -lfoo.
foreach(file, invoker.libs) {
if (get_path_info(file, "extension") == "so" ||
get_path_info(file, "extension") == "a") {
zx_lib_dirs += [ rebase_path(get_path_info(file, "dir"),
"",
zircon_root_build_dir) ]
zx_libs += [ get_path_info(file, "name") ]
} else {
file = rebase_path(file, "", zircon_root_build_dir)
write_file("$target_gen_dir/lib$library.so", [ "INPUT($file)" ])
zx_lib_dirs += [ rebase_path(target_gen_dir) ]
zx_libs += [ library ]
}
}
if (defined(invoker.lib_dirs)) {
zx_lib_dirs += rebase_path(invoker.lib_dirs, "", zircon_root_build_dir)
}
} else {
# A source library is always built for static linking only.
# The invoker (i.e. the JSON) specifies `sources`.
type = "static_library"
}
# A library() always an include/ directory dependents must use.
# A prebuilt library() (`sdk != "source"`) has a library they must link in.
config("$library.config") {
include_dirs = include
if (!is_prebuilt) {
include_dirs += invoker.compilation_include_dirs
} else {
not_needed(invoker, [ "compilation_include_dirs" ])
}
if (is_fuchsia || is_prebuilt) {
libs = library_libs
lib_dirs = zx_lib_dirs
not_needed([ "zx_libs" ])
} else {
not_needed([
"library_libs",
"zx_lib_dirs",
"zx_libs",
])
}
if (defined(invoker.libs) && invoker.libs != []) {
is_host_library =
string_replace(library, "-host", "") + "-host" == library
assert(is_fuchsia != is_host_library,
"Prebuilt $library used in wrong toolchain")
libs += rebase_path(invoker.libs, ".", zircon_root_build_dir)
}
}
has_runtime_dep = false
if (is_prebuilt) {
foreach(file, invoker.install) {
if (get_path_info(file.dest, "dir") == "dist") {
has_runtime_dep = true
}
}
if (has_runtime_dep) {
import("//build/unification/lib/zircon_runtime_library.gni")
runtime_target = "${library}_runtime"
zircon_runtime_library(runtime_target) {
library = library
}
}
}
target(type, library) {
forward_variables_from(invoker,
"*",
[
"compilation_defines",
"compilation_include_dirs",
"debug",
"deps",
"dir",
"disable_ubsan",
"disable_unused_function",
"disable_sanitizers",
"headers",
"include_dirs",
"install",
"lib_dirs",
"dist_dir",
"libs",
"public_deps",
"publishable",
"source_dir",
])
public_configs = [ ":$library.config" ]
if (!is_prebuilt) {
configs += [ "//build/unification/config:zircon-library" ]
if (defined(invoker.disable_ubsan) && invoker.disable_ubsan) {
configs += [ "//build/config:temporarily_disable_ubsan_do_not_use" ]
}
if (defined(invoker.disable_unused_function) &&
invoker.disable_unused_function) {
configs += [ "//build/config:Wno-unused-function" ]
}
if (defined(invoker.disable_sanitizers) && invoker.disable_sanitizers) {
configs += [ "//build/config:no_sanitizers" ]
}
defines = invoker.compilation_defines
} else {
not_needed(invoker, [ "compilation_defines" ])
}
deps = library_deps
public_deps = library_public_deps
if (!is_fuchsia) {
public_deps += [ "//zircon/system/public" ]
}
metadata = {
}
if (zx_lib_dirs != []) {
metadata.zircon_lib_dirs = zx_lib_dirs
}
if (has_runtime_dep) {
if (!defined(data_deps)) {
data_deps = []
}
data_deps += [ ":$runtime_target" ]
}
# TODO(fxb/41298): This is a temporary change to activate writing the
# v1 FIDL wire-format selectively. Remove this when all bindings start
# writing v1 wire-format by default.
if (library == "fidl_base" && type == "static_library" &&
fidl_write_v1_wireformat) {
if (!defined(defines)) {
defines = []
}
defines += [ "FIDL_EXPERIMENTAL_WRITE_V1_WIREFORMAT" ]
}
if (!is_prebuilt) {
if (!defined(defines)) {
defines = []
}
defines += [ "_ALL_SOURCE" ]
}
# Manually add data dependencies.
# That information is not available in the metadata provided by the ZN
# build, so we manually replicate it here.
if (!defined(data_deps)) {
data_deps = []
}
if (library == "hermetic-decompressor") {
data_deps += [
"//build/unification/data:hermetic.decompress-lz4f",
"//build/unification/data:hermetic.decompress-zstd",
]
}
if (library == "fs-management") {
data_deps += [
"//zircon/third_party/uapp/fsck-msdosfs",
"//zircon/third_party/uapp/mkfs-msdosfs",
"//zircon/system/uapp/blobfs",
"//zircon/system/uapp/minfs",
]
}
# Tests migrated from the Zircon build depend on libraries exposed in
# //zircon/public/lib. However, these tests cannot be marked as "testonly"
# for legacy reasons (in short: the -many- targets that transitively depend
# on them via manifests are not testonly). Rather than introduce a huge
# number of testonly markers everywhere, we disable it here, knowing that
# we can and should reintroduce it when these libraries are migrated away
# from the Zircon build. This seems like an acceptable compromise given that
# the vast majority of these libraries do not have the marker anyways.
testonly = false
}
if (defined(invoker.publishable) && invoker.publishable) {
verify_pragma_once("$library-cpp_pragma") {
headers = library_headers
}
lib_to_extract_symbols = ""
foreach(file, invoker.install) {
if (get_path_info(file.dest, "dir") == "lib") {
# TODO(DX-688): formulate a policy around and handle static archives
if (get_path_info(file.dest, "extension") != "a") {
assert(lib_to_extract_symbols == "",
"There should be only one entry under lib")
lib_to_extract_symbols = file.source
}
}
}
if (lib_to_extract_symbols != "") {
lib_name = library
generated_symbols_file = "$target_gen_dir/$lib_name.symbols.api"
reference_symbols_file = "//sdk/lib/$lib_name/$lib_name.symbols.api"
extract_public_symbols("$library-extract_public_symbols") {
library = rebase_path(lib_to_extract_symbols, "", zircon_root_build_dir)
# No dependencies, since all of Zircon has been built
symbols = generated_symbols_file
}
verify_public_symbols("$library-verify_public_symbols") {
current = generated_symbols_file
reference = reference_symbols_file
library_name = "(zircon) ${lib_name}"
deps = [ ":$library-extract_public_symbols" ]
}
}
is_shared = false
if (invoker.install != []) {
_debug = invoker.debug
installed_binaries = {
if (_debug != []) {
assert(_debug == [ _debug[0] ])
debug = rebase_path(_debug[0], "", zircon_root_build_dir)
}
}
foreach(file, invoker.install) {
if (get_path_info(file.dest, "dir") == "dist") {
installed_binaries.dist = "arch/$target_cpu/${file.dest}"
file_name = get_path_info(file.dest, "file")
installed_binaries.dist_path = "lib/$file_name"
} else if (get_path_info(file.dest, "dir") == "lib") {
installed_binaries.link = "arch/$target_cpu/${file.dest}"
}
}
is_shared = get_path_info(installed_binaries.link, "extension") == "so"
}
_sdk_deps = []
if (!is_shared && defined(invoker.deps)) {
_sdk_deps += invoker.deps
}
if (defined(invoker.public_deps)) {
_sdk_deps += invoker.public_deps
}
# De-duplicate.
sdk_deps = []
foreach(label, _sdk_deps) {
sdk_deps += [ label ]
sdk_deps -= [ label ]
sdk_deps += [ label ]
}
_lib_deps = []
_fidl_deps = []
_banjo_deps = []
foreach(label, sdk_deps) {
if (get_path_info(get_path_info(label, "dir"), "name") == "fidl") {
_fidl_deps += [ get_path_info(get_label_info(label, "dir"), "name") ]
} else if (get_path_info(get_path_info(label, "dir"), "name") ==
"banjo") {
_banjo_deps += [ get_path_info(get_label_info(label, "dir"), "name") ]
} else {
_lib_deps += [ get_path_info(get_label_info(label, "dir"), "name") ]
}
}
# Zircon targets depend explicitly on $zx/system/ulib/zircon, but in
# legacy Fuchsia GN there is no //zircon/public/lib/zircon and instead
# it's available implicitly in the sysroot via `libs = [ "zircon" ]`.
# zircon-internal is a header-only library used by some static libraries.
_lib_deps += [
"zircon",
"zircon-internal",
]
_lib_deps -= [
"zircon",
"zircon-internal",
]
pkg = "pkg/$library"
sdk_metadata = {
name = library
root = pkg
if (defined(invoker.sources)) {
type = "cc_source_library"
} else {
type = "cc_prebuilt_library"
}
include_dir = "$pkg/include"
headers = rebase_path(invoker.headers, "//", "//$pkg/include")
if (defined(invoker.sources)) {
sources = rebase_path(rebase_path(invoker.sources, invoker.source_dir),
"//",
"//$pkg")
}
deps = _lib_deps
if (invoker.install == []) {
banjo_deps = _banjo_deps
fidl_deps = _fidl_deps
} else {
not_needed([
"_banjo_deps",
"_fidl_deps",
])
if (is_shared) {
format = "shared"
} else if (get_path_info(installed_binaries.link, "extension") == "a") {
format = "static"
}
binaries = {
if (target_cpu == "arm64") {
arm64 = installed_binaries
} else if (target_cpu == "x64") {
x64 = installed_binaries
}
}
}
}
sdk_atom("${library}_sdk") {
id = "sdk://pkg/$library"
category = "partner"
meta = {
dest = "$pkg/meta.json"
schema = sdk_metadata.type
if (invoker.debug == []) {
value = sdk_metadata
} else {
source = "$target_out_dir/$library.meta.out.json"
}
}
non_sdk_deps = [ ":$library-cpp_pragma" ]
if (lib_to_extract_symbols != "") {
non_sdk_deps += [ ":$library-verify_public_symbols" ]
}
if (invoker.debug != []) {
non_sdk_deps += [ ":$library-meta" ]
file_list = "$target_out_dir/$library.debug.manifest"
}
deps = []
foreach(dep, _sdk_deps) {
if (dep != "//zircon/public/lib/zircon" &&
dep != "//zircon/public/lib/zircon-internal") {
full_label = get_label_info(dep, "label_no_toolchain")
sdk_dep = "${full_label}_sdk"
deps += [ sdk_dep ]
}
}
files = []
api_contents = []
foreach(file, library_headers) {
api_contents += [
{
source = file
dest = "$pkg/include/" + rebase_path(file, include[0])
},
]
}
files += api_contents
if (api_contents != []) {
api = "//sdk/lib/$library/$library.api"
}
if (defined(invoker.sources)) {
foreach(file, invoker.sources) {
files += [
{
source = file
dest = "$pkg/" + rebase_path(file, invoker.source_dir)
},
]
}
}
foreach(file, invoker.install) {
files += [
{
source = rebase_path(file.source, "", zircon_root_build_dir)
dest = "arch/$target_cpu/${file.dest}"
},
]
}
}
if (invoker.debug != []) {
write_file("$target_gen_dir/$library.meta.in.json", sdk_metadata, "json")
action("$library-meta") {
visibility = [ ":*" ]
script = "//build/zircon/sdk_build_id.py"
sources = [ "$target_gen_dir/$library.meta.in.json" ]
outputs = [
"$target_out_dir/$library.meta.out.json",
"$target_out_dir/$library.debug.manifest",
]
args = [
"--input=" + rebase_path(sources[0], root_build_dir),
"--output=" + rebase_path(outputs[0], root_build_dir),
"--manifest=" + rebase_path(outputs[1], root_build_dir),
"--location=/binaries/$target_cpu/debug",
]
}
}
} else {
not_needed([ "library_headers" ])
} # defined(invoker.publishable) && invoker.publishable
}