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 16load("@rules_cc//cc:cc_library.bzl", "cc_library") 17 18def pw_facade(name, srcs = None, backend = None, **kwargs): 19 """Create a cc_library with a facade. 20 21 This macro simplifies instantiating Pigweed's facade pattern. It generates 22 two targets: 23 24 * cc_library with the label "name". This is the complete library target. 25 Users of the functionality provided by this library should depend on this 26 target. It has a public dependency on the "backend". 27 * cc_library with the label "name.facade". This library exposes only the 28 headers. Implementations of the backend should depend on it. 29 30 Args: 31 name: The name of the cc_library. 32 srcs: The source files of the cc_library. 33 backend: The backend for the facade. This should be a label_flag or other 34 target that allows swapping out the backend implementation at build 35 time. (In a downstream project an alias with an "actual = select(...)" 36 attribute may also be appropriate, but in upstream Pigweed use only a 37 label_flag.). 38 **kwargs: Passed on to cc_library. 39 """ 40 if type(backend) != "string": 41 fail( 42 "The 'backend' attribute must be a single label, " + 43 "got {} of type {}".format(backend, type(backend)), 44 ) 45 46 facade_kwargs = dict(**kwargs) 47 48 # A facade has no srcs, so it can only have public deps. Don't specify any 49 # implementation_deps on the facade target. 50 facade_kwargs.pop("implementation_deps", []) 51 cc_library( 52 name = name + ".facade", 53 # The .facade target is not self-contained (it's missing a dependency 54 # on the backend headers), so it can't be successfully clang-tidied. 55 # "no-clang-tidy-headers" is a special tag defined in bazel_clang_tidy 56 # that exempts a build target's headers from tidying; see 57 # https://github.com/erenon/bazel_clang_tidy/pull/76. 58 tags = facade_kwargs.pop("tags", []) + ["no-clang-tidy-headers"], 59 **facade_kwargs 60 ) 61 62 kwargs["deps"] = kwargs.get("deps", []) + [backend] 63 cc_library( 64 name = name, 65 srcs = srcs, 66 **kwargs 67 ) 68