1*1b3f573fSAndroid Build Coastguard Worker# Rules for distributable C++ libraries 2*1b3f573fSAndroid Build Coastguard Worker 3*1b3f573fSAndroid Build Coastguard Workerload("@rules_cc//cc:action_names.bzl", cc_action_names = "ACTION_NAMES") 4*1b3f573fSAndroid Build Coastguard Workerload("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") 5*1b3f573fSAndroid Build Coastguard Worker 6*1b3f573fSAndroid Build Coastguard Worker# Creates an action to build the `output_file` static library (archive) 7*1b3f573fSAndroid Build Coastguard Worker# using `object_files`. 8*1b3f573fSAndroid Build Coastguard Workerdef _create_archive_action( 9*1b3f573fSAndroid Build Coastguard Worker ctx, 10*1b3f573fSAndroid Build Coastguard Worker feature_configuration, 11*1b3f573fSAndroid Build Coastguard Worker cc_toolchain, 12*1b3f573fSAndroid Build Coastguard Worker output_file, 13*1b3f573fSAndroid Build Coastguard Worker object_files): 14*1b3f573fSAndroid Build Coastguard Worker # Based on Bazel's src/main/starlark/builtins_bzl/common/cc/cc_import.bzl: 15*1b3f573fSAndroid Build Coastguard Worker 16*1b3f573fSAndroid Build Coastguard Worker # Build the command line and add args for all of the input files: 17*1b3f573fSAndroid Build Coastguard Worker archiver_variables = cc_common.create_link_variables( 18*1b3f573fSAndroid Build Coastguard Worker feature_configuration = feature_configuration, 19*1b3f573fSAndroid Build Coastguard Worker cc_toolchain = cc_toolchain, 20*1b3f573fSAndroid Build Coastguard Worker output_file = output_file.path, 21*1b3f573fSAndroid Build Coastguard Worker is_using_linker = False, 22*1b3f573fSAndroid Build Coastguard Worker ) 23*1b3f573fSAndroid Build Coastguard Worker command_line = cc_common.get_memory_inefficient_command_line( 24*1b3f573fSAndroid Build Coastguard Worker feature_configuration = feature_configuration, 25*1b3f573fSAndroid Build Coastguard Worker action_name = cc_action_names.cpp_link_static_library, 26*1b3f573fSAndroid Build Coastguard Worker variables = archiver_variables, 27*1b3f573fSAndroid Build Coastguard Worker ) 28*1b3f573fSAndroid Build Coastguard Worker args = ctx.actions.args() 29*1b3f573fSAndroid Build Coastguard Worker args.add_all(command_line) 30*1b3f573fSAndroid Build Coastguard Worker args.add_all(object_files) 31*1b3f573fSAndroid Build Coastguard Worker args.use_param_file("@%s", use_always = True) 32*1b3f573fSAndroid Build Coastguard Worker 33*1b3f573fSAndroid Build Coastguard Worker archiver_path = cc_common.get_tool_for_action( 34*1b3f573fSAndroid Build Coastguard Worker feature_configuration = feature_configuration, 35*1b3f573fSAndroid Build Coastguard Worker action_name = cc_action_names.cpp_link_static_library, 36*1b3f573fSAndroid Build Coastguard Worker ) 37*1b3f573fSAndroid Build Coastguard Worker 38*1b3f573fSAndroid Build Coastguard Worker env = cc_common.get_environment_variables( 39*1b3f573fSAndroid Build Coastguard Worker feature_configuration = feature_configuration, 40*1b3f573fSAndroid Build Coastguard Worker action_name = cc_action_names.cpp_link_static_library, 41*1b3f573fSAndroid Build Coastguard Worker variables = archiver_variables, 42*1b3f573fSAndroid Build Coastguard Worker ) 43*1b3f573fSAndroid Build Coastguard Worker 44*1b3f573fSAndroid Build Coastguard Worker ctx.actions.run( 45*1b3f573fSAndroid Build Coastguard Worker executable = archiver_path, 46*1b3f573fSAndroid Build Coastguard Worker arguments = [args], 47*1b3f573fSAndroid Build Coastguard Worker env = env, 48*1b3f573fSAndroid Build Coastguard Worker inputs = depset( 49*1b3f573fSAndroid Build Coastguard Worker direct = object_files, 50*1b3f573fSAndroid Build Coastguard Worker transitive = [ 51*1b3f573fSAndroid Build Coastguard Worker cc_toolchain.all_files, 52*1b3f573fSAndroid Build Coastguard Worker ], 53*1b3f573fSAndroid Build Coastguard Worker ), 54*1b3f573fSAndroid Build Coastguard Worker use_default_shell_env = True, 55*1b3f573fSAndroid Build Coastguard Worker outputs = [output_file], 56*1b3f573fSAndroid Build Coastguard Worker mnemonic = "CppArchiveDist", 57*1b3f573fSAndroid Build Coastguard Worker ) 58*1b3f573fSAndroid Build Coastguard Worker 59*1b3f573fSAndroid Build Coastguard Worker# Implementation for cc_dist_library rule. 60*1b3f573fSAndroid Build Coastguard Workerdef _cc_dist_library_impl(ctx): 61*1b3f573fSAndroid Build Coastguard Worker cc_toolchain_info = find_cc_toolchain(ctx) 62*1b3f573fSAndroid Build Coastguard Worker if cc_toolchain_info.ar_executable == None: 63*1b3f573fSAndroid Build Coastguard Worker return [] 64*1b3f573fSAndroid Build Coastguard Worker 65*1b3f573fSAndroid Build Coastguard Worker feature_configuration = cc_common.configure_features( 66*1b3f573fSAndroid Build Coastguard Worker ctx = ctx, 67*1b3f573fSAndroid Build Coastguard Worker cc_toolchain = cc_toolchain_info, 68*1b3f573fSAndroid Build Coastguard Worker ) 69*1b3f573fSAndroid Build Coastguard Worker 70*1b3f573fSAndroid Build Coastguard Worker # Collect the set of object files from the immediate deps. 71*1b3f573fSAndroid Build Coastguard Worker 72*1b3f573fSAndroid Build Coastguard Worker objs = [] 73*1b3f573fSAndroid Build Coastguard Worker pic_objs = [] 74*1b3f573fSAndroid Build Coastguard Worker for dep in ctx.attr.deps: 75*1b3f573fSAndroid Build Coastguard Worker if CcInfo not in dep: 76*1b3f573fSAndroid Build Coastguard Worker continue 77*1b3f573fSAndroid Build Coastguard Worker 78*1b3f573fSAndroid Build Coastguard Worker link_ctx = dep[CcInfo].linking_context 79*1b3f573fSAndroid Build Coastguard Worker if link_ctx == None: 80*1b3f573fSAndroid Build Coastguard Worker continue 81*1b3f573fSAndroid Build Coastguard Worker 82*1b3f573fSAndroid Build Coastguard Worker linker_inputs = link_ctx.linker_inputs.to_list() 83*1b3f573fSAndroid Build Coastguard Worker for link_input in linker_inputs: 84*1b3f573fSAndroid Build Coastguard Worker if link_input.owner != dep.label: 85*1b3f573fSAndroid Build Coastguard Worker # This is a transitive dep: skip it. 86*1b3f573fSAndroid Build Coastguard Worker continue 87*1b3f573fSAndroid Build Coastguard Worker 88*1b3f573fSAndroid Build Coastguard Worker for lib in link_input.libraries: 89*1b3f573fSAndroid Build Coastguard Worker objs.extend(lib.objects or []) 90*1b3f573fSAndroid Build Coastguard Worker pic_objs.extend(lib.pic_objects or []) 91*1b3f573fSAndroid Build Coastguard Worker 92*1b3f573fSAndroid Build Coastguard Worker # For static libraries, build separately with and without pic. 93*1b3f573fSAndroid Build Coastguard Worker 94*1b3f573fSAndroid Build Coastguard Worker stemname = "lib" + ctx.label.name 95*1b3f573fSAndroid Build Coastguard Worker outputs = [] 96*1b3f573fSAndroid Build Coastguard Worker 97*1b3f573fSAndroid Build Coastguard Worker if len(objs) > 0: 98*1b3f573fSAndroid Build Coastguard Worker archive_out = ctx.actions.declare_file(stemname + ".a") 99*1b3f573fSAndroid Build Coastguard Worker _create_archive_action( 100*1b3f573fSAndroid Build Coastguard Worker ctx, 101*1b3f573fSAndroid Build Coastguard Worker feature_configuration, 102*1b3f573fSAndroid Build Coastguard Worker cc_toolchain_info, 103*1b3f573fSAndroid Build Coastguard Worker archive_out, 104*1b3f573fSAndroid Build Coastguard Worker objs, 105*1b3f573fSAndroid Build Coastguard Worker ) 106*1b3f573fSAndroid Build Coastguard Worker outputs.append(archive_out) 107*1b3f573fSAndroid Build Coastguard Worker 108*1b3f573fSAndroid Build Coastguard Worker if len(pic_objs) > 0: 109*1b3f573fSAndroid Build Coastguard Worker pic_archive_out = ctx.actions.declare_file(stemname + ".pic.a") 110*1b3f573fSAndroid Build Coastguard Worker _create_archive_action( 111*1b3f573fSAndroid Build Coastguard Worker ctx, 112*1b3f573fSAndroid Build Coastguard Worker feature_configuration, 113*1b3f573fSAndroid Build Coastguard Worker cc_toolchain_info, 114*1b3f573fSAndroid Build Coastguard Worker pic_archive_out, 115*1b3f573fSAndroid Build Coastguard Worker pic_objs, 116*1b3f573fSAndroid Build Coastguard Worker ) 117*1b3f573fSAndroid Build Coastguard Worker outputs.append(pic_archive_out) 118*1b3f573fSAndroid Build Coastguard Worker 119*1b3f573fSAndroid Build Coastguard Worker # For dynamic libraries, use the `cc_common.link` command to ensure 120*1b3f573fSAndroid Build Coastguard Worker # everything gets built correctly according to toolchain definitions. 121*1b3f573fSAndroid Build Coastguard Worker 122*1b3f573fSAndroid Build Coastguard Worker compilation_outputs = cc_common.create_compilation_outputs( 123*1b3f573fSAndroid Build Coastguard Worker objects = depset(objs), 124*1b3f573fSAndroid Build Coastguard Worker pic_objects = depset(pic_objs), 125*1b3f573fSAndroid Build Coastguard Worker ) 126*1b3f573fSAndroid Build Coastguard Worker link_output = cc_common.link( 127*1b3f573fSAndroid Build Coastguard Worker actions = ctx.actions, 128*1b3f573fSAndroid Build Coastguard Worker feature_configuration = feature_configuration, 129*1b3f573fSAndroid Build Coastguard Worker cc_toolchain = cc_toolchain_info, 130*1b3f573fSAndroid Build Coastguard Worker compilation_outputs = compilation_outputs, 131*1b3f573fSAndroid Build Coastguard Worker name = ctx.label.name, 132*1b3f573fSAndroid Build Coastguard Worker output_type = "dynamic_library", 133*1b3f573fSAndroid Build Coastguard Worker user_link_flags = ctx.attr.linkopts, 134*1b3f573fSAndroid Build Coastguard Worker ) 135*1b3f573fSAndroid Build Coastguard Worker library_to_link = link_output.library_to_link 136*1b3f573fSAndroid Build Coastguard Worker 137*1b3f573fSAndroid Build Coastguard Worker # Note: library_to_link.dynamic_library and interface_library are often 138*1b3f573fSAndroid Build Coastguard Worker # symlinks in the solib directory. For DefaultInfo, prefer reporting 139*1b3f573fSAndroid Build Coastguard Worker # the resolved artifact paths. 140*1b3f573fSAndroid Build Coastguard Worker if library_to_link.resolved_symlink_dynamic_library != None: 141*1b3f573fSAndroid Build Coastguard Worker outputs.append(library_to_link.resolved_symlink_dynamic_library) 142*1b3f573fSAndroid Build Coastguard Worker elif library_to_link.dynamic_library != None: 143*1b3f573fSAndroid Build Coastguard Worker outputs.append(library_to_link.dynamic_library) 144*1b3f573fSAndroid Build Coastguard Worker 145*1b3f573fSAndroid Build Coastguard Worker if library_to_link.resolved_symlink_interface_library != None: 146*1b3f573fSAndroid Build Coastguard Worker outputs.append(library_to_link.resolved_symlink_interface_library) 147*1b3f573fSAndroid Build Coastguard Worker elif library_to_link.interface_library != None: 148*1b3f573fSAndroid Build Coastguard Worker outputs.append(library_to_link.interface_library) 149*1b3f573fSAndroid Build Coastguard Worker 150*1b3f573fSAndroid Build Coastguard Worker # We could expose the libraries for use from cc rules: 151*1b3f573fSAndroid Build Coastguard Worker # 152*1b3f573fSAndroid Build Coastguard Worker # linking_context = cc_common.create_linking_context( 153*1b3f573fSAndroid Build Coastguard Worker # linker_inputs = depset([ 154*1b3f573fSAndroid Build Coastguard Worker # cc_common.create_linker_input( 155*1b3f573fSAndroid Build Coastguard Worker # owner = ctx.label, 156*1b3f573fSAndroid Build Coastguard Worker # libraries = depset([library_to_link]), 157*1b3f573fSAndroid Build Coastguard Worker # ), 158*1b3f573fSAndroid Build Coastguard Worker # ]), 159*1b3f573fSAndroid Build Coastguard Worker # ) 160*1b3f573fSAndroid Build Coastguard Worker # cc_info = CcInfo(linking_context = linking_context) # and return this 161*1b3f573fSAndroid Build Coastguard Worker # 162*1b3f573fSAndroid Build Coastguard Worker # However, if the goal is to force a protobuf dependency to use the 163*1b3f573fSAndroid Build Coastguard Worker # DSO, then `cc_import` is a better-supported way to do so. 164*1b3f573fSAndroid Build Coastguard Worker # 165*1b3f573fSAndroid Build Coastguard Worker # If we wanted to expose CcInfo from this rule (and make it usable as a 166*1b3f573fSAndroid Build Coastguard Worker # C++ dependency), then we would probably want to include the static 167*1b3f573fSAndroid Build Coastguard Worker # archive and headers as well. exposing headers would probably require 168*1b3f573fSAndroid Build Coastguard Worker # an additional aspect to extract CcInfos with just the deps' headers. 169*1b3f573fSAndroid Build Coastguard Worker 170*1b3f573fSAndroid Build Coastguard Worker return [ 171*1b3f573fSAndroid Build Coastguard Worker DefaultInfo(files = depset(outputs)), 172*1b3f573fSAndroid Build Coastguard Worker ] 173*1b3f573fSAndroid Build Coastguard Worker 174*1b3f573fSAndroid Build Coastguard Workercc_dist_library = rule( 175*1b3f573fSAndroid Build Coastguard Worker implementation = _cc_dist_library_impl, 176*1b3f573fSAndroid Build Coastguard Worker doc = """ 177*1b3f573fSAndroid Build Coastguard WorkerCreate libraries suitable for distribution. 178*1b3f573fSAndroid Build Coastguard Worker 179*1b3f573fSAndroid Build Coastguard WorkerThis rule creates static and dynamic libraries from the libraries listed in 180*1b3f573fSAndroid Build Coastguard Worker'deps'. The resulting libraries are suitable for distributing all of 'deps' 181*1b3f573fSAndroid Build Coastguard Workerin a single logical library, for example, in an installable binary package. 182*1b3f573fSAndroid Build Coastguard WorkerOnly the targets listed in 'deps' are included in the result (i.e., the 183*1b3f573fSAndroid Build Coastguard Workeroutput does not include transitive dependencies), allowing precise control 184*1b3f573fSAndroid Build Coastguard Workerover the library boundary. 185*1b3f573fSAndroid Build Coastguard Worker 186*1b3f573fSAndroid Build Coastguard WorkerThe outputs of this rule are a dynamic library and a static library. (If 187*1b3f573fSAndroid Build Coastguard Workerthe build produces both PIC and non-PIC object files, then there is also a 188*1b3f573fSAndroid Build Coastguard Workersecond static library.) The example below illustrates additional details. 189*1b3f573fSAndroid Build Coastguard Worker 190*1b3f573fSAndroid Build Coastguard WorkerThis rule is different from Bazel's experimental `shared_cc_library` in 191*1b3f573fSAndroid Build Coastguard Workerseveral ways. First, this rule ignores transitive dependencies, which means 192*1b3f573fSAndroid Build Coastguard Workerthat dynamic library dependencies generally need to be specified via 193*1b3f573fSAndroid Build Coastguard Worker'linkopts'. Second, this rule produces a static archive library in addition 194*1b3f573fSAndroid Build Coastguard Workerto the dynamic shared library. Third, this rule is not directly usable as a 195*1b3f573fSAndroid Build Coastguard WorkerC++ dependency (although the outputs could be used, e.g., by `cc_import`). 196*1b3f573fSAndroid Build Coastguard Worker 197*1b3f573fSAndroid Build Coastguard WorkerExample: 198*1b3f573fSAndroid Build Coastguard Worker 199*1b3f573fSAndroid Build Coastguard Worker cc_library(name = "a", srcs = ["a.cc"], hdrs = ["a.h"]) 200*1b3f573fSAndroid Build Coastguard Worker cc_library(name = "b", srcs = ["b.cc"], hdrs = ["b.h"], deps = [":a"]) 201*1b3f573fSAndroid Build Coastguard Worker cc_library(name = "c", srcs = ["c.cc"], hdrs = ["c.h"], deps = [":b"]) 202*1b3f573fSAndroid Build Coastguard Worker 203*1b3f573fSAndroid Build Coastguard Worker # Creates libdist.so and (typically) libdist.pic.a: 204*1b3f573fSAndroid Build Coastguard Worker # (This may also produce libdist.a if the build produces non-PIC objects.) 205*1b3f573fSAndroid Build Coastguard Worker cc_dist_library( 206*1b3f573fSAndroid Build Coastguard Worker name = "dist", 207*1b3f573fSAndroid Build Coastguard Worker linkopts = ["-la"], # libdist.so dynamically links against liba.so. 208*1b3f573fSAndroid Build Coastguard Worker deps = [":b", ":c"], # Output contains b.o and c.o, but not a.o. 209*1b3f573fSAndroid Build Coastguard Worker ) 210*1b3f573fSAndroid Build Coastguard Worker""", 211*1b3f573fSAndroid Build Coastguard Worker attrs = { 212*1b3f573fSAndroid Build Coastguard Worker "deps": attr.label_list( 213*1b3f573fSAndroid Build Coastguard Worker doc = ("The list of libraries to be included in the outputs. " + 214*1b3f573fSAndroid Build Coastguard Worker "Only these targets' compilation outputs will be " + 215*1b3f573fSAndroid Build Coastguard Worker "included (i.e., the transitive dependencies are not " + 216*1b3f573fSAndroid Build Coastguard Worker "included in the output)."), 217*1b3f573fSAndroid Build Coastguard Worker ), 218*1b3f573fSAndroid Build Coastguard Worker "linkopts": attr.string_list( 219*1b3f573fSAndroid Build Coastguard Worker doc = ("Add these flags to the C++ linker command when creating " + 220*1b3f573fSAndroid Build Coastguard Worker "the dynamic library."), 221*1b3f573fSAndroid Build Coastguard Worker ), 222*1b3f573fSAndroid Build Coastguard Worker # C++ toolchain before https://github.com/bazelbuild/bazel/issues/7260: 223*1b3f573fSAndroid Build Coastguard Worker "_cc_toolchain": attr.label( 224*1b3f573fSAndroid Build Coastguard Worker default = Label("@rules_cc//cc:current_cc_toolchain"), 225*1b3f573fSAndroid Build Coastguard Worker ), 226*1b3f573fSAndroid Build Coastguard Worker }, 227*1b3f573fSAndroid Build Coastguard Worker toolchains = [ 228*1b3f573fSAndroid Build Coastguard Worker # C++ toolchain after https://github.com/bazelbuild/bazel/issues/7260: 229*1b3f573fSAndroid Build Coastguard Worker "@bazel_tools//tools/cpp:toolchain_type", 230*1b3f573fSAndroid Build Coastguard Worker ], 231*1b3f573fSAndroid Build Coastguard Worker fragments = ["cpp"], 232*1b3f573fSAndroid Build Coastguard Worker) 233