| """ |
| Copyright (C) 2021 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| """ |
| |
| load( |
| ":cc_library_common.bzl", |
| "create_ccinfo_for_includes", |
| "is_external_directory", |
| "parse_sdk_version", |
| "system_dynamic_deps_defaults", |
| ) |
| load(":stl.bzl", "static_stl_deps") |
| load("@bazel_skylib//lib:collections.bzl", "collections") |
| load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain") |
| load("@rules_cc//examples:experimental_cc_shared_library.bzl", "CcSharedLibraryInfo") |
| load("//build/bazel/product_variables:constants.bzl", "constants") |
| |
| CcStaticLibraryInfo = provider(fields = ["root_static_archive", "objects"]) |
| |
| def cc_library_static( |
| name, |
| deps = [], |
| implementation_deps = [], |
| dynamic_deps = [], |
| implementation_dynamic_deps = [], |
| whole_archive_deps = [], |
| implementation_whole_archive_deps = [], |
| system_dynamic_deps = None, |
| export_absolute_includes = [], |
| export_includes = [], |
| export_system_includes = [], |
| local_includes = [], |
| absolute_includes = [], |
| hdrs = [], |
| native_bridge_supported = False, # TODO: not supported yet. |
| use_libcrt = True, |
| rtti = False, |
| stl = "", |
| cpp_std = "", |
| c_std = "", |
| # Flags for C and C++ |
| copts = [], |
| # C++ attributes |
| srcs = [], |
| cppflags = [], |
| # C attributes |
| srcs_c = [], |
| conlyflags = [], |
| # asm attributes |
| srcs_as = [], |
| asflags = [], |
| features = [], |
| alwayslink = None, |
| target_compatible_with = [], |
| # TODO(b/202299295): Handle data attribute. |
| data = [], |
| sdk_version = "", |
| min_sdk_version = "", |
| use_version_lib = False): |
| "Bazel macro to correspond with the cc_library_static Soong module." |
| |
| exports_name = "%s_exports" % name |
| locals_name = "%s_locals" % name |
| cpp_name = "%s_cpp" % name |
| c_name = "%s_c" % name |
| asm_name = "%s_asm" % name |
| |
| toolchain_features = [] |
| toolchain_features += features |
| |
| if is_external_directory(native.package_name()): |
| toolchain_features += [ |
| "-non_external_compiler_flags", |
| "external_compiler_flags", |
| ] |
| |
| if use_version_lib: |
| libbuildversionLabel = "//build/soong/cc/libbuildversion:libbuildversion" |
| whole_archive_deps = whole_archive_deps + [libbuildversionLabel] |
| |
| if rtti: |
| toolchain_features += ["rtti"] |
| if not use_libcrt: |
| toolchain_features += ["use_libcrt"] |
| if cpp_std: |
| toolchain_features += [cpp_std, "-cpp_std_default"] |
| if c_std: |
| toolchain_features += [c_std, "-c_std_default"] |
| |
| if min_sdk_version: |
| toolchain_features += [ |
| "sdk_version_" + parse_sdk_version(min_sdk_version), |
| "-sdk_version_default", |
| ] |
| |
| if system_dynamic_deps == None: |
| system_dynamic_deps = system_dynamic_deps_defaults |
| |
| _cc_includes( |
| name = exports_name, |
| includes = export_includes, |
| absolute_includes = export_absolute_includes, |
| system_includes = export_system_includes, |
| # whole archive deps always re-export their includes, etc |
| deps = deps + whole_archive_deps + dynamic_deps, |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| _cc_includes( |
| name = locals_name, |
| includes = local_includes, |
| absolute_includes = absolute_includes, |
| deps = implementation_deps + implementation_dynamic_deps + system_dynamic_deps + static_stl_deps(stl) + implementation_whole_archive_deps, |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| # Silently drop these attributes for now: |
| # - native_bridge_supported |
| common_attrs = dict( |
| [ |
| # TODO(b/199917423): This may be superfluous. Investigate and possibly remove. |
| ("linkstatic", True), |
| ("hdrs", hdrs), |
| # Add dynamic_deps to implementation_deps, as the include paths from the |
| # dynamic_deps are also needed. |
| ("implementation_deps", [locals_name]), |
| ("deps", [exports_name]), |
| ("features", toolchain_features), |
| ("toolchains", ["//build/bazel/platforms:android_target_product_vars"]), |
| ("alwayslink", alwayslink), |
| ("target_compatible_with", target_compatible_with), |
| ], |
| ) |
| |
| native.cc_library( |
| name = cpp_name, |
| srcs = srcs, |
| copts = copts + cppflags, |
| **common_attrs |
| ) |
| native.cc_library( |
| name = c_name, |
| srcs = srcs_c, |
| copts = copts + conlyflags, |
| **common_attrs |
| ) |
| native.cc_library( |
| name = asm_name, |
| srcs = srcs_as, |
| copts = asflags, |
| **common_attrs |
| ) |
| |
| # Root target to handle combining of the providers of the language-specific targets. |
| _cc_library_combiner( |
| name = name, |
| deps = [cpp_name, c_name, asm_name] + whole_archive_deps + implementation_whole_archive_deps, |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| # Returns a CcInfo object which combines one or more CcInfo objects, except that all |
| # linker inputs owned by owners in `old_owner_labels` are relinked and owned by the current target. |
| # |
| # This is useful in the "macro with proxy rule" pattern, as some rules upstream |
| # may expect they are depending directly on a target which generates linker inputs, |
| # as opposed to a proxy target which is a level of indirection to such a target. |
| def _cc_library_combiner_impl(ctx): |
| old_owner_labels = [] |
| cc_infos = [] |
| for dep in ctx.attr.deps: |
| old_owner_labels.append(dep.label) |
| cc_infos.append(dep[CcInfo]) |
| combined_info = cc_common.merge_cc_infos(cc_infos = cc_infos) |
| |
| objects_to_link = [] |
| |
| # This is not ideal, as it flattens a depset. |
| for old_linker_input in combined_info.linking_context.linker_inputs.to_list(): |
| if old_linker_input.owner in old_owner_labels: |
| for lib in old_linker_input.libraries: |
| # These objects will be recombined into the root archive. |
| objects_to_link.extend(lib.objects) |
| else: |
| # Android macros don't handle transitive linker dependencies because |
| # it's unsupported in legacy. We may want to change this going forward, |
| # but for now it's good to validate that this invariant remains. |
| fail("cc_static_library %s given transitive linker dependency from %s" % (ctx.label, old_linker_input.owner)) |
| |
| cc_toolchain = find_cpp_toolchain(ctx) |
| CPP_LINK_STATIC_LIBRARY_ACTION_NAME = "c++-link-static-library" |
| feature_configuration = cc_common.configure_features( |
| ctx = ctx, |
| cc_toolchain = cc_toolchain, |
| requested_features = ctx.features, |
| unsupported_features = ctx.disabled_features + ["linker_flags"], |
| ) |
| |
| output_file = ctx.actions.declare_file("lib" + ctx.label.name + ".a") |
| linker_input = cc_common.create_linker_input( |
| owner = ctx.label, |
| libraries = depset(direct = [ |
| cc_common.create_library_to_link( |
| actions = ctx.actions, |
| feature_configuration = feature_configuration, |
| cc_toolchain = cc_toolchain, |
| static_library = output_file, |
| objects = objects_to_link, |
| ), |
| ]), |
| ) |
| |
| linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input])) |
| |
| archiver_path = cc_common.get_tool_for_action( |
| feature_configuration = feature_configuration, |
| action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, |
| ) |
| archiver_variables = cc_common.create_link_variables( |
| feature_configuration = feature_configuration, |
| cc_toolchain = cc_toolchain, |
| output_file = output_file.path, |
| is_using_linker = False, |
| ) |
| command_line = cc_common.get_memory_inefficient_command_line( |
| feature_configuration = feature_configuration, |
| action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, |
| variables = archiver_variables, |
| ) |
| args = ctx.actions.args() |
| args.add_all(command_line) |
| args.add_all(objects_to_link) |
| |
| ctx.actions.run( |
| executable = archiver_path, |
| arguments = [args], |
| inputs = depset( |
| direct = objects_to_link, |
| transitive = [ |
| cc_toolchain.all_files, |
| ], |
| ), |
| outputs = [output_file], |
| ) |
| return [ |
| DefaultInfo(files = depset(direct = [output_file]), data_runfiles = ctx.runfiles(files = [output_file])), |
| CcInfo(compilation_context = combined_info.compilation_context, linking_context = linking_context), |
| CcStaticLibraryInfo(root_static_archive = output_file, objects = objects_to_link), |
| ] |
| |
| # A rule which combines objects of oen or more cc_library targets into a single |
| # static linker input. This outputs a single archive file combining the objects |
| # of its direct deps, and propagates Cc providers describing that these objects |
| # should be linked for linking rules upstream. |
| # This rule is useful for maintaining the illusion that the target's deps are |
| # comprised by a single consistent rule: |
| # - A single archive file is always output by this rule. |
| # - A single linker input struct is always output by this rule, and it is 'owned' |
| # by this rule. |
| _cc_library_combiner = rule( |
| implementation = _cc_library_combiner_impl, |
| attrs = { |
| "deps": attr.label_list(providers = [CcInfo]), |
| "_cc_toolchain": attr.label( |
| default = Label("@local_config_cc//:toolchain"), |
| providers = [cc_common.CcToolchainInfo], |
| ), |
| }, |
| toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], |
| provides = [CcInfo], |
| fragments = ["cpp"], |
| ) |
| |
| def _cc_includes_impl(ctx): |
| return [create_ccinfo_for_includes( |
| ctx, |
| includes = ctx.attr.includes, |
| absolute_includes = ctx.attr.absolute_includes, |
| system_includes = ctx.attr.system_includes, |
| deps = ctx.attr.deps, |
| )] |
| |
| # Bazel's native cc_library rule supports specifying include paths two ways: |
| # 1. non-exported includes can be specified via copts attribute |
| # 2. exported -isystem includes can be specified via includes attribute |
| # |
| # In order to guarantee a correct inclusion search order, we need to export |
| # includes paths for both -I and -isystem; however, there is no native Bazel |
| # support to export both of these, this rule provides a CcInfo to propagate the |
| # given package-relative include/system include paths as exec root relative |
| # include/system include paths. |
| _cc_includes = rule( |
| implementation = _cc_includes_impl, |
| attrs = { |
| "absolute_includes": attr.string_list(doc = "List of exec-root relative or absolute search paths for headers, usually passed with -I"), |
| "includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -I"), |
| "system_includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -isystem"), |
| "deps": attr.label_list(doc = "Re-propagates the includes obtained from these dependencies.", providers = [CcInfo]), |
| }, |
| toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], |
| fragments = ["cpp"], |
| provides = [CcInfo], |
| ) |