1# Copyright (C) 2021 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("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
17load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
18load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
19load("@soong_injection//cc_toolchain:config_constants.bzl", config_constants = "constants")
20load("//build/bazel/rules:common.bzl", "get_dep_targets")
21load(
22    ":cc_library_common.bzl",
23    "CPP_EXTENSIONS",
24    "C_EXTENSIONS",
25    "CcAndroidMkInfo",
26    "check_absolute_include_dirs_disabled",
27    "create_cc_androidmk_provider",
28    "create_ccinfo_for_includes",
29    "get_non_header_srcs",
30    "get_sanitizer_lib_info",
31    "is_external_directory",
32    "parse_sdk_version",
33    "system_dynamic_deps_defaults",
34)
35load(":clang_tidy.bzl", "ClangTidyInfo", "clang_tidy_for_dir", "generate_clang_tidy_actions")
36
37# TODO: b/294868620 - Change this back to lto_deps_transition when completing
38#                     the bug
39load(":composed_transitions.bzl", "lto_and_sanitizer_static_transition")
40
41# TODO: b/294868620 - Remove when completing the bug
42load(
43    ":sanitizer_enablement_transition.bzl",
44    "drop_sanitizer_enablement_transition",
45)
46load(":stl.bzl", "stl_info_from_attr")
47
48_ALLOWED_MANUAL_INTERFACE_PATHS = [
49    "vendor/",
50    "hardware/",
51    # for testing
52    "build/bazel/rules/cc",
53]
54
55CcStaticLibraryInfo = provider(fields = ["root_static_archive", "objects"])
56
57def cc_library_static(
58        name,
59        shared_linking = False,
60        deps = [],
61        implementation_deps = [],
62        dynamic_deps = [],
63        implementation_dynamic_deps = [],
64        whole_archive_deps = [],
65        implementation_whole_archive_deps = [],
66        system_dynamic_deps = None,
67        runtime_deps = [],
68        export_absolute_includes = [],
69        export_includes = [],
70        export_system_includes = [],
71        local_includes = [],
72        absolute_includes = [],
73        hdrs = [],
74        native_bridge_supported = False,  # TODO: not supported yet. @unused
75        rtti = False,
76        stl = "",
77        cpp_std = "",
78        c_std = "",
79        # Flags for C and C++
80        copts = [],
81        # C++ attributes
82        srcs = [],
83        cppflags = [],
84        # C attributes
85        srcs_c = [],
86        conlyflags = [],
87        # asm attributes
88        srcs_as = [],
89        asflags = [],
90        features = [],
91        linkopts = [],
92        alwayslink = None,
93        target_compatible_with = [],
94        # TODO(b/202299295): Handle data attribute.
95        data = [],  # @unused
96        sdk_version = "",  # @unused
97        min_sdk_version = "",
98        tags = [],
99        tidy = None,
100        tidy_checks = None,
101        tidy_checks_as_errors = None,
102        tidy_flags = None,
103        tidy_disabled_srcs = None,
104        tidy_timeout_srcs = None,
105        tidy_gen_header_filter = None,
106        native_coverage = True,
107        additional_compiler_inputs = [],
108        applicable_licenses = []):
109    "Bazel macro to correspond with the cc_library_static Soong module."
110
111    exports_name = "%s_exports" % name
112    locals_name = "%s_locals" % name
113    cpp_name = "%s_cpp" % name
114    c_name = "%s_c" % name
115    asm_name = "%s_asm" % name
116
117    toolchain_features = []
118
119    toolchain_features.append("pic")
120
121    if is_external_directory(native.package_name()):
122        toolchain_features += [
123            "-non_external_compiler_flags",
124            "external_compiler_flags",
125        ]
126    else:
127        toolchain_features += [
128            "non_external_compiler_flags",
129            "-external_compiler_flags",
130        ]
131
132    for allowed_project in config_constants.WarningAllowedProjects:
133        if native.package_name().startswith(allowed_project):
134            toolchain_features.append("-warnings_as_errors")
135            break
136
137    if rtti:
138        toolchain_features.append("rtti")
139    if cpp_std:
140        toolchain_features += [cpp_std, "-cpp_std_default"]
141    if c_std:
142        toolchain_features += [c_std, "-c_std_default"]
143
144    for path in _ALLOWED_MANUAL_INTERFACE_PATHS:
145        if native.package_name().startswith(path):
146            toolchain_features.append("do_not_check_manual_binder_interfaces")
147            break
148
149    if min_sdk_version:
150        toolchain_features += parse_sdk_version(min_sdk_version) + ["-sdk_version_default"]
151    toolchain_features += features
152
153    if not native_coverage:
154        toolchain_features += ["-coverage"]  # buildifier: disable=list-append This could be a select, not a list
155
156    if system_dynamic_deps == None:
157        system_dynamic_deps = system_dynamic_deps_defaults
158
159    _cc_includes(
160        name = exports_name,
161        includes = export_includes,
162        absolute_includes = export_absolute_includes,
163        system_includes = export_system_includes,
164        # whole archive deps always re-export their includes, etc
165        deps = deps + whole_archive_deps + dynamic_deps,
166        target_compatible_with = target_compatible_with,
167        applicable_licenses = applicable_licenses,
168        tags = ["manual"],
169    )
170
171    stl_info = stl_info_from_attr(stl, False)
172    linkopts = linkopts + stl_info.linkopts
173    copts = copts + stl_info.cppflags
174
175    _cc_includes(
176        name = locals_name,
177        includes = local_includes,
178        absolute_includes = absolute_includes,
179        deps = (
180            implementation_deps +
181            implementation_dynamic_deps +
182            system_dynamic_deps +
183            stl_info.deps +
184            stl_info.static_deps +
185            stl_info.shared_deps +
186            implementation_whole_archive_deps
187        ),
188        target_compatible_with = target_compatible_with,
189        applicable_licenses = applicable_licenses,
190        tags = ["manual"],
191    )
192
193    # Silently drop these attributes for now:
194    # - native_bridge_supported
195    common_attrs = dict(
196        [
197            # TODO(b/199917423): This may be superfluous. Investigate and possibly remove.
198            ("linkstatic", True),
199            ("hdrs", hdrs),
200            # Add dynamic_deps to implementation_deps, as the include paths from the
201            # dynamic_deps are also needed.
202            ("implementation_deps", [locals_name]),
203            ("deps", [exports_name]),
204            ("features", toolchain_features),
205            ("toolchains", ["//build/bazel/product_config:product_variables_for_attributes"]),
206            ("target_compatible_with", target_compatible_with),
207            ("linkopts", linkopts),
208            ("applicable_licenses", applicable_licenses),
209        ],
210    )
211
212    # TODO(b/231574899): restructure this to handle other images
213    copts += select({
214        "//build/bazel/rules/apex:non_apex": [],
215        "//conditions:default": [
216            "-D__ANDROID_APEX__",
217        ],
218    })
219
220    native.cc_library(
221        name = cpp_name,
222        srcs = srcs,
223        copts = copts + cppflags,
224        additional_compiler_inputs = additional_compiler_inputs,
225        tags = ["manual"],
226        alwayslink = True,
227        **common_attrs
228    )
229    native.cc_library(
230        name = c_name,
231        srcs = srcs_c,
232        copts = copts + conlyflags,
233        additional_compiler_inputs = additional_compiler_inputs,
234        tags = ["manual"],
235        alwayslink = True,
236        **common_attrs
237    )
238    native.cc_library(
239        name = asm_name,
240        srcs = srcs_as,
241        copts = asflags,
242        tags = ["manual"],
243        alwayslink = True,
244        **common_attrs
245    )
246
247    tidy_providing_deps = []
248    if shared_linking:
249        tidy_providing_deps = (
250            deps +
251            implementation_deps +
252            whole_archive_deps +
253            implementation_whole_archive_deps +
254            runtime_deps +
255            dynamic_deps +
256            implementation_dynamic_deps
257        )
258    else:
259        # We should only be running tidy actions for object files on which
260        # we depend. For static libraries, only whole_archive_deps actually
261        # create a linking dependency; other dependencies are header-only,
262        # so we shouldn't try to run their tidy actions.
263        tidy_providing_deps = whole_archive_deps + implementation_whole_archive_deps
264
265    # Root target to handle combining of the providers of the language-specific targets.
266    _cc_library_combiner(
267        name = name,
268        shared_linking = shared_linking,
269        roots = [cpp_name, c_name, asm_name],
270        deps = whole_archive_deps + implementation_whole_archive_deps,
271        additional_sanitizer_deps = (
272            deps +
273            stl_info.deps +
274            stl_info.static_deps +
275            implementation_deps
276        ),
277        runtime_deps = runtime_deps,
278        target_compatible_with = target_compatible_with,
279        alwayslink = alwayslink,
280        static_deps = deps + implementation_deps + whole_archive_deps + implementation_whole_archive_deps,
281        androidmk_static_deps = deps + implementation_deps + stl_info.static_deps,
282        androidmk_whole_archive_deps = whole_archive_deps + implementation_whole_archive_deps,
283        androidmk_dynamic_deps = dynamic_deps + implementation_dynamic_deps + system_dynamic_deps + stl_info.shared_deps,
284        exports = exports_name,
285        applicable_licenses = applicable_licenses,
286        tags = tags,
287        features = toolchain_features,
288
289        # clang-tidy attributes
290        tidy = tidy,
291        srcs_cpp = srcs,
292        srcs_c = srcs_c,
293        copts_cpp = copts + cppflags,
294        copts_c = copts + conlyflags,
295        hdrs = hdrs,
296        includes = [locals_name, exports_name],
297        tidy_flags = tidy_flags,
298        tidy_checks = tidy_checks,
299        tidy_checks_as_errors = tidy_checks_as_errors,
300        tidy_disabled_srcs = tidy_disabled_srcs,
301        tidy_timeout_srcs = tidy_timeout_srcs,
302        tidy_gen_header_filter = tidy_gen_header_filter,
303        tidy_providing_deps = tidy_providing_deps,
304    )
305
306def _generate_tidy_files(ctx):
307    disabled_srcs = [] + ctx.files.tidy_disabled_srcs
308    tidy_timeout = ctx.attr._tidy_timeout[BuildSettingInfo].value
309    if tidy_timeout != "":
310        disabled_srcs.extend(ctx.attr.tidy_timeout_srcs)
311
312    if ctx.attr.tidy_gen_header_filter:
313        if ctx.attr.tidy_flags:
314            fail("tidy_flags cannot be set when also using tidy_gen_header_filter")
315        tidy_flags = ["-header-filter=" + paths.join(ctx.genfiles_dir.path, ctx.label.package) + ".*"]
316    else:
317        tidy_flags = ctx.attr.tidy_flags
318
319    cpp_srcs, cpp_hdrs = get_non_header_srcs(
320        ctx.files.srcs_cpp,
321        ctx.files.tidy_disabled_srcs,
322        source_extensions = CPP_EXTENSIONS,
323    )
324    c_srcs, c_hdrs = get_non_header_srcs(
325        ctx.files.srcs_cpp + ctx.files.srcs_c,
326        ctx.files.tidy_disabled_srcs,
327        source_extensions = C_EXTENSIONS,
328    )
329    hdrs = ctx.files.hdrs + cpp_hdrs + c_hdrs
330    cpp_tidy_outs = generate_clang_tidy_actions(
331        ctx,
332        ctx.attr.copts_cpp,
333        ctx.attr.deps + ctx.attr.includes,
334        cpp_srcs,
335        hdrs,
336        "c++",
337        tidy_flags,
338        ctx.attr.tidy_checks,
339        ctx.attr.tidy_checks_as_errors,
340        tidy_timeout,
341    )
342    c_tidy_outs = generate_clang_tidy_actions(
343        ctx,
344        ctx.attr.copts_c,
345        ctx.attr.deps + ctx.attr.includes,
346        c_srcs,
347        hdrs,
348        "c",
349        tidy_flags,
350        ctx.attr.tidy_checks,
351        ctx.attr.tidy_checks_as_errors,
352        tidy_timeout,
353    )
354    return cpp_tidy_outs + c_tidy_outs
355
356def _generate_tidy_actions(ctx):
357    transitive_tidy_files = []
358    for attr, attr_targets in get_dep_targets(ctx.attr, predicate = lambda t: ClangTidyInfo in t).items():
359        if attr == "tidy_providing_deps":
360            for t in attr_targets:
361                transitive_tidy_files.append(t[ClangTidyInfo].transitive_tidy_files)
362
363    with_tidy = ctx.attr._with_tidy[BuildSettingInfo].value
364    allow_local_tidy_true = ctx.attr._allow_local_tidy_true[BuildSettingInfo].value
365    tidy_external_vendor = ctx.attr._tidy_external_vendor[BuildSettingInfo].value
366    tidy_enabled = (with_tidy and ctx.attr.tidy != "never") or (allow_local_tidy_true and ctx.attr.tidy == "local")
367    should_run_for_current_package = clang_tidy_for_dir(tidy_external_vendor, ctx.label.package)
368    if tidy_enabled and should_run_for_current_package:
369        direct_tidy_files = _generate_tidy_files(ctx)
370    else:
371        direct_tidy_files = None
372
373    tidy_files = depset(
374        direct = direct_tidy_files,
375    )
376    transitive_tidy_files = depset(
377        direct = direct_tidy_files,
378        transitive = transitive_tidy_files,
379    )
380    return [
381        OutputGroupInfo(
382            _validation = tidy_files,
383        ),
384        ClangTidyInfo(
385            tidy_files = tidy_files,
386            transitive_tidy_files = transitive_tidy_files,
387        ),
388    ]
389
390def _archive_with_prebuilt_libs(ctx, prebuilt_deps, linking_outputs, cc_toolchain):
391    linking_output = linking_outputs.library_to_link.static_library
392    if not prebuilt_deps:
393        return linking_output
394
395    feature_configuration = cc_common.configure_features(
396        ctx = ctx,
397        cc_toolchain = cc_toolchain,
398        requested_features = ctx.features + ["archive_with_prebuilt_flags"],
399        unsupported_features = ctx.disabled_features + ["linker_flags", "archiver_flags"],
400    )
401
402    output_file = ctx.actions.declare_file("lib" + ctx.label.name + ".a")
403
404    archiver_path = cc_common.get_tool_for_action(
405        feature_configuration = feature_configuration,
406        action_name = ACTION_NAMES.cpp_link_static_library,
407    )
408    archiver_variables = cc_common.create_link_variables(
409        feature_configuration = feature_configuration,
410        cc_toolchain = cc_toolchain,
411        output_file = output_file.path,
412        is_using_linker = False,
413    )
414    command_line = cc_common.get_memory_inefficient_command_line(
415        feature_configuration = feature_configuration,
416        action_name = ACTION_NAMES.cpp_link_static_library,
417        variables = archiver_variables,
418    )
419    args = ctx.actions.args()
420    args.add_all(command_line)
421    args.add(linking_output)
422    args.add_all(prebuilt_deps)
423
424    ctx.actions.run(
425        executable = archiver_path,
426        arguments = [args],
427        inputs = depset(
428            direct = [linking_output] + prebuilt_deps,
429            transitive = [
430                cc_toolchain.all_files,
431            ],
432        ),
433        outputs = [output_file],
434        mnemonic = "CppArchive",
435    )
436
437    return output_file
438
439# Returns a CcInfo object which combines one or more CcInfo objects, except that all
440# linker inputs owned by  owners in `old_owner_labels` are relinked and owned by the current target.
441#
442# This is useful in the "macro with proxy rule" pattern, as some rules upstream
443# may expect they are depending directly on a target which generates linker inputs,
444# as opposed to a proxy target which is a level of indirection to such a target.
445def _cc_library_combiner_impl(ctx):
446    sanitizer_lib_info = get_sanitizer_lib_info(ctx.attr.features, ctx.attr.deps + ctx.attr.additional_sanitizer_deps)
447
448    old_owner_labels = []
449    cc_infos = []
450
451    # Soong links whole archive deps of a static lib differently, all the .o files
452    # from the whole archive deps will be loaded into the static lib. This is
453    # different from when linking from a shared lib, in which case the whole
454    # archive deps will be linked separately.
455    if not ctx.attr.shared_linking:
456        for dep in ctx.attr.deps:
457            old_owner_labels.append(dep.label)
458            cc_info = dep[CcInfo]
459
460            # do not propagate includes, hdrs, etc, already handled by roots
461            cc_infos.append(CcInfo(linking_context = cc_info.linking_context))
462
463    # we handle roots after deps to mimic Soong handling objects from whole archive deps prior to objects from the target itself
464    for dep in ctx.attr.roots:
465        old_owner_labels.append(dep.label)
466        cc_infos.append(dep[CcInfo])
467
468    direct_owner_labels = []
469    if ctx.attr.shared_linking:
470        for dep in ctx.attr.static_deps:
471            if dep.label in old_owner_labels:
472                continue
473            direct_owner_labels.append(dep.label)
474            cc_info = dep[CcInfo]
475
476            # do not propagate includes, hdrs, etc, already handled by roots
477            cc_infos.append(CcInfo(linking_context = cc_info.linking_context))
478        if sanitizer_lib_info.propagate_ubsan_deps:
479            direct_owner_labels.append(ctx.attr._ubsan_library.label)
480            cc_infos.append(CcInfo(linking_context = ctx.attr._ubsan_library[CcInfo].linking_context))
481
482    combined_info = cc_common.merge_cc_infos(cc_infos = cc_infos)
483
484    objects_to_link = []
485    extra_linker_inputs = []
486
487    prebuilt_deps = []
488
489    # This is not ideal, as it flattens a depset.
490    for old_linker_input in combined_info.linking_context.linker_inputs.to_list():
491        if old_linker_input.owner in old_owner_labels:
492            for lib in old_linker_input.libraries:
493                # These objects will be recombined into the root archive.
494                objects_to_link.extend(lib.objects)
495
496                # This is a prebuilt library, we have to handle it separately
497                if not lib.objects and lib.static_library:
498                    prebuilt_deps.append(lib.static_library)
499        elif ctx.attr.shared_linking:
500            if old_linker_input.owner in direct_owner_labels:
501                extra_linker_inputs.append(old_linker_input)
502        else:
503            # Android macros don't handle transitive linker dependencies because
504            # it's unsupported in legacy. We may want to change this going forward,
505            # but for now it's good to validate that this invariant remains.
506            fail("cc_static_library %s given transitive linker dependency from %s %s" % (ctx.label, old_linker_input.owner, old_owner_labels))
507
508    cc_toolchain = find_cpp_toolchain(ctx)
509
510    feature_configuration = cc_common.configure_features(
511        ctx = ctx,
512        cc_toolchain = cc_toolchain,
513        requested_features = ctx.features + ["archiver_flags"],
514        unsupported_features = ctx.disabled_features + ["linker_flags"],
515    )
516
517    out_name = ctx.label.name
518    if prebuilt_deps:
519        out_name += "_objs_only"
520    linking_context, linking_outputs = cc_common.create_linking_context_from_compilation_outputs(
521        actions = ctx.actions,
522        name = out_name,
523        feature_configuration = feature_configuration,
524        cc_toolchain = cc_toolchain,
525        alwayslink = ctx.attr.alwayslink,
526        disallow_dynamic_library = True,
527        compilation_outputs = cc_common.create_compilation_outputs(objects = depset(direct = objects_to_link)),
528    )
529
530    output_file = _archive_with_prebuilt_libs(ctx, prebuilt_deps, linking_outputs, cc_toolchain)
531    linker_input = cc_common.create_linker_input(
532        owner = ctx.label,
533        libraries = depset(
534            direct = [
535                cc_common.create_library_to_link(
536                    actions = ctx.actions,
537                    feature_configuration = feature_configuration,
538                    cc_toolchain = cc_toolchain,
539                    static_library = output_file,
540                    objects = objects_to_link,
541                    alwayslink = ctx.attr.alwayslink,
542                ),
543            ],
544        ),
545    )
546    linking_context = cc_common.create_linking_context(
547        linker_inputs = depset(
548            direct = [linker_input],
549            transitive = [depset(direct = extra_linker_inputs)],
550        ),
551    )
552
553    providers = [
554        DefaultInfo(files = depset(direct = [output_file]), data_runfiles = ctx.runfiles(files = [output_file])),
555        CcInfo(compilation_context = combined_info.compilation_context, linking_context = linking_context),
556        CcStaticLibraryInfo(root_static_archive = output_file, objects = objects_to_link),
557        sanitizer_lib_info,
558        create_cc_androidmk_provider(
559            static_deps = ctx.attr.androidmk_static_deps,
560            whole_archive_deps = ctx.attr.androidmk_whole_archive_deps,
561            dynamic_deps = ctx.attr.androidmk_dynamic_deps,
562        ),
563    ]
564    providers.extend(_generate_tidy_actions(ctx))
565    if ctx.attr.shared_linking:
566        providers.append(
567            # cc_shared_library only needs to traverse some attrs of the root library
568            cc_common.CcSharedLibraryHintInfo(
569                attributes = [
570                    "roots",
571                    "deps",
572                    "static_deps",
573                    "_ubsan_library",
574                ],
575            ),
576        )
577    else:
578        providers.append(cc_common.CcSharedLibraryHintInfo(
579            # cc_shared_library only needs to traverse some attrs of a static library
580            attributes = [],
581        ))
582
583    return providers
584
585# A rule which combines objects of oen or more cc_library targets into a single
586# static linker input. This outputs a single archive file combining the objects
587# of its direct deps, and propagates Cc providers describing that these objects
588# should be linked for linking rules upstream.
589# This rule is useful for maintaining the illusion that the target's deps are
590# comprised by a single consistent rule:
591#   - A single archive file is always output by this rule.
592#   - A single linker input struct is always output by this rule, and it is 'owned'
593#       by this rule.
594_cc_library_combiner = rule(
595    implementation = _cc_library_combiner_impl,
596    cfg = drop_sanitizer_enablement_transition,
597    attrs = {
598        "roots": attr.label_list(
599            providers = [CcInfo],
600            cfg = lto_and_sanitizer_static_transition,
601        ),
602        "deps": attr.label_list(
603            providers = [CcInfo],
604            cfg = lto_and_sanitizer_static_transition,
605        ),
606        "shared_linking": attr.bool(
607            doc = "Whether to link as needed for shared libraries, rather than as needed for a static libraries.",
608            default = False,
609        ),
610        "additional_sanitizer_deps": attr.label_list(
611            providers = [CcInfo],
612            cfg = lto_and_sanitizer_static_transition,
613            doc = "Deps used only to check for sanitizer enablement",
614        ),
615        "runtime_deps": attr.label_list(
616            providers = [CcInfo],
617            doc = "Deps that should be installed along with this target. Read by the apex cc aspect.",
618        ),
619        "static_deps": attr.label_list(
620            providers = [CcInfo],
621            doc = "All the static deps of the lib. This is used by" +
622                  " abi_dump_aspect to travel along the static_deps edges" +
623                  " to create abi dump files.",
624        ),
625        "_ubsan_library": attr.label(
626            default = "//prebuilts/clang/host/linux-x86:libclang_rt.ubsan_minimal",
627            doc = "The library target corresponding to the undefined " +
628                  "behavior sanitizer library to be used",
629        ),
630        "androidmk_static_deps": attr.label_list(
631            providers = [CcInfo],
632            doc = "All the whole archive deps of the lib. This is used to propagate" +
633                  " information to AndroidMk about LOCAL_STATIC_LIBRARIES.",
634        ),
635        "androidmk_whole_archive_deps": attr.label_list(
636            providers = [CcInfo],
637            doc = "All the whole archive deps of the lib. This is used to propagate" +
638                  " information to AndroidMk about LOCAL_WHOLE_STATIC_LIBRARIES.",
639        ),
640        "androidmk_dynamic_deps": attr.label_list(
641            providers = [CcInfo],
642            doc = "All the dynamic deps of the lib. This is used to propagate" +
643                  " information to AndroidMk about LOCAL_SHARED_LIBRARIES." +
644                  " The attribute name is prefixed with androidmk to avoid" +
645                  " collision with the dynamic_deps attribute used in APEX" +
646                  " aspects' propagation.",
647        ),
648        "exports": attr.label(
649            providers = [CcInfo],
650            cfg = lto_and_sanitizer_static_transition,
651        ),
652        "_cc_toolchain": attr.label(
653            default = Label("@local_config_cc//:toolchain"),
654            providers = [cc_common.CcToolchainInfo],
655            doc = "The exported includes used by abi_dump_aspect to retrieve" +
656                  " and use as the inputs of abi dumper binary.",
657        ),
658        "alwayslink": attr.bool(
659            doc = """At link time, whether these libraries should be wrapped in
660            the --whole_archive block. This causes all libraries in the static
661            archive to be unconditionally linked, regardless of whether the
662            symbols in these object files are being searched by the linker.""",
663            default = False,
664        ),
665
666        # Clang-tidy attributes
667        "tidy": attr.string(values = ["", "local", "never"]),
668        "srcs_cpp": attr.label_list(allow_files = True),
669        "srcs_c": attr.label_list(allow_files = True),
670        "copts_cpp": attr.string_list(),
671        "copts_c": attr.string_list(),
672        "hdrs": attr.label_list(allow_files = True),
673        "includes": attr.label_list(cfg = lto_and_sanitizer_static_transition),
674        "tidy_checks": attr.string_list(),
675        "tidy_checks_as_errors": attr.string_list(),
676        "tidy_flags": attr.string_list(),
677        "tidy_disabled_srcs": attr.label_list(allow_files = True),
678        "tidy_timeout_srcs": attr.label_list(allow_files = True),
679        "tidy_gen_header_filter": attr.bool(),
680        "tidy_providing_deps": attr.label_list(),
681        "_clang_tidy_sh": attr.label(
682            default = Label("@//prebuilts/clang/host/linux-x86:clang-tidy.sh"),
683            allow_single_file = True,
684            executable = True,
685            cfg = "exec",
686            doc = "The clang tidy shell wrapper",
687        ),
688        "_clang_tidy": attr.label(
689            default = Label("@//prebuilts/clang/host/linux-x86:clang-tidy"),
690            allow_single_file = True,
691            executable = True,
692            cfg = "exec",
693            doc = "The clang tidy executable",
694        ),
695        "_clang_tidy_real": attr.label(
696            default = Label("@//prebuilts/clang/host/linux-x86:clang-tidy.real"),
697            allow_single_file = True,
698            executable = True,
699            cfg = "exec",
700        ),
701        "_with_tidy": attr.label(
702            default = "//build/bazel/flags/cc/tidy:with_tidy",
703        ),
704        "_allow_local_tidy_true": attr.label(
705            default = "//build/bazel/flags/cc/tidy:allow_local_tidy_true",
706        ),
707        "_with_tidy_flags": attr.label(
708            default = "//build/bazel/flags/cc/tidy:with_tidy_flags",
709        ),
710        "_default_tidy_header_dirs": attr.label(
711            default = "//build/bazel/flags/cc/tidy:default_tidy_header_dirs",
712        ),
713        "_tidy_timeout": attr.label(
714            default = "//build/bazel/flags/cc/tidy:tidy_timeout",
715        ),
716        "_tidy_external_vendor": attr.label(
717            default = "//build/bazel/flags/cc/tidy:tidy_external_vendor",
718        ),
719        "_allowlist_function_transition": attr.label(
720            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
721        ),
722        "_tidy_checks": attr.label(
723            default = "//build/bazel/product_config:tidy_checks",
724        ),
725    },
726    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
727    provides = [
728        CcInfo,
729        CcAndroidMkInfo,
730        cc_common.CcSharedLibraryHintInfo,
731    ],
732    fragments = ["cpp"],
733)
734
735def _cc_includes_impl(ctx):
736    check_absolute_include_dirs_disabled(
737        ctx.label.package,
738        ctx.attr.absolute_includes,
739    )
740
741    return [
742        create_ccinfo_for_includes(
743            ctx,
744            includes = ctx.attr.includes,
745            absolute_includes = ctx.attr.absolute_includes,
746            system_includes = ctx.attr.system_includes,
747            deps = ctx.attr.deps,
748        ),
749        cc_common.CcSharedLibraryHintInfo(
750            # cc_shared_library shouldn't ever traverse into deps of includes
751            attributes = [],
752        ),
753    ]
754
755# Bazel's native cc_library rule supports specifying include paths two ways:
756# 1. non-exported includes can be specified via copts attribute
757# 2. exported -isystem includes can be specified via includes attribute
758#
759# In order to guarantee a correct inclusion search order, we need to export
760# includes paths for both -I and -isystem; however, there is no native Bazel
761# support to export both of these, this rule provides a CcInfo to propagate the
762# given package-relative include/system include paths as exec root relative
763# include/system include paths.
764_cc_includes = rule(
765    implementation = _cc_includes_impl,
766    attrs = {
767        "absolute_includes": attr.string_list(doc = "List of exec-root relative or absolute search paths for headers, usually passed with -I"),
768        "includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -I"),
769        "system_includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -isystem"),
770        "deps": attr.label_list(doc = "Re-propagates the includes obtained from these dependencies.", providers = [CcInfo]),
771    },
772    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
773    fragments = ["cpp"],
774    provides = [CcInfo, cc_common.CcSharedLibraryHintInfo],
775)
776