| # 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/python_action.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. |
| # |
| # To avoid circular dependencies, pw_facade creates two targets: |
| # |
| # - $target_name: the public-facing pw_source_set |
| # - $target_name.facade: target used by the backend to avoid circular |
| # dependencies |
| # |
| # 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. |
| # |
| # Example facade: |
| # |
| # # Creates ":module_name" and ":module_name.facade" GN targets. |
| # pw_facade("module_name") { |
| # backend = dir_module_name_backend |
| # public_deps = [ |
| # ":module_api_layer" |
| # ] |
| # } |
| # |
| # Accepts the standard pw_source_set args with the following additions: |
| # |
| # - backend: the dependency that implements this facade (a GN variable) |
| # |
| template("pw_facade") { |
| assert(defined(invoker.backend), |
| "pw_facade requires a reference to a backend variable for the facade") |
| |
| _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" ] |
| } |
| } |
| |
| # For backwards compatibility, provide a _facade version of the name. |
| group(target_name + "_facade") { |
| public_deps = [ ":$_facade_name" ] |
| } |
| |
| # 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_action(_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" ] |
| } |
| } |
| } |