xref: /aosp_15_r20/build/bazel/rules/aidl/aidl_library.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1*7594170eSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project
2*7594170eSAndroid Build Coastguard Worker#
3*7594170eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*7594170eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*7594170eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*7594170eSAndroid Build Coastguard Worker#
7*7594170eSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*7594170eSAndroid Build Coastguard Worker#
9*7594170eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*7594170eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*7594170eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*7594170eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*7594170eSAndroid Build Coastguard Worker# limitations under the License.
14*7594170eSAndroid Build Coastguard Worker
15*7594170eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:paths.bzl", "paths")
16*7594170eSAndroid Build Coastguard Worker
17*7594170eSAndroid Build Coastguard WorkerAidlGenInfo = provider(
18*7594170eSAndroid Build Coastguard Worker    fields = [
19*7594170eSAndroid Build Coastguard Worker        "srcs",
20*7594170eSAndroid Build Coastguard Worker        "hdrs",
21*7594170eSAndroid Build Coastguard Worker        "hash_file",
22*7594170eSAndroid Build Coastguard Worker        "transitive_srcs",
23*7594170eSAndroid Build Coastguard Worker        "transitive_include_dirs",
24*7594170eSAndroid Build Coastguard Worker        "flags",
25*7594170eSAndroid Build Coastguard Worker    ],
26*7594170eSAndroid Build Coastguard Worker)
27*7594170eSAndroid Build Coastguard Worker
28*7594170eSAndroid Build Coastguard Workerdef _symlink_aidl_srcs(ctx, srcs, strip_import_prefix):
29*7594170eSAndroid Build Coastguard Worker    virtual_imports = paths.join("_virtual_imports", ctx.label.name)
30*7594170eSAndroid Build Coastguard Worker    include_path = paths.join(ctx.genfiles_dir.path, ctx.label.package, virtual_imports)
31*7594170eSAndroid Build Coastguard Worker    workspace_root_strip_import_prefix = paths.join(ctx.label.package, strip_import_prefix)
32*7594170eSAndroid Build Coastguard Worker
33*7594170eSAndroid Build Coastguard Worker    direct_srcs = []
34*7594170eSAndroid Build Coastguard Worker    for src in srcs:
35*7594170eSAndroid Build Coastguard Worker        src_path = src.short_path
36*7594170eSAndroid Build Coastguard Worker
37*7594170eSAndroid Build Coastguard Worker        if not paths.normalize(src_path).startswith(paths.normalize(workspace_root_strip_import_prefix)):
38*7594170eSAndroid Build Coastguard Worker            fail(".aidl file '%s' is not under the specified strip prefix '%s'" %
39*7594170eSAndroid Build Coastguard Worker                 (src_path, workspace_root_strip_import_prefix))
40*7594170eSAndroid Build Coastguard Worker
41*7594170eSAndroid Build Coastguard Worker        import_path = paths.relativize(src_path, workspace_root_strip_import_prefix)
42*7594170eSAndroid Build Coastguard Worker        virtual_src = ctx.actions.declare_file(paths.join(virtual_imports, import_path))
43*7594170eSAndroid Build Coastguard Worker        ctx.actions.symlink(
44*7594170eSAndroid Build Coastguard Worker            output = virtual_src,
45*7594170eSAndroid Build Coastguard Worker            target_file = src,
46*7594170eSAndroid Build Coastguard Worker            progress_message = "Symlinking virtual .aidl sources for %{label}",
47*7594170eSAndroid Build Coastguard Worker        )
48*7594170eSAndroid Build Coastguard Worker        direct_srcs.append(virtual_src)
49*7594170eSAndroid Build Coastguard Worker    return include_path, direct_srcs
50*7594170eSAndroid Build Coastguard Worker
51*7594170eSAndroid Build Coastguard Worker# https://cs.android.com/android/platform/system/tools/aidl/+/master:build/aidl_api.go;l=718-724;drc=87bcb923b4ed9cf6e6837f4cc02d954f211c0b12
52*7594170eSAndroid Build Coastguard Workerdef _version_for_hash_gen(version):
53*7594170eSAndroid Build Coastguard Worker    if int(version) > 1:
54*7594170eSAndroid Build Coastguard Worker        return int(version) - 1
55*7594170eSAndroid Build Coastguard Worker    return "latest-version"
56*7594170eSAndroid Build Coastguard Worker
57*7594170eSAndroid Build Coastguard Workerdef _get_aidl_interface_name(versioned_name):
58*7594170eSAndroid Build Coastguard Worker    parts = versioned_name.split("-V")
59*7594170eSAndroid Build Coastguard Worker    if len(parts) == 1 or not parts[-1].isdigit():
60*7594170eSAndroid Build Coastguard Worker        fail("{}'s version is not parsable", versioned_name)
61*7594170eSAndroid Build Coastguard Worker
62*7594170eSAndroid Build Coastguard Worker    return parts[0]
63*7594170eSAndroid Build Coastguard Worker
64*7594170eSAndroid Build Coastguard Workerdef _verify_hash_file(ctx):
65*7594170eSAndroid Build Coastguard Worker    timestamp = ctx.actions.declare_file(ctx.label.name + "_checkhash_" + ctx.attr.version + ".timestamp")
66*7594170eSAndroid Build Coastguard Worker
67*7594170eSAndroid Build Coastguard Worker    api_dir = "{package_dir}/aidl_api/{aidl_interface_name}/{version}".format(
68*7594170eSAndroid Build Coastguard Worker        package_dir = paths.dirname(ctx.build_file_path),
69*7594170eSAndroid Build Coastguard Worker        aidl_interface_name = _get_aidl_interface_name(ctx.label.name),
70*7594170eSAndroid Build Coastguard Worker        version = ctx.attr.version,
71*7594170eSAndroid Build Coastguard Worker    )
72*7594170eSAndroid Build Coastguard Worker
73*7594170eSAndroid Build Coastguard Worker    shell_command = """
74*7594170eSAndroid Build Coastguard Worker        cd {api_dir}
75*7594170eSAndroid Build Coastguard Worker        aidl_files_checksums=$(find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo {version})
76*7594170eSAndroid Build Coastguard Worker        cd -
77*7594170eSAndroid Build Coastguard Worker
78*7594170eSAndroid Build Coastguard Worker        if [[ $(echo "$aidl_files_checksums" | sha1sum | cut -d " " -f 1) = $(tail -1 {hash_file}) ]]; then
79*7594170eSAndroid Build Coastguard Worker            touch {timestamp};
80*7594170eSAndroid Build Coastguard Worker        else
81*7594170eSAndroid Build Coastguard Worker            cat "{message_check_equality}"
82*7594170eSAndroid Build Coastguard Worker            exit 1;
83*7594170eSAndroid Build Coastguard Worker        fi;
84*7594170eSAndroid Build Coastguard Worker    """.format(
85*7594170eSAndroid Build Coastguard Worker        api_dir = api_dir,
86*7594170eSAndroid Build Coastguard Worker        aidl_files = " ".join([src.path for src in ctx.files.srcs]),
87*7594170eSAndroid Build Coastguard Worker        version = _version_for_hash_gen(ctx.attr.version),
88*7594170eSAndroid Build Coastguard Worker        hash_file = ctx.file.hash_file.path,
89*7594170eSAndroid Build Coastguard Worker        timestamp = timestamp.path,
90*7594170eSAndroid Build Coastguard Worker        message_check_equality = ctx.file._message_check_equality.path,
91*7594170eSAndroid Build Coastguard Worker    )
92*7594170eSAndroid Build Coastguard Worker
93*7594170eSAndroid Build Coastguard Worker    ctx.actions.run_shell(
94*7594170eSAndroid Build Coastguard Worker        inputs = ctx.files.srcs + [ctx.file.hash_file, ctx.file._message_check_equality],
95*7594170eSAndroid Build Coastguard Worker        outputs = [timestamp],
96*7594170eSAndroid Build Coastguard Worker        command = shell_command,
97*7594170eSAndroid Build Coastguard Worker        mnemonic = "AidlHashValidation",
98*7594170eSAndroid Build Coastguard Worker        progress_message = "Validating AIDL .hash file",
99*7594170eSAndroid Build Coastguard Worker    )
100*7594170eSAndroid Build Coastguard Worker
101*7594170eSAndroid Build Coastguard Worker    return timestamp
102*7594170eSAndroid Build Coastguard Worker
103*7594170eSAndroid Build Coastguard Workerdef _aidl_library_rule_impl(ctx):
104*7594170eSAndroid Build Coastguard Worker    transitive_srcs = []
105*7594170eSAndroid Build Coastguard Worker    transitive_include_dirs = []
106*7594170eSAndroid Build Coastguard Worker
107*7594170eSAndroid Build Coastguard Worker    validation_output = []
108*7594170eSAndroid Build Coastguard Worker
109*7594170eSAndroid Build Coastguard Worker    if ctx.attr.hash_file and ctx.attr.version:
110*7594170eSAndroid Build Coastguard Worker        # if the aidl_library represents an aidl_interface frozen version,
111*7594170eSAndroid Build Coastguard Worker        # hash_file and version attributes are set
112*7594170eSAndroid Build Coastguard Worker        validation_output.append(_verify_hash_file(ctx))
113*7594170eSAndroid Build Coastguard Worker
114*7594170eSAndroid Build Coastguard Worker    aidl_import_infos = [d[AidlGenInfo] for d in ctx.attr.deps]
115*7594170eSAndroid Build Coastguard Worker    for info in aidl_import_infos:
116*7594170eSAndroid Build Coastguard Worker        transitive_srcs.append(info.transitive_srcs)
117*7594170eSAndroid Build Coastguard Worker        transitive_include_dirs.append(info.transitive_include_dirs)
118*7594170eSAndroid Build Coastguard Worker
119*7594170eSAndroid Build Coastguard Worker    include_path, srcs = _symlink_aidl_srcs(ctx, ctx.files.srcs, ctx.attr.strip_import_prefix)
120*7594170eSAndroid Build Coastguard Worker    _, hdrs = _symlink_aidl_srcs(ctx, ctx.files.hdrs, ctx.attr.strip_import_prefix)
121*7594170eSAndroid Build Coastguard Worker
122*7594170eSAndroid Build Coastguard Worker    return [
123*7594170eSAndroid Build Coastguard Worker        DefaultInfo(files = depset(ctx.files.srcs)),
124*7594170eSAndroid Build Coastguard Worker        OutputGroupInfo(
125*7594170eSAndroid Build Coastguard Worker            _validation = depset(direct = validation_output),
126*7594170eSAndroid Build Coastguard Worker        ),
127*7594170eSAndroid Build Coastguard Worker        AidlGenInfo(
128*7594170eSAndroid Build Coastguard Worker            srcs = depset(srcs),
129*7594170eSAndroid Build Coastguard Worker            hdrs = depset(hdrs),
130*7594170eSAndroid Build Coastguard Worker            hash_file = ctx.file.hash_file,
131*7594170eSAndroid Build Coastguard Worker            transitive_srcs = depset(
132*7594170eSAndroid Build Coastguard Worker                direct = srcs + hdrs,
133*7594170eSAndroid Build Coastguard Worker                transitive = transitive_srcs,
134*7594170eSAndroid Build Coastguard Worker            ),
135*7594170eSAndroid Build Coastguard Worker            transitive_include_dirs = depset(
136*7594170eSAndroid Build Coastguard Worker                direct = [include_path],
137*7594170eSAndroid Build Coastguard Worker                transitive = transitive_include_dirs,
138*7594170eSAndroid Build Coastguard Worker                # build with preorder so that transitive_include_dirs.to_list()
139*7594170eSAndroid Build Coastguard Worker                # return direct include path in the first element
140*7594170eSAndroid Build Coastguard Worker                order = "preorder",
141*7594170eSAndroid Build Coastguard Worker            ),
142*7594170eSAndroid Build Coastguard Worker            flags = ctx.attr.flags,
143*7594170eSAndroid Build Coastguard Worker        ),
144*7594170eSAndroid Build Coastguard Worker    ]
145*7594170eSAndroid Build Coastguard Worker
146*7594170eSAndroid Build Coastguard Workeraidl_library = rule(
147*7594170eSAndroid Build Coastguard Worker    implementation = _aidl_library_rule_impl,
148*7594170eSAndroid Build Coastguard Worker    attrs = {
149*7594170eSAndroid Build Coastguard Worker        "srcs": attr.label_list(
150*7594170eSAndroid Build Coastguard Worker            allow_files = [".aidl"],
151*7594170eSAndroid Build Coastguard Worker            doc = "AIDL source files that contain StructuredParcelable" +
152*7594170eSAndroid Build Coastguard Worker                  " AIDL defintions. These files can be compiled to language" +
153*7594170eSAndroid Build Coastguard Worker                  " bindings.",
154*7594170eSAndroid Build Coastguard Worker        ),
155*7594170eSAndroid Build Coastguard Worker        "hdrs": attr.label_list(
156*7594170eSAndroid Build Coastguard Worker            allow_files = [".aidl"],
157*7594170eSAndroid Build Coastguard Worker            doc = "AIDL source files that contain UnstructuredParcelable" +
158*7594170eSAndroid Build Coastguard Worker                  " AIDL defintions. These files cannot be compiled to language" +
159*7594170eSAndroid Build Coastguard Worker                  " bindings, but can be referenced by other AIDL sources.",
160*7594170eSAndroid Build Coastguard Worker        ),
161*7594170eSAndroid Build Coastguard Worker        "version": attr.string(
162*7594170eSAndroid Build Coastguard Worker            doc = "The version of the upstream aidl_interface that" +
163*7594170eSAndroid Build Coastguard Worker                  " the aidl_library is created for",
164*7594170eSAndroid Build Coastguard Worker        ),
165*7594170eSAndroid Build Coastguard Worker        "hash_file": attr.label(
166*7594170eSAndroid Build Coastguard Worker            doc = "The .hash file in the api directory of an aidl_interface frozen version",
167*7594170eSAndroid Build Coastguard Worker            allow_single_file = [".hash"],
168*7594170eSAndroid Build Coastguard Worker        ),
169*7594170eSAndroid Build Coastguard Worker        "_message_check_equality": attr.label(
170*7594170eSAndroid Build Coastguard Worker            allow_single_file = [".txt"],
171*7594170eSAndroid Build Coastguard Worker            default = "//system/tools/aidl/build:message_check_equality.txt",
172*7594170eSAndroid Build Coastguard Worker        ),
173*7594170eSAndroid Build Coastguard Worker        "deps": attr.label_list(
174*7594170eSAndroid Build Coastguard Worker            providers = [AidlGenInfo],
175*7594170eSAndroid Build Coastguard Worker            doc = "Targets listed here provide AIDL sources referenced" +
176*7594170eSAndroid Build Coastguard Worker                  "by this library.",
177*7594170eSAndroid Build Coastguard Worker        ),
178*7594170eSAndroid Build Coastguard Worker        "strip_import_prefix": attr.string(
179*7594170eSAndroid Build Coastguard Worker            doc = "The prefix to strip from the paths of the .aidl files in " +
180*7594170eSAndroid Build Coastguard Worker                  "this rule. When set, aidl source files in the srcs " +
181*7594170eSAndroid Build Coastguard Worker                  "attribute of this rule are accessible at their path with " +
182*7594170eSAndroid Build Coastguard Worker                  "this prefix cut off.",
183*7594170eSAndroid Build Coastguard Worker        ),
184*7594170eSAndroid Build Coastguard Worker        "flags": attr.string_list(
185*7594170eSAndroid Build Coastguard Worker            doc = "Flags to pass to AIDL tool",
186*7594170eSAndroid Build Coastguard Worker        ),
187*7594170eSAndroid Build Coastguard Worker    },
188*7594170eSAndroid Build Coastguard Worker    provides = [AidlGenInfo],
189*7594170eSAndroid Build Coastguard Worker)
190*7594170eSAndroid Build Coastguard Worker
191*7594170eSAndroid Build Coastguard Workerdef _generate_aidl_bindings(ctx, lang, aidl_info):
192*7594170eSAndroid Build Coastguard Worker    """ Utility function for creating AIDL bindings from aidl_libraries.
193*7594170eSAndroid Build Coastguard Worker
194*7594170eSAndroid Build Coastguard Worker    Args:
195*7594170eSAndroid Build Coastguard Worker      ctx: context, used for declaring actions and new files and providing _aidl_tool
196*7594170eSAndroid Build Coastguard Worker      lang: string, defines the language of the generated binding code
197*7594170eSAndroid Build Coastguard Worker      aidl_src_infos: AidlGenInfo, list of sources to provide to AIDL compiler
198*7594170eSAndroid Build Coastguard Worker
199*7594170eSAndroid Build Coastguard Worker    Returns:
200*7594170eSAndroid Build Coastguard Worker        list of output files
201*7594170eSAndroid Build Coastguard Worker    """
202*7594170eSAndroid Build Coastguard Worker
203*7594170eSAndroid Build Coastguard Worker    #TODO(b/235113507) support C++ AIDL binding
204*7594170eSAndroid Build Coastguard Worker    ext = ""
205*7594170eSAndroid Build Coastguard Worker    if lang == "java":
206*7594170eSAndroid Build Coastguard Worker        ext = ".java"
207*7594170eSAndroid Build Coastguard Worker    else:
208*7594170eSAndroid Build Coastguard Worker        fail("Cannot generate AIDL language bindings for `{}`.".format(lang))
209*7594170eSAndroid Build Coastguard Worker
210*7594170eSAndroid Build Coastguard Worker    out_files = []
211*7594170eSAndroid Build Coastguard Worker    for aidl_file in aidl_info.srcs.to_list():
212*7594170eSAndroid Build Coastguard Worker        out_filename = paths.replace_extension(aidl_file.basename, ext)
213*7594170eSAndroid Build Coastguard Worker        out_file = ctx.actions.declare_file(out_filename, sibling = aidl_file)
214*7594170eSAndroid Build Coastguard Worker        out_files.append(out_file)
215*7594170eSAndroid Build Coastguard Worker
216*7594170eSAndroid Build Coastguard Worker        args = ctx.actions.args()
217*7594170eSAndroid Build Coastguard Worker        args.add_all(aidl_info.flags)
218*7594170eSAndroid Build Coastguard Worker
219*7594170eSAndroid Build Coastguard Worker        #TODO(b/241139797) allow this flag to be controlled by an attribute
220*7594170eSAndroid Build Coastguard Worker        args.add("--structured")
221*7594170eSAndroid Build Coastguard Worker
222*7594170eSAndroid Build Coastguard Worker        args.add_all([
223*7594170eSAndroid Build Coastguard Worker            "-I {}".format(i)
224*7594170eSAndroid Build Coastguard Worker            for i in aidl_info.transitive_include_dirs.to_list()
225*7594170eSAndroid Build Coastguard Worker        ])
226*7594170eSAndroid Build Coastguard Worker        args.add(aidl_file.path)
227*7594170eSAndroid Build Coastguard Worker        args.add(out_file)
228*7594170eSAndroid Build Coastguard Worker
229*7594170eSAndroid Build Coastguard Worker        ctx.actions.run(
230*7594170eSAndroid Build Coastguard Worker            inputs = aidl_info.transitive_srcs,
231*7594170eSAndroid Build Coastguard Worker            outputs = [out_file],
232*7594170eSAndroid Build Coastguard Worker            arguments = [args],
233*7594170eSAndroid Build Coastguard Worker            progress_message = "Generating {} AIDL binding from {}".format(lang, aidl_file.short_path),
234*7594170eSAndroid Build Coastguard Worker            executable = ctx.executable._aidl_tool,
235*7594170eSAndroid Build Coastguard Worker        )
236*7594170eSAndroid Build Coastguard Worker
237*7594170eSAndroid Build Coastguard Worker    return out_files
238*7594170eSAndroid Build Coastguard Worker
239*7594170eSAndroid Build Coastguard Workeraidl_file_utils = struct(
240*7594170eSAndroid Build Coastguard Worker    generate_aidl_bindings = _generate_aidl_bindings,
241*7594170eSAndroid Build Coastguard Worker)
242