xref: /aosp_15_r20/build/bazel/rules/cc/cc_xsd_config_library.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1# Copyright (C) 2023 The Android Open Source Project
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#     http://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
15load("@bazel_skylib//lib:paths.bzl", "paths")
16load(":cc_library_common.bzl", "create_ccinfo_for_includes")
17load(":cc_library_static.bzl", "cc_library_static")
18
19# Return the relative directory where the cpp files should be generated
20def _cpp_gen_dir(ctx):
21    return ctx.attr.name
22
23# Return the relative directory where the h files should be generated
24def _h_gen_dir(ctx):
25    return paths.join(
26        _cpp_gen_dir(ctx),
27        "include",
28    )
29
30def _cc_xsdc_args(ctx):
31    args = ctx.actions.args()
32    args.add(ctx.file.src)
33    args.add("-p", ctx.attr.package_name)
34    args.add("-c")  # Generate cpp sources
35
36    if ctx.attr.gen_writer:
37        args.add("-w")
38
39    if ctx.attr.enums_only:
40        args.add("-e")
41
42    if ctx.attr.parser_only:
43        # parser includes the enum.h file so generate both
44        # in the wrapper cc_static_library, we will only include the .o file of the parser
45        pass
46
47    if ctx.attr.boolean_getter:
48        args.add("-b")
49
50    if ctx.attr.tinyxml:
51        args.add("-t")
52
53    for root_element in ctx.attr.root_elements:
54        args.add("-r", root_element)
55
56    return args
57
58# Returns a tuple of cpp and h filenames that should be generated
59def _cc_xsdc_outputs(ctx):
60    filename_stem = ctx.attr.package_name.replace(".", "_")
61    parser_cpp = filename_stem + ".cpp"
62    parser_h = filename_stem + ".h"
63    enums_cpp = filename_stem + "_enums.cpp"
64    enums_h = filename_stem + "_enums.h"
65    if ctx.attr.parser_only:
66        # parser_cpp includes enums_h, so we need to return both .h files
67        return [parser_cpp], [parser_h, enums_h]
68    elif ctx.attr.enums_only:
69        return [enums_cpp], [enums_h]
70
71    # Default: Generate both parser and enums
72    return [parser_cpp, enums_cpp], [parser_h, enums_h]
73
74def _cc_xsd_codegen_impl(ctx):
75    outputs_cpp, outputs_h = [], []
76    cpp_filenames, h_filenames = _cc_xsdc_outputs(ctx)
77
78    # Declare the cpp files
79    for cpp_filename in cpp_filenames:
80        outputs_cpp.append(
81            ctx.actions.declare_file(
82                paths.join(
83                    _cpp_gen_dir(ctx),
84                    cpp_filename,
85                ),
86            ),
87        )
88
89    # Declare the h files
90    for h_filename in h_filenames:
91        outputs_h.append(
92            ctx.actions.declare_file(
93                paths.join(
94                    _h_gen_dir(ctx),
95                    h_filename,
96                ),
97            ),
98        )
99
100    args = _cc_xsdc_args(ctx)
101
102    # Pass the output directory
103    args.add("-o", outputs_cpp[0].dirname)
104
105    ctx.actions.run(
106        executable = ctx.executable._xsdc,
107        inputs = [ctx.file.src] + ctx.files.include_files,
108        outputs = outputs_cpp + outputs_h,
109        arguments = [args],
110        mnemonic = "XsdcCppCompile",
111    )
112
113    return [
114        DefaultInfo(
115            # Return the CPP files.
116            # Skip headers since rdep does not compile headers.
117            files = depset(outputs_cpp),
118        ),
119        create_ccinfo_for_includes(
120            ctx,
121            hdrs = outputs_h,
122            includes = [_h_gen_dir(ctx)],
123        ),
124    ]
125
126_cc_xsd_codegen = rule(
127    implementation = _cc_xsd_codegen_impl,
128    doc = "This rule generates .cpp/.h files from an xsd file using xsdc",
129    attrs = {
130        "src": attr.label(
131            allow_single_file = [".xsd"],
132            doc = "The main xsd file",
133            mandatory = True,
134        ),
135        "include_files": attr.label_list(
136            allow_files = [".xsd"],
137            doc = "The (transitive) xsd files included by `src` using xs:include",
138        ),
139        "package_name": attr.string(
140            doc = "Namespace to use in the generated .cpp file",
141            mandatory = True,
142        ),
143        "gen_writer": attr.bool(
144            doc = "Add xml writer to the generated .cpp file",
145        ),
146        "enums_only": attr.bool(),
147        "parser_only": attr.bool(),
148        "boolean_getter": attr.bool(
149            doc = "Whether getter name of boolean element or attribute is getX or isX. If true, getter name is isX",
150            default = False,
151        ),
152        "tinyxml": attr.bool(
153            doc = "Generate code that uses libtinyxml2 instead of libxml2",
154            default = False,
155        ),
156        "root_elements": attr.string_list(
157            doc = "If set, xsdc will generate parser code only for the specified root elements",
158        ),
159        "_xsdc": attr.label(
160            executable = True,
161            cfg = "exec",
162            default = Label("//system/tools/xsdc"),
163        ),
164    },
165    provides = [
166        CcInfo,
167    ],
168)
169
170def cc_xsd_config_library(
171        name,
172        src,
173        include_files = [],
174        package_name = "",
175        gen_writer = False,
176        enums_only = False,
177        parser_only = False,
178        boolean_getter = False,
179        tinyxml = False,
180        root_elements = [],
181        deps = [],
182        implementation_dynamic_deps = [],
183        **kwargs):
184    """
185    Generate .cpp/.h sources from .xsd file using xsdc and wrap it in a cc_static_library.
186
187    """
188    _gen = name + "_gen"
189
190    _cc_xsd_codegen(
191        name = _gen,
192        src = src,
193        include_files = include_files,
194        package_name = package_name,
195        gen_writer = gen_writer,
196        enums_only = enums_only,
197        parser_only = parser_only,
198        boolean_getter = boolean_getter,
199        tinyxml = tinyxml,
200        root_elements = root_elements,
201        **kwargs
202    )
203
204    cc_library_static(
205        name = name,
206        srcs = [_gen],
207        deps = deps + [_gen],  # Generated hdrs
208        implementation_dynamic_deps = implementation_dynamic_deps,
209        **kwargs
210    )
211