1# Protocol Buffers - Google's data interchange format 2# Copyright 2024 Google Inc. All rights reserved. 3# 4# Use of this source code is governed by a BSD-style 5# license that can be found in the LICENSE file or at 6# https://developers.google.com/open-source/licenses/bsd 7# 8"""Supporting C++ compilation of generated code""" 9 10load("@proto_bazel_features//:features.bzl", "bazel_features") 11load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") 12load("@rules_cc//cc/common:cc_common.bzl", "cc_common") 13load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") 14 15def get_feature_configuration(ctx, has_sources, extra_requested_features = []): 16 """Returns C++ feature configuration for compiling and linking generated C++ files. 17 18 Args: 19 ctx: (RuleCtx) rule context. 20 has_sources: (bool) Has the proto_library sources. 21 extra_requested_features: (list[str]) Additionally requested features. 22 Returns: 23 (FeatureConfiguration) C++ feature configuration 24 """ 25 cc_toolchain = find_cc_toolchain(ctx) 26 requested_features = ctx.features + extra_requested_features 27 28 # TODO: Remove LAYERING_CHECK once we have verified that there are direct 29 # dependencies for all generated #includes. 30 unsupported_features = ctx.disabled_features + ["parse_headers", "layering_check"] 31 if has_sources: 32 requested_features.append("header_modules") 33 else: 34 unsupported_features.append("header_modules") 35 return cc_common.configure_features( 36 ctx = ctx, 37 cc_toolchain = cc_toolchain, 38 requested_features = requested_features, 39 unsupported_features = unsupported_features, 40 ) 41 42def _get_libraries_from_linking_outputs(linking_outputs, feature_configuration): 43 library_to_link = linking_outputs.library_to_link 44 if not library_to_link: 45 return [] 46 outputs = [] 47 if library_to_link.static_library: 48 outputs.append(library_to_link.static_library) 49 if library_to_link.pic_static_library: 50 outputs.append(library_to_link.pic_static_library) 51 52 # On Windows, dynamic library is not built by default, so don't add them to files_to_build. 53 if not cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "targets_windows"): 54 if library_to_link.resolved_symlink_dynamic_library: 55 outputs.append(library_to_link.resolved_symlink_dynamic_library) 56 elif library_to_link.dynamic_library: 57 outputs.append(library_to_link.dynamic_library) 58 if library_to_link.resolved_symlink_interface_library: 59 outputs.append(library_to_link.resolved_symlink_interface_library) 60 elif library_to_link.interface_library: 61 outputs.append(library_to_link.interface_library) 62 return outputs 63 64def cc_proto_compile_and_link(ctx, deps, sources, headers, disallow_dynamic_library = None, feature_configuration = None, alwayslink = False, **kwargs): 65 """Creates C++ compilation and linking actions for C++ proto sources. 66 67 Args: 68 ctx: rule context 69 deps: (list[CcInfo]) List of libraries to be added as dependencies to compilation and linking 70 actions. 71 sources:(list[File]) List of C++ sources files. 72 headers: list(File] List of C++ headers files. 73 disallow_dynamic_library: (bool) Are dynamic libraries disallowed. 74 feature_configuration: (FeatureConfiguration) feature configuration to use. 75 alwayslink: (bool) Should the library be always linked. 76 **kwargs: Additional arguments passed to the compilation. See cc_common.compile. 77 78 Returns: 79 (CcInfo, list[File], list[File]) 80 - CcInfo provider with compilation context and linking context 81 - A list of linked libraries related to this proto 82 - A list of temporary files generated durind compilation 83 """ 84 cc_toolchain = find_cc_toolchain(ctx) 85 feature_configuration = feature_configuration or get_feature_configuration(ctx, bool(sources)) 86 if disallow_dynamic_library == None: 87 # TODO: Configure output artifact with action_config 88 # once proto compile action is configurable from the crosstool. 89 disallow_dynamic_library = not cc_common.is_enabled( 90 feature_name = "supports_dynamic_linker", 91 feature_configuration = feature_configuration, 92 ) 93 94 (compilation_context, compilation_outputs) = cc_common.compile( 95 actions = ctx.actions, 96 feature_configuration = feature_configuration, 97 cc_toolchain = cc_toolchain, 98 srcs = sources, 99 public_hdrs = headers, 100 compilation_contexts = [dep[CcInfo].compilation_context for dep in deps if CcInfo in dep], 101 name = ctx.label.name, 102 # Don't instrument the generated C++ files even when --collect_code_coverage is set. 103 # If we actually start generating coverage instrumentation for .proto files based on coverage 104 # data from the generated C++ files, this will have to be removed. Currently, the work done 105 # to instrument those files and execute the instrumentation is all for nothing, and it can 106 # be quite a bit of extra computation even when that's not made worse by performance bugs, 107 # as in b/64963386. 108 # code_coverage_enabled = False (cc_common.compile disables code_coverage by default) 109 **kwargs 110 ) 111 112 if sources: 113 linking_context, linking_outputs = cc_common.create_linking_context_from_compilation_outputs( 114 actions = ctx.actions, 115 feature_configuration = feature_configuration, 116 cc_toolchain = cc_toolchain, 117 compilation_outputs = compilation_outputs, 118 linking_contexts = [dep[CcInfo].linking_context for dep in deps if CcInfo in dep], 119 name = ctx.label.name, 120 disallow_dynamic_library = disallow_dynamic_library, 121 alwayslink = alwayslink, 122 ) 123 libraries = _get_libraries_from_linking_outputs(linking_outputs, feature_configuration) 124 else: 125 linking_context = cc_common.merge_linking_contexts( 126 linking_contexts = [dep[CcInfo].linking_context for dep in deps if CcInfo in dep], 127 ) 128 libraries = [] 129 130 debug_context = None 131 temps = [] 132 if bazel_features.cc.protobuf_on_allowlist: 133 debug_context = cc_common.merge_debug_context( 134 [cc_common.create_debug_context(compilation_outputs)] + 135 [dep[CcInfo].debug_context() for dep in deps if CcInfo in dep], 136 ) 137 temps = compilation_outputs.temps() 138 139 return CcInfo( 140 compilation_context = compilation_context, 141 linking_context = linking_context, 142 debug_context = debug_context, 143 ), libraries, temps 144