xref: /aosp_15_r20/external/pigweed/pw_build/pw_facade.bzl (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Bazel rules for declaring Pigweed facade interface layers."""
15
16def pw_facade(name, srcs = None, backend = None, **kwargs):
17    """Create a cc_library with a facade.
18
19    This macro simplifies instantiating Pigweed's facade pattern. It generates
20    two targets:
21
22    * cc_library with the label "name". This is the complete library target.
23      Users of the functionality provided by this library should depend on this
24      target.  It has a public dependency on the "backend".
25    * cc_library with the label "name.facade". This library exposes only the
26      headers. Implementations of the backend should depend on it.
27
28    Args:
29      name: The name of the cc_library.
30      srcs: The source files of the cc_library.
31      backend: The backend for the facade. This should be a label_flag or other
32        target that allows swapping out the backend implementation at build
33        time. (In a downstream project an alias with an "actual = select(...)"
34        attribute may also be appropriate, but in upstream Pigweed use only a
35        label_flag.).
36      **kwargs: Passed on to cc_library.
37    """
38    if type(backend) != "string":
39        fail(
40            "The 'backend' attribute must be a single label, " +
41            "got {} of type {}".format(backend, type(backend)),
42        )
43
44    facade_kwargs = dict(**kwargs)
45
46    # This is a workaround for layering_check, which appears to only allow
47    # two libraries to export the same headers if one lists it as textual_hdrs
48    # for unclear reasons (b/142314377#comment11).
49    facade_kwargs["textual_hdrs"] = facade_kwargs.pop("hdrs", [])
50
51    # TODO: https://github.com/bazelbuild/bazel/issues/12424 - Unfortunately,
52    # strip_include_prefix does not work correctly with textual_hdrs.
53    if "strip_include_prefix" in facade_kwargs:
54        facade_kwargs["includes"] = [facade_kwargs["strip_include_prefix"]]
55
56    # A facade has no srcs, so it can only have public deps. Don't specify any
57    # implementation_deps on the facade target.
58    facade_kwargs.pop("implementation_deps", [])
59    native.cc_library(
60        name = name + ".facade",
61        **facade_kwargs
62    )
63
64    kwargs["deps"] = kwargs.get("deps", []) + [backend]
65    native.cc_library(
66        name = name,
67        srcs = srcs,
68        **kwargs
69    )
70