mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-20 13:51:05 +00:00
6166322c2e
- Make the pw_build_LINK_DEPS check in pw_assert a generic feature in pw_facade. - Use "impl" instead of "deps" for the pw_assert dependencies and restructure the impl / backend split. Change-Id: I75c0f7e67b3b97bfe333760897223ab4601649c0 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/43980 Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com> Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com> Reviewed-by: Ewout van Bekkum <ewout@google.com> Reviewed-by: Armando Montanez <amontanez@google.com>
187 lines
7.1 KiB
Plaintext
187 lines
7.1 KiB
Plaintext
# 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.
|
|
|
|
import("//build_overrides/pigweed.gni")
|
|
|
|
import("$dir_pw_build/error.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.
|
|
#
|
|
# pw_facade creates two targets:
|
|
#
|
|
# $target_name: The public-facing pw_source_set that provides the API and
|
|
# implementation (backend). Users of the facade should depend on this.
|
|
# $target_name.facade: A private source_set that provides ONLY the API. ONLY
|
|
# backends should depend on this.
|
|
#
|
|
# If the target name matches the directory name (e.g. //foo:foo), a ":facade"
|
|
# alias of the facade target (e.g. //foo:facade) is also provided. This avoids
|
|
# the need to repeat the directory name, for consistency with the main target.
|
|
#
|
|
# The facade's headers are split out into the *.facade target to avoid circular
|
|
# dependencies. Here's a concrete example to illustrate why this is needed:
|
|
#
|
|
# 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 = [ ":foo.facade" ]
|
|
# sources = [ "bar.cc" ]
|
|
# }
|
|
#
|
|
# This creates the following dependency graph:
|
|
#
|
|
# foo.facade <-.
|
|
# ^ \
|
|
# | \
|
|
# | \
|
|
# foo ----------> foo_backend_bar
|
|
#
|
|
# This allows foo_backend_bar to include "foo.h". If you tried to directly
|
|
# depend on `foo` from `foo_backend_bar`, you'd get a dependency cycle error in
|
|
# GN.
|
|
#
|
|
# Accepts the standard pw_source_set args with the following additions:
|
|
#
|
|
# Args:
|
|
# backend: (required) The dependency that implements this facade (a GN
|
|
# variable)
|
|
# public: (required) The headers exposed by this facade. A facade acts as a
|
|
# tool to break dependency cycles that come from the backend trying to
|
|
# include headers from the facade itself. If the facade doesn't expose any
|
|
# headers, it's basically the same as just depending directly on the build
|
|
# arg that `backend` is set to.
|
|
# require_link_deps: A list of build targets that must be included in
|
|
# pw_build_LINK_DEPS if this facade is used. This mechanism is used to
|
|
# avoid circular dependencies in low-level facades like pw_assert.
|
|
#
|
|
template("pw_facade") {
|
|
assert(defined(invoker.backend),
|
|
"pw_facade requires a reference to a backend variable for the facade")
|
|
assert(defined(invoker.public),
|
|
"If your facade does not explicitly expose an API that a backend " +
|
|
"must depend on, you can just directly depend on the build arg " +
|
|
"that the `backend` template argument would have been set to.")
|
|
|
|
_facade_name = "$target_name.facade"
|
|
|
|
if (get_path_info(get_label_info(":$target_name", "dir"), "name") ==
|
|
get_label_info(":$target_name", "name")) {
|
|
group("facade") {
|
|
public_deps = [ ":$_facade_name" ]
|
|
}
|
|
}
|
|
|
|
_facade_vars = [
|
|
# allow_circular_includes_from should very rarely be used, but when it is,
|
|
# it only applies to headers, so should be in the .facade target.
|
|
"allow_circular_includes_from",
|
|
"public_configs",
|
|
"public_deps",
|
|
"public",
|
|
]
|
|
pw_source_set(_facade_name) {
|
|
forward_variables_from(invoker, _facade_vars, [ "require_link_deps" ])
|
|
}
|
|
|
|
if (invoker.backend == "") {
|
|
# Try to guess the name of the facade's backend variable.
|
|
_dir = get_path_info(get_label_info(":$target_name", "dir"), "name")
|
|
if (target_name == _dir) {
|
|
_varname = target_name + "_BACKEND"
|
|
} else {
|
|
# There is no way to capitalize this string in GN, so use <FACADE_NAME>
|
|
# instead of the lowercase target name.
|
|
_varname = _dir + "_<FACADE_NAME>_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.
|
|
pw_error(target_name + ".NO_BACKEND_SET") {
|
|
_label = get_label_info(":${invoker.target_name}", "label_no_toolchain")
|
|
message_lines = [
|
|
"Attempted to build the $_label facade with no backend.",
|
|
"",
|
|
"If you are using this facade, ensure you have configured a backend ",
|
|
"properly. The build arg for the facade must be set to a valid ",
|
|
"backend in the toolchain. For example, you may need to add a line ",
|
|
"like the following to the toolchain's .gni file:",
|
|
"",
|
|
" $_varname = \"//path/to/the:backend\"",
|
|
"",
|
|
"If you are NOT using this facade, this error may have been triggered ",
|
|
"by trying to build all targets.",
|
|
]
|
|
}
|
|
}
|
|
|
|
# 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 = _facade_vars + [
|
|
"backend",
|
|
"require_link_deps",
|
|
]
|
|
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 += [ ":$target_name.NO_BACKEND_SET" ]
|
|
}
|
|
}
|
|
|
|
if (defined(invoker.require_link_deps) && invoker.backend != "") {
|
|
# Check that the specified labels are listed in pw_build_LINK_DEPS. This
|
|
# ensures these dependencies are available during linking, even if nothing
|
|
# else in the build depends on them.
|
|
foreach(label, invoker.require_link_deps) {
|
|
_required_dep = get_label_info(label, "label_no_toolchain")
|
|
_dep_is_in_link_dependencies = false
|
|
|
|
foreach(link_dep, pw_build_LINK_DEPS) {
|
|
if (get_label_info(link_dep, "label_no_toolchain") == _required_dep) {
|
|
_dep_is_in_link_dependencies = true
|
|
}
|
|
}
|
|
|
|
_facade_name = get_label_info(":$target_name", "label_no_toolchain")
|
|
assert(_dep_is_in_link_dependencies,
|
|
"$_required_dep must be listed in the pw_build_LINK_DEPS build " +
|
|
"arg when the $_facade_name facade is in use. Please update " +
|
|
"your toolchain configuration.")
|
|
}
|
|
} else {
|
|
not_needed(invoker, [ "require_link_deps" ])
|
|
}
|
|
}
|