1load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain")
2load(":cc_constants.bzl", "constants")
3
4# "cc_object" module copts, taken from build/soong/cc/object.go
5_CC_OBJECT_COPTS = ["-fno-addrsig"]
6
7# partialLd module link opts, taken from build/soong/cc/builder.go
8# https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/builder.go;l=87;drc=f2be52c4dcc2e3d743318e106633e61de0ad2afd
9_CC_OBJECT_LINKOPTS = [
10    "-fuse-ld=lld",
11    "-nostdlib",
12    "-no-pie",
13    "-Wl,-r",
14]
15
16
17CcObjectInfo = provider(fields = [
18    # The merged compilation outputs for this cc_object and its transitive
19    # dependencies.
20    "objects",
21])
22
23def split_srcs_hdrs(files):
24    headers = []
25    non_headers = []
26    for f in files:
27        if f.extension in constants.hdr_exts:
28            headers += [f]
29        else:
30            non_headers += [f]
31    return non_headers, headers
32
33
34def _cc_object_impl(ctx):
35    cc_toolchain = find_cpp_toolchain(ctx)
36
37    feature_configuration = cc_common.configure_features(
38        ctx = ctx,
39        cc_toolchain = cc_toolchain,
40        requested_features = ctx.features,
41        unsupported_features = ctx.disabled_features + ["linker_flags"],
42    )
43
44    compilation_contexts = []
45    deps_objects = []
46    for obj in ctx.attr.deps:
47        compilation_contexts.append(obj[CcInfo].compilation_context)
48        deps_objects.append(obj[CcObjectInfo].objects)
49
50    product_variables = ctx.attr._android_product_variables[platform_common.TemplateVariableInfo]
51    asflags = [flag.format(**product_variables.variables) for flag in ctx.attr.asflags]
52
53    srcs, private_hdrs = split_srcs_hdrs(ctx.files.srcs)
54
55    (compilation_context, compilation_outputs) = cc_common.compile(
56        name = ctx.label.name,
57        actions = ctx.actions,
58        feature_configuration = feature_configuration,
59        cc_toolchain = cc_toolchain,
60        srcs = srcs,
61        includes = ctx.attr.includes,
62        public_hdrs = ctx.files.hdrs,
63        private_hdrs = private_hdrs,
64        user_compile_flags = ctx.attr.copts + asflags,
65        compilation_contexts = compilation_contexts,
66    )
67
68    objects_to_link = cc_common.merge_compilation_outputs(compilation_outputs=deps_objects + [compilation_outputs])
69
70    # partially link if there are multiple object files
71    if len(objects_to_link.objects) + len(objects_to_link.pic_objects) > 1:
72        linking_output = cc_common.link(
73            name = ctx.label.name + ".o",
74            actions = ctx.actions,
75            feature_configuration = feature_configuration,
76            cc_toolchain = cc_toolchain,
77            user_link_flags = _CC_OBJECT_LINKOPTS,
78            compilation_outputs = objects_to_link,
79        )
80        files = depset([linking_output.executable])
81    else:
82        files = depset(objects_to_link.objects + objects_to_link.pic_objects)
83
84    return [
85        DefaultInfo(files = files),
86        CcInfo(compilation_context = compilation_context),
87        CcObjectInfo(objects = objects_to_link),
88    ]
89
90_cc_object = rule(
91    implementation = _cc_object_impl,
92    attrs = {
93        "srcs": attr.label_list(allow_files = constants.all_dot_exts),
94        "hdrs": attr.label_list(allow_files = constants.hdr_dot_exts),
95        "includes": attr.string_list(),
96        "copts": attr.string_list(),
97        "asflags": attr.string_list(),
98        "deps": attr.label_list(providers=[CcInfo, CcObjectInfo]),
99        "_cc_toolchain": attr.label(
100            default = Label("@local_config_cc//:toolchain"),
101            providers = [cc_common.CcToolchainInfo],
102        ),
103        "_android_product_variables": attr.label(
104            default = Label("//build/bazel/product_variables:android_product_variables"),
105            providers = [platform_common.TemplateVariableInfo],
106        ),
107    },
108    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
109    fragments = ["cpp"],
110)
111
112def cc_object(
113        name,
114        copts = [],
115        hdrs = [],
116        asflags = [],
117        srcs = [],
118        deps = [],
119        native_bridge_supported = False, # TODO: not supported yet.
120        **kwargs):
121    "Build macro to correspond with the cc_object Soong module."
122
123    _cc_object(
124        name = name,
125        hdrs = hdrs,
126        asflags = asflags,
127        copts = _CC_OBJECT_COPTS + copts,
128        srcs = srcs,
129        deps = deps,
130        **kwargs
131    )
132