blob: 952a94d107ef8e22238bc2f933c4557f1ca7db34 [file] [log] [blame]
# Copyright 2018 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/verify_pragma_once.gni")
import("//build/sdk/sdk_atom.gni")
# A source set that can be exported to an SDK.
#
# An equivalent to the built-in source_set which adds an SDK atom declaration to
# allow the set to be included in an SDK as sources.
#
# Parameters
#
# category (required)
# Publication level of the library in SDKs.
# See //build/sdk/sdk_atom.gni.
#
# api (optional)
# Path to the file representing the API of this library.
# This file is used to ensure modifications to the library's API are
# explicitly acknowledged. It is mandatory for publication categories of
# "partner" or "public".
# Defaults to "<SDK name>.api".
#
# sdk_name (required)
# Name of the library in the SDK.
#
# source_dir (optional)
# If set, path to the base directory of the sources.
# This is useful if the sources are generated and therefore not hosted
# directly under the directory where the GN rules are declared.
#
# include_base (optional)
# Path to the root directory for includes.
# Defaults to "include".
#
# build_as_static (optional)
# Whether the sources should be exposed as a static library.
# This is mostly used in the transition of Zircon libraries to the GN build.
# Defaults to false.
#
# non_sdk_deps (optional)
# List of dependencies that should not be reflected in SDKs.
# Mostly useful for code generation.
#
# extra_headers [optional]
# List of header files that are part of the SDK headers for the library
# but that must not be exposed as part of the Fuchsia build. This must ONLY
# be used as a work-around for https://fxbug.dev/60129.
#
template("sdk_source_set") {
assert(defined(invoker.category), "Must define an SDK category")
assert(defined(invoker.sdk_name), "Must define an SDK name")
if (invoker.category == "partner" || invoker.category == "public") {
api_reference = "${invoker.sdk_name}.api"
if (defined(invoker.api)) {
api_reference = invoker.api
}
}
main_target_name = target_name
sdk_target_name = "${target_name}_sdk"
target_type = "source_set"
if (defined(invoker.build_as_static) && invoker.build_as_static) {
target_type = "static_library"
}
target(target_type, main_target_name) {
forward_variables_from(invoker,
"*",
[
"api",
"category",
"include_base",
"non_sdk_deps",
"sdk_name",
"source_dir",
])
if (defined(visibility)) {
visibility += [ ":$sdk_target_name" ]
}
# Ensure this sdk_source_set() is instrumented for coverage when
# building in the 'coverage-sdk' build variant.
if (toolchain_variant.name == "coverage-sdk") {
configs += [ "//build/config/profile:coverage-sdk-source-config" ]
}
}
# Identify dependencies and their metadata files.
sdk_metas = []
sdk_deps = []
all_deps = []
if (defined(invoker.deps)) {
all_deps += invoker.deps
}
if (defined(invoker.public_deps)) {
all_deps += invoker.public_deps
}
foreach(dep, all_deps) {
full_label = get_label_info(dep, "label_no_toolchain")
sdk_dep = "${full_label}_sdk"
sdk_deps += [ sdk_dep ]
gen_dir = get_label_info(sdk_dep, "target_gen_dir")
name = get_label_info(sdk_dep, "name")
sdk_metas += [ rebase_path("$gen_dir/$name.meta.json") ]
}
# Sort headers vs. sources.
all_headers = []
all_sources = []
source_headers_are_public = true
if (defined(invoker.public)) {
source_headers_are_public = false
all_headers += invoker.public
}
if (defined(invoker.sources)) {
foreach(source_file, invoker.sources) {
extension = get_path_info(source_file, "extension")
if (extension == "h" && source_headers_are_public) {
all_headers += [ source_file ]
} else {
all_sources += [ source_file ]
}
}
not_needed([ "source_headers_are_public" ])
} else {
not_needed([ "source_headers_are_public" ])
}
if (defined(invoker.extra_headers)) {
all_headers += invoker.extra_headers
}
# Determine destinations in the SDK for headers and sources.
file_base = "pkg/${invoker.sdk_name}"
sdk_metadata_headers = []
sdk_metadata_sources = []
sdk_header_files = []
sdk_files = []
foreach(header, all_headers) {
include_base = "include"
if (defined(invoker.include_base)) {
include_base = invoker.include_base
}
relative_destination = rebase_path(header, include_base)
destination = "$file_base/include/$relative_destination"
sdk_metadata_headers += [ destination ]
sdk_header_files += [
{
source = header
dest = destination
},
]
}
sdk_files += sdk_header_files
foreach(source, all_sources) {
sdk_metadata_sources += [ "$file_base/$source" ]
sdk_files += [
{
source = source
dest = "$file_base/$source"
},
]
}
verify_pragma_target_name = "${target_name}_sdk_pragma"
verify_pragma_once(verify_pragma_target_name) {
headers = all_headers
}
metadata_target_name = "${target_name}_sdk_metadata"
metadata_file = "$target_gen_dir/$target_name.sdk_meta.json"
action(metadata_target_name) {
script = "//build/cpp/gen_sdk_sources_meta_file.py"
inputs = sdk_metas
outputs = [ metadata_file ]
args = [
"--out",
rebase_path(metadata_file),
"--name",
invoker.sdk_name,
"--root",
file_base,
"--include-dir",
"$file_base/include",
]
args += [ "--deps" ] + sdk_metas
args += [ "--sources" ] + sdk_metadata_sources
args += [ "--headers" ] + sdk_metadata_headers
deps = sdk_deps
}
sdk_atom(sdk_target_name) {
forward_variables_from(invoker,
[
"source_dir",
"testonly",
])
id = "sdk://pkg/${invoker.sdk_name}"
category = invoker.category
if (defined(api_reference)) {
api = api_reference
api_contents = sdk_header_files
}
meta = {
source = metadata_file
dest = "$file_base/meta.json"
schema = "cc_source_library"
}
files = sdk_files
deps = sdk_deps
non_sdk_deps = [
":$main_target_name",
":$metadata_target_name",
":$verify_pragma_target_name",
]
# Explicitly add non-public dependencies, in case some of the source files
# are generated.
if (defined(invoker.non_sdk_deps)) {
non_sdk_deps += invoker.non_sdk_deps
}
metadata = {
# Used by the //sdk:sdk_source_set_list build API module.
sdk_source_set_sources = rebase_path(all_sources + all_headers, "//")
}
}
}
set_defaults("sdk_source_set") {
configs = default_common_binary_configs
}