• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Copyright (C) 2021 The Android Open Source Project
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15"""
16
17load(
18    ":cc_library_common.bzl",
19    "create_ccinfo_for_includes",
20    "is_external_directory",
21    "parse_sdk_version",
22    "system_dynamic_deps_defaults",
23)
24load(":stl.bzl", "static_stl_deps")
25load("@bazel_skylib//lib:collections.bzl", "collections")
26load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain")
27load("@rules_cc//examples:experimental_cc_shared_library.bzl", "CcSharedLibraryInfo")
28load("//build/bazel/product_variables:constants.bzl", "constants")
29
30CcStaticLibraryInfo = provider(fields = ["root_static_archive", "objects"])
31
32def cc_library_static(
33        name,
34        deps = [],
35        implementation_deps = [],
36        dynamic_deps = [],
37        implementation_dynamic_deps = [],
38        whole_archive_deps = [],
39        implementation_whole_archive_deps = [],
40        system_dynamic_deps = None,
41        export_absolute_includes = [],
42        export_includes = [],
43        export_system_includes = [],
44        local_includes = [],
45        absolute_includes = [],
46        hdrs = [],
47        native_bridge_supported = False,  # TODO: not supported yet.
48        use_libcrt = True,
49        rtti = False,
50        stl = "",
51        cpp_std = "",
52        c_std = "",
53        # Flags for C and C++
54        copts = [],
55        # C++ attributes
56        srcs = [],
57        cppflags = [],
58        # C attributes
59        srcs_c = [],
60        conlyflags = [],
61        # asm attributes
62        srcs_as = [],
63        asflags = [],
64        features = [],
65        alwayslink = None,
66        target_compatible_with = [],
67        # TODO(b/202299295): Handle data attribute.
68        data = [],
69        sdk_version = "",
70        min_sdk_version = "",
71        use_version_lib = False):
72    "Bazel macro to correspond with the cc_library_static Soong module."
73
74    exports_name = "%s_exports" % name
75    locals_name = "%s_locals" % name
76    cpp_name = "%s_cpp" % name
77    c_name = "%s_c" % name
78    asm_name = "%s_asm" % name
79
80    toolchain_features = []
81    toolchain_features += features
82
83    if is_external_directory(native.package_name()):
84        toolchain_features += [
85            "-non_external_compiler_flags",
86            "external_compiler_flags",
87        ]
88
89    if use_version_lib:
90        libbuildversionLabel = "//build/soong/cc/libbuildversion:libbuildversion"
91        whole_archive_deps = whole_archive_deps + [libbuildversionLabel]
92
93    if rtti:
94        toolchain_features += ["rtti"]
95    if not use_libcrt:
96        toolchain_features += ["use_libcrt"]
97    if cpp_std:
98        toolchain_features += [cpp_std, "-cpp_std_default"]
99    if c_std:
100        toolchain_features += [c_std, "-c_std_default"]
101
102    if min_sdk_version:
103        toolchain_features += [
104            "sdk_version_" + parse_sdk_version(min_sdk_version),
105            "-sdk_version_default",
106        ]
107
108    if system_dynamic_deps == None:
109        system_dynamic_deps = system_dynamic_deps_defaults
110
111    _cc_includes(
112        name = exports_name,
113        includes = export_includes,
114        absolute_includes = export_absolute_includes,
115        system_includes = export_system_includes,
116        # whole archive deps always re-export their includes, etc
117        deps = deps + whole_archive_deps + dynamic_deps,
118        target_compatible_with = target_compatible_with,
119    )
120
121    _cc_includes(
122        name = locals_name,
123        includes = local_includes,
124        absolute_includes = absolute_includes,
125        deps = implementation_deps + implementation_dynamic_deps + system_dynamic_deps + static_stl_deps(stl) + implementation_whole_archive_deps,
126        target_compatible_with = target_compatible_with,
127    )
128
129    # Silently drop these attributes for now:
130    # - native_bridge_supported
131    common_attrs = dict(
132        [
133            # TODO(b/199917423): This may be superfluous. Investigate and possibly remove.
134            ("linkstatic", True),
135            ("hdrs", hdrs),
136            # Add dynamic_deps to implementation_deps, as the include paths from the
137            # dynamic_deps are also needed.
138            ("implementation_deps", [locals_name]),
139            ("deps", [exports_name]),
140            ("features", toolchain_features),
141            ("toolchains", ["//build/bazel/platforms:android_target_product_vars"]),
142            ("alwayslink", alwayslink),
143            ("target_compatible_with", target_compatible_with),
144        ],
145    )
146
147    native.cc_library(
148        name = cpp_name,
149        srcs = srcs,
150        copts = copts + cppflags,
151        **common_attrs
152    )
153    native.cc_library(
154        name = c_name,
155        srcs = srcs_c,
156        copts = copts + conlyflags,
157        **common_attrs
158    )
159    native.cc_library(
160        name = asm_name,
161        srcs = srcs_as,
162        copts = asflags,
163        **common_attrs
164    )
165
166    # Root target to handle combining of the providers of the language-specific targets.
167    _cc_library_combiner(
168        name = name,
169        deps = [cpp_name, c_name, asm_name] + whole_archive_deps + implementation_whole_archive_deps,
170        target_compatible_with = target_compatible_with,
171    )
172
173# Returns a CcInfo object which combines one or more CcInfo objects, except that all
174# linker inputs owned by  owners in `old_owner_labels` are relinked and owned by the current target.
175#
176# This is useful in the "macro with proxy rule" pattern, as some rules upstream
177# may expect they are depending directly on a target which generates linker inputs,
178# as opposed to a proxy target which is a level of indirection to such a target.
179def _cc_library_combiner_impl(ctx):
180    old_owner_labels = []
181    cc_infos = []
182    for dep in ctx.attr.deps:
183        old_owner_labels.append(dep.label)
184        cc_infos.append(dep[CcInfo])
185    combined_info = cc_common.merge_cc_infos(cc_infos = cc_infos)
186
187    objects_to_link = []
188
189    # This is not ideal, as it flattens a depset.
190    for old_linker_input in combined_info.linking_context.linker_inputs.to_list():
191        if old_linker_input.owner in old_owner_labels:
192            for lib in old_linker_input.libraries:
193                # These objects will be recombined into the root archive.
194                objects_to_link.extend(lib.objects)
195        else:
196            # Android macros don't handle transitive linker dependencies because
197            # it's unsupported in legacy. We may want to change this going forward,
198            # but for now it's good to validate that this invariant remains.
199            fail("cc_static_library %s given transitive linker dependency from %s" % (ctx.label, old_linker_input.owner))
200
201    cc_toolchain = find_cpp_toolchain(ctx)
202    CPP_LINK_STATIC_LIBRARY_ACTION_NAME = "c++-link-static-library"
203    feature_configuration = cc_common.configure_features(
204        ctx = ctx,
205        cc_toolchain = cc_toolchain,
206        requested_features = ctx.features,
207        unsupported_features = ctx.disabled_features + ["linker_flags"],
208    )
209
210    output_file = ctx.actions.declare_file("lib" + ctx.label.name + ".a")
211    linker_input = cc_common.create_linker_input(
212        owner = ctx.label,
213        libraries = depset(direct = [
214            cc_common.create_library_to_link(
215                actions = ctx.actions,
216                feature_configuration = feature_configuration,
217                cc_toolchain = cc_toolchain,
218                static_library = output_file,
219                objects = objects_to_link,
220            ),
221        ]),
222    )
223
224    linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input]))
225
226    archiver_path = cc_common.get_tool_for_action(
227        feature_configuration = feature_configuration,
228        action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
229    )
230    archiver_variables = cc_common.create_link_variables(
231        feature_configuration = feature_configuration,
232        cc_toolchain = cc_toolchain,
233        output_file = output_file.path,
234        is_using_linker = False,
235    )
236    command_line = cc_common.get_memory_inefficient_command_line(
237        feature_configuration = feature_configuration,
238        action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
239        variables = archiver_variables,
240    )
241    args = ctx.actions.args()
242    args.add_all(command_line)
243    args.add_all(objects_to_link)
244
245    ctx.actions.run(
246        executable = archiver_path,
247        arguments = [args],
248        inputs = depset(
249            direct = objects_to_link,
250            transitive = [
251                cc_toolchain.all_files,
252            ],
253        ),
254        outputs = [output_file],
255    )
256    return [
257        DefaultInfo(files = depset(direct = [output_file]), data_runfiles = ctx.runfiles(files = [output_file])),
258        CcInfo(compilation_context = combined_info.compilation_context, linking_context = linking_context),
259        CcStaticLibraryInfo(root_static_archive = output_file, objects = objects_to_link),
260    ]
261
262# A rule which combines objects of oen or more cc_library targets into a single
263# static linker input. This outputs a single archive file combining the objects
264# of its direct deps, and propagates Cc providers describing that these objects
265# should be linked for linking rules upstream.
266# This rule is useful for maintaining the illusion that the target's deps are
267# comprised by a single consistent rule:
268#   - A single archive file is always output by this rule.
269#   - A single linker input struct is always output by this rule, and it is 'owned'
270#       by this rule.
271_cc_library_combiner = rule(
272    implementation = _cc_library_combiner_impl,
273    attrs = {
274        "deps": attr.label_list(providers = [CcInfo]),
275        "_cc_toolchain": attr.label(
276            default = Label("@local_config_cc//:toolchain"),
277            providers = [cc_common.CcToolchainInfo],
278        ),
279    },
280    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
281    provides = [CcInfo],
282    fragments = ["cpp"],
283)
284
285def _cc_includes_impl(ctx):
286    return [create_ccinfo_for_includes(
287        ctx,
288        includes = ctx.attr.includes,
289        absolute_includes = ctx.attr.absolute_includes,
290        system_includes = ctx.attr.system_includes,
291        deps = ctx.attr.deps,
292    )]
293
294# Bazel's native cc_library rule supports specifying include paths two ways:
295# 1. non-exported includes can be specified via copts attribute
296# 2. exported -isystem includes can be specified via includes attribute
297#
298# In order to guarantee a correct inclusion search order, we need to export
299# includes paths for both -I and -isystem; however, there is no native Bazel
300# support to export both of these, this rule provides a CcInfo to propagate the
301# given package-relative include/system include paths as exec root relative
302# include/system include paths.
303_cc_includes = rule(
304    implementation = _cc_includes_impl,
305    attrs = {
306        "absolute_includes": attr.string_list(doc = "List of exec-root relative or absolute search paths for headers, usually passed with -I"),
307        "includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -I"),
308        "system_includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -isystem"),
309        "deps": attr.label_list(doc = "Re-propagates the includes obtained from these dependencies.", providers = [CcInfo]),
310    },
311    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
312    fragments = ["cpp"],
313    provides = [CcInfo],
314)
315