kleaf: Expose CcInfo provider from ddk_headers rule

Update `ddk_headers` rule in `kleaf/impl/ddk/ddk_headers.bzl` to
construct and export a `CcInfo` provider transitively from dependencies.

Add helper function `ddk_headers_cc_info_transitively()` which gathers
include paths and compilation context headers from `hdrs` and
`textual_hdrs` targets that provide `CcInfo` (such as `kernel_headers`
or dependent `ddk_headers`), allowing downstream DDK targets to
transitively propagate C/C++ compilation contexts.

Bug: 517401745
Change-Id: I47e8529177a419be21591f868202ab3bf2830ea2
Signed-off-by: Lucas Wei <lucaswei@google.com>
diff --git a/kleaf/impl/ddk/ddk_headers.bzl b/kleaf/impl/ddk/ddk_headers.bzl
index d29ecd8..1f1cbef 100644
--- a/kleaf/impl/ddk/ddk_headers.bzl
+++ b/kleaf/impl/ddk/ddk_headers.bzl
@@ -16,6 +16,8 @@
 
 load("@bazel_skylib//lib:paths.bzl", "paths")
 load("@bazel_skylib//lib:sets.bzl", "sets")
+load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
+load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
 load(
     ":common_providers.bzl",
     "DdkHeadersInfo",
@@ -130,6 +132,36 @@
         ),
     )
 
+def ddk_headers_cc_info_transitively(label, hdrs, includes, linux_includes):
+    """Constructs CcInfo transitively from dependencies.
+
+    Args:
+        label: Label of this target.
+        hdrs: List of header dependencies (targets).
+        includes: List of include directories relative to the current package.
+        linux_includes: Like `includes` but for `LINUXINCLUDE`.
+    Returns:
+        CcInfo provider.
+    """
+    our_prefix = paths.join(label.workspace_root, label.package)
+    our_includes = [paths.join(our_prefix, inc) for inc in includes + linux_includes]
+
+    transitive_includes = []
+    transitive_headers = []
+
+    for dep in hdrs:
+        if CcInfo in dep:
+            transitive_includes.append(dep[CcInfo].compilation_context.includes)
+            transitive_headers.append(dep[CcInfo].compilation_context.headers)
+        else:
+            transitive_headers.append(dep.files)
+
+    compilation_context = cc_common.create_compilation_context(
+        headers = depset(transitive = transitive_headers),
+        includes = depset(our_includes, transitive = transitive_includes),
+    )
+    return CcInfo(compilation_context = compilation_context)
+
 def _ddk_headers_impl(ctx):
     if get_headers_depset(ctx.attr.textual_hdrs):
         # buildifier: disable=print
@@ -149,10 +181,18 @@
         kernel_build_ddk_config_env = None,
     )
 
+    cc_info = ddk_headers_cc_info_transitively(
+        ctx.label,
+        ctx.attr.hdrs + ctx.attr.textual_hdrs,
+        ctx.attr.includes,
+        ctx.attr.linux_includes,
+    )
+
     return [
         DefaultInfo(files = ddk_headers_info.files),
         ddk_headers_info,
         ddk_config_info,
+        cc_info,
     ]
 
 ddk_headers = rule(