xref: /aosp_15_r20/external/emboss/build_defs.bzl (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1# Copyright 2019 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of 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,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# -*- mode: python; -*-
16# vim:set ft=blazebuild:
17"""Build defs for Emboss.
18
19This file exports emboss_library, which creates an Emboss library, and
20cc_emboss_library, which creates a header file and can be used as a dep in a
21`cc_library`, `cc_binary`, or `cc_test` rule.
22
23There is also a convenience macro, `emboss_cc_library()`, which creates an
24`emboss_library` and a `cc_emboss_library` based on it.
25"""
26
27load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
28
29def emboss_cc_library(name, srcs, deps = [], visibility = None, import_dirs = [], enable_enum_traits = True, **kwargs):
30    """Constructs a C++ library from an .emb file."""
31    if len(srcs) != 1:
32        fail(
33            "Must specify exactly one Emboss source file for emboss_cc_library.",
34            "srcs",
35        )
36
37    emboss_library(
38        name = name + "_ir",
39        srcs = srcs,
40        deps = [dep + "_ir" for dep in deps],
41        import_dirs = import_dirs,
42        **kwargs
43    )
44
45    cc_emboss_library(
46        name = name,
47        deps = [":" + name + "_ir"],
48        visibility = visibility,
49        enable_enum_traits = enable_enum_traits,
50        **kwargs
51    )
52
53# Full Starlark rules for emboss_library and cc_emboss_library.
54#
55# This implementation is loosely based on the proto_library and
56# cc_proto_library rules that are included with Bazel.
57
58EmbossInfo = provider(
59    doc = "Encapsulates information provided by a `emboss_library.`",
60    fields = {
61        "direct_source": "(File) The `.emb` source files from the `srcs`" +
62                         " attribute.",
63        "transitive_sources": "(depset[File]) The `.emb` files from `srcs` " +
64                              "and all `deps`.",
65        "transitive_roots": "(list[str]) The root paths for all " +
66                            "transitive_sources.",
67        "direct_ir": "(list[File]) The `.emb.ir` files generated from the " +
68                     "`srcs`.",
69        "transitive_ir": "(depset[File]) The `.emb.ir` files generated from " +
70                         "transitive_srcs.",
71    },
72)
73
74def _emboss_library_impl(ctx):
75    deps = [dep[EmbossInfo] for dep in ctx.attr.deps]
76    outs = []
77    if len(ctx.attr.srcs) != 1:
78        fail("`srcs` attribute must contain exactly one label.", attr = "srcs")
79    src = ctx.files.srcs[0]
80    out = ctx.actions.declare_file(src.basename + ".ir", sibling = src)
81    outs.append(out)
82    inputs = depset(
83        direct = [src],
84        transitive = [dep.transitive_sources for dep in deps],
85    )
86
87    # If the file is in an external repo, we want to use the path to that repo
88    # as the root (e.g. ./external/my-repo) so that import paths are resolved
89    # relative to the external repo root.
90    fixed_src_root = src.root.path
91    if src.path.startswith("external/"):
92        path_segments = src.path.split("/")[:2]
93        fixed_src_root = "/".join(path_segments)
94
95    transitive_roots = depset(
96        direct = [fixed_src_root],
97        transitive = [dep.transitive_roots for dep in deps],
98    )
99
100    imports = ["--import-dir=" + root for root in transitive_roots.to_list()]
101    imports_arg = ["--import-dir=" + impt.path for impt in ctx.files.import_dirs]
102    ctx.actions.run(
103        inputs = inputs.to_list(),
104        outputs = [out],
105        arguments = [src.path, "--output-file=" + out.path] + imports + imports_arg,
106        executable = ctx.executable._emboss_compiler,
107    )
108    transitive_sources = depset(
109        direct = [src],
110        transitive = [dep.transitive_sources for dep in deps],
111    )
112    transitive_ir = depset(
113        direct = outs,
114        transitive = [dep.transitive_ir for dep in deps],
115    )
116    return [
117        EmbossInfo(
118            direct_source = src,
119            transitive_sources = transitive_sources,
120            transitive_roots = transitive_roots,
121            direct_ir = outs,
122            transitive_ir = transitive_ir,
123        ),
124        DefaultInfo(
125            files = depset(outs),
126        ),
127    ]
128
129emboss_library = rule(
130    _emboss_library_impl,
131    attrs = {
132        "srcs": attr.label_list(
133            allow_files = [".emb"],
134        ),
135        "deps": attr.label_list(
136            providers = [EmbossInfo],
137        ),
138        "import_dirs": attr.label_list(
139            allow_files = True,
140        ),
141        "licenses": attr.license() if hasattr(attr, "license") else attr.string_list(),
142        "_emboss_compiler": attr.label(
143            executable = True,
144            cfg = "exec",
145            allow_files = True,
146            default = Label(
147                "@com_google_emboss//compiler/front_end:emboss_front_end",
148            ),
149        ),
150    },
151    provides = [EmbossInfo],
152)
153
154EmbossCcHeaderInfo = provider(
155    fields = {
156        "headers": "(list[File]) The `.emb.h` headers from this rule.",
157        "transitive_headers": "(list[File]) The `.emb.h` headers from this " +
158                              "rule and all dependencies.",
159    },
160    doc = "Provide cc emboss headers.",
161)
162
163def _cc_emboss_aspect_impl(target, ctx):
164    cc_toolchain = find_cpp_toolchain(ctx, mandatory = True)
165    emboss_cc_compiler = ctx.executable._emboss_cc_compiler
166    emboss_info = target[EmbossInfo]
167    feature_configuration = cc_common.configure_features(
168        ctx = ctx,
169        cc_toolchain = cc_toolchain,
170        requested_features = list(ctx.features),
171        unsupported_features = list(ctx.disabled_features),
172    )
173    src = target[EmbossInfo].direct_source
174    headers = [ ctx.actions.declare_file( src.basename + ".h", sibling = src) ]
175    args = ctx.actions.args()
176    args.add("--input-file")
177    args.add_all(emboss_info.direct_ir)
178    args.add("--output-file")
179    args.add_all(headers)
180    if not ctx.attr.enable_enum_traits:
181      args.add("--no-cc-enum-traits")
182    ctx.actions.run(
183        executable = emboss_cc_compiler,
184        arguments = [args],
185        inputs = emboss_info.direct_ir,
186        outputs = headers,
187    )
188    runtime_cc_info = ctx.attr._emboss_cc_runtime[CcInfo]
189    transitive_headers = depset(
190        direct = headers,
191        transitive = [
192                         dep[EmbossCcHeaderInfo].transitive_headers
193                         for dep in ctx.rule.attr.deps
194                     ],
195    )
196    (cc_compilation_context, cc_compilation_outputs) = cc_common.compile(
197        name = ctx.label.name,
198        actions = ctx.actions,
199        feature_configuration = feature_configuration,
200        cc_toolchain = cc_toolchain,
201        public_hdrs = headers,
202        private_hdrs = transitive_headers.to_list(),
203        compilation_contexts = [runtime_cc_info.compilation_context],
204    )
205    return [
206        CcInfo(compilation_context = cc_compilation_context),
207        EmbossCcHeaderInfo(
208            headers = depset(headers),
209            transitive_headers = transitive_headers,
210        ),
211    ]
212
213_cc_emboss_aspect = aspect(
214    implementation = _cc_emboss_aspect_impl,
215    attr_aspects = ["deps"],
216    fragments = ["cpp"],
217    required_providers = [EmbossInfo],
218    attrs = {
219        "_cc_toolchain": attr.label(
220            default = "@bazel_tools//tools/cpp:current_cc_toolchain",
221        ),
222        "_emboss_cc_compiler": attr.label(
223            executable = True,
224            cfg = "exec",
225            default = "@com_google_emboss//compiler/back_end/cpp:emboss_codegen_cpp",
226        ),
227        "_emboss_cc_runtime": attr.label(
228            default = "@com_google_emboss//runtime/cpp:cpp_utils",
229        ),
230        "enable_enum_traits": attr.bool(
231            default = True,
232        ),
233    },
234    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
235)
236
237def _cc_emboss_library_impl(ctx):
238    if len(ctx.attr.deps) != 1:
239        fail("`deps` attribute must contain exactly one label.", attr = "deps")
240    dep = ctx.attr.deps[0]
241    return [
242        dep[CcInfo],
243        dep[EmbossInfo],
244        DefaultInfo(files = dep[EmbossCcHeaderInfo].headers),
245    ]
246
247cc_emboss_library = rule(
248    implementation = _cc_emboss_library_impl,
249    attrs = {
250        "deps": attr.label_list(
251            aspects = [_cc_emboss_aspect],
252            allow_rules = ["emboss_library"],
253            allow_files = False,
254        ),
255        "enable_enum_traits": attr.bool(
256            default = True,
257        ),
258    },
259    provides = [CcInfo, EmbossInfo],
260)
261