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