blob: a5a51593ad2340cb87189451fd0a4b7209b4cf6a [file] [log] [blame]
# Copyright 2019 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
# gn-format disable
import("//build_overrides/pigweed.gni")
import("$dir_pw_build/python_script.gni")
import("$dir_pw_build/target_types.gni")
# Declare a facade.
#
# A Pigweed facade is an API layer that has a single implementation it must
# link against. Typically this will be done by pointing a build arg like
# `pw_[module]_BACKEND` at a backend implementation for that module.
#
# Example facade:
#
# pw_facade("module_name") {
# backend = dir_module_name_backend
# public_deps = [
# ":module_api_layer"
# ]
# }
#
# Args:
# - backend: the dependency that implements this facade
# - facade_name: (optional) The name to use for the facade target on which the
# backend depends. Only required when a module defines multiple facades.
# Defaults to "facade".
#
template("pw_facade") {
assert(defined(invoker.backend),
"pw_facade requires a reference to a backend variable for the facade")
if (defined(invoker.facade_name)) {
_facade_name = invoker.facade_name
} else {
_facade_name = "facade"
}
# A facade's headers are split into a separate target to avoid a circular
# dependency between the facade and the backend.
#
# For example, the following targets:
#
# foo_backend = "//foo:foo_backend_bar"
#
# pw_facade("foo") {
# backend = foo_backend
# public = [ "foo.h" ]
# sources = [ "foo.cc" ]
# }
#
# pw_source_set("foo_backend_bar") {
# deps = [ ":facade" ]
# sources = [ "bar.cc" ]
# }
#
# Create the following dependency graph:
#
# facade <-.
# ^ \
# | \
# | \
# foo ------> foo_backend_bar
#
_facade_vars = [
"public_configs",
"public_deps",
"public",
]
pw_source_set(_facade_name) {
forward_variables_from(invoker, _facade_vars)
}
if (invoker.backend == "") {
# If backend is not set to anything, create a script that emits an error.
# This will be added as a data dependency to the actual target, so that
# attempting to build the facade without a backend fails with a relevant
# error message.
_main_target_name = target_name
pw_python_script(_main_target_name + "_NO_BACKEND_SET") {
stamp = true
script = "$dir_pw_build/py/pw_build/null_backend.py"
args = [ _main_target_name ]
not_needed(invoker, "*")
}
}
# Create a target that defines the main facade library. Always emit this
# target, even if the backend isn't defined, so that the dependency graph is
# correctly expressed for gn check.
pw_source_set(target_name) {
# The main library contains everything else specified in the template.
_ignore_vars = [ "backend" ] + _facade_vars
forward_variables_from(invoker, "*", _ignore_vars)
public_deps = [ ":$_facade_name" ]
# If the backend is set, inject it as a dependency.
if (invoker.backend != "") {
public_deps += [ invoker.backend ]
} else {
# If the backend is not set, depend on the *_NO_BACKEND_SET target.
public_deps += [ ":$_main_target_name" + "_NO_BACKEND_SET" ]
}
}
}