1*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2021 The gRPC Authors 2*cc02d7e2SAndroid Build Coastguard Worker# 3*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*cc02d7e2SAndroid Build Coastguard Worker# 7*cc02d7e2SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*cc02d7e2SAndroid Build Coastguard Worker# 9*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License. 14*cc02d7e2SAndroid Build Coastguard Worker 15*cc02d7e2SAndroid Build Coastguard Worker""" 16*cc02d7e2SAndroid Build Coastguard WorkerThis module contains build rules relating to gRPC Objective-C. 17*cc02d7e2SAndroid Build Coastguard Worker""" 18*cc02d7e2SAndroid Build Coastguard Worker 19*cc02d7e2SAndroid Build Coastguard Workerload("@rules_proto//proto:defs.bzl", "ProtoInfo") 20*cc02d7e2SAndroid Build Coastguard Workerload( 21*cc02d7e2SAndroid Build Coastguard Worker "//bazel:protobuf.bzl", 22*cc02d7e2SAndroid Build Coastguard Worker "get_include_directory", 23*cc02d7e2SAndroid Build Coastguard Worker "get_plugin_args", 24*cc02d7e2SAndroid Build Coastguard Worker "proto_path_to_generated_filename", 25*cc02d7e2SAndroid Build Coastguard Worker) 26*cc02d7e2SAndroid Build Coastguard Workerload(":grpc_util.bzl", "to_upper_camel_with_extension") 27*cc02d7e2SAndroid Build Coastguard Worker 28*cc02d7e2SAndroid Build Coastguard Worker_GRPC_PROTO_HEADER_FMT = "{}.pbrpc.h" 29*cc02d7e2SAndroid Build Coastguard Worker_GRPC_PROTO_SRC_FMT = "{}.pbrpc.m" 30*cc02d7e2SAndroid Build Coastguard Worker_PROTO_HEADER_FMT = "{}.pbobjc.h" 31*cc02d7e2SAndroid Build Coastguard Worker_PROTO_SRC_FMT = "{}.pbobjc.m" 32*cc02d7e2SAndroid Build Coastguard Worker_GENERATED_PROTOS_DIR = "_generated_protos" 33*cc02d7e2SAndroid Build Coastguard Worker 34*cc02d7e2SAndroid Build Coastguard Worker_GENERATE_HDRS = 1 35*cc02d7e2SAndroid Build Coastguard Worker_GENERATE_SRCS = 2 36*cc02d7e2SAndroid Build Coastguard Worker_GENERATE_NON_ARC_SRCS = 3 37*cc02d7e2SAndroid Build Coastguard Worker 38*cc02d7e2SAndroid Build Coastguard Workerdef _generate_objc_impl(ctx): 39*cc02d7e2SAndroid Build Coastguard Worker """Implementation of the generate_objc rule.""" 40*cc02d7e2SAndroid Build Coastguard Worker protos = [ 41*cc02d7e2SAndroid Build Coastguard Worker f 42*cc02d7e2SAndroid Build Coastguard Worker for src in ctx.attr.deps 43*cc02d7e2SAndroid Build Coastguard Worker for f in src[ProtoInfo].transitive_imports.to_list() 44*cc02d7e2SAndroid Build Coastguard Worker ] 45*cc02d7e2SAndroid Build Coastguard Worker 46*cc02d7e2SAndroid Build Coastguard Worker target_package = _join_directories([ctx.label.workspace_root, ctx.label.package]) 47*cc02d7e2SAndroid Build Coastguard Worker 48*cc02d7e2SAndroid Build Coastguard Worker files_with_rpc = [_label_to_full_file_path(f, target_package) for f in ctx.attr.srcs] 49*cc02d7e2SAndroid Build Coastguard Worker 50*cc02d7e2SAndroid Build Coastguard Worker outs = [] 51*cc02d7e2SAndroid Build Coastguard Worker for proto in protos: 52*cc02d7e2SAndroid Build Coastguard Worker outs.append(_get_output_file_name_from_proto(proto, _PROTO_HEADER_FMT)) 53*cc02d7e2SAndroid Build Coastguard Worker outs.append(_get_output_file_name_from_proto(proto, _PROTO_SRC_FMT)) 54*cc02d7e2SAndroid Build Coastguard Worker 55*cc02d7e2SAndroid Build Coastguard Worker file_path = _get_full_path_from_file(proto) 56*cc02d7e2SAndroid Build Coastguard Worker if file_path in files_with_rpc: 57*cc02d7e2SAndroid Build Coastguard Worker outs.append(_get_output_file_name_from_proto(proto, _GRPC_PROTO_HEADER_FMT)) 58*cc02d7e2SAndroid Build Coastguard Worker outs.append(_get_output_file_name_from_proto(proto, _GRPC_PROTO_SRC_FMT)) 59*cc02d7e2SAndroid Build Coastguard Worker 60*cc02d7e2SAndroid Build Coastguard Worker out_files = [ctx.actions.declare_file(out) for out in outs] 61*cc02d7e2SAndroid Build Coastguard Worker dir_out = _join_directories([ 62*cc02d7e2SAndroid Build Coastguard Worker str(ctx.genfiles_dir.path), 63*cc02d7e2SAndroid Build Coastguard Worker target_package, 64*cc02d7e2SAndroid Build Coastguard Worker _GENERATED_PROTOS_DIR, 65*cc02d7e2SAndroid Build Coastguard Worker ]) 66*cc02d7e2SAndroid Build Coastguard Worker 67*cc02d7e2SAndroid Build Coastguard Worker arguments = [] 68*cc02d7e2SAndroid Build Coastguard Worker tools = [] 69*cc02d7e2SAndroid Build Coastguard Worker if ctx.executable.plugin: 70*cc02d7e2SAndroid Build Coastguard Worker arguments += get_plugin_args( 71*cc02d7e2SAndroid Build Coastguard Worker ctx.executable.plugin, 72*cc02d7e2SAndroid Build Coastguard Worker [], 73*cc02d7e2SAndroid Build Coastguard Worker dir_out, 74*cc02d7e2SAndroid Build Coastguard Worker False, 75*cc02d7e2SAndroid Build Coastguard Worker ) 76*cc02d7e2SAndroid Build Coastguard Worker tools = [ctx.executable.plugin] 77*cc02d7e2SAndroid Build Coastguard Worker arguments.append("--objc_out=" + dir_out) 78*cc02d7e2SAndroid Build Coastguard Worker 79*cc02d7e2SAndroid Build Coastguard Worker arguments.append("--proto_path=.") 80*cc02d7e2SAndroid Build Coastguard Worker arguments += [ 81*cc02d7e2SAndroid Build Coastguard Worker "--proto_path={}".format(get_include_directory(i)) 82*cc02d7e2SAndroid Build Coastguard Worker for i in protos 83*cc02d7e2SAndroid Build Coastguard Worker ] 84*cc02d7e2SAndroid Build Coastguard Worker 85*cc02d7e2SAndroid Build Coastguard Worker # Include the output directory so that protoc puts the generated code in the 86*cc02d7e2SAndroid Build Coastguard Worker # right directory. 87*cc02d7e2SAndroid Build Coastguard Worker arguments.append("--proto_path={}".format(dir_out)) 88*cc02d7e2SAndroid Build Coastguard Worker arguments += ["--proto_path={}".format(_get_directory_from_proto(proto)) for proto in protos] 89*cc02d7e2SAndroid Build Coastguard Worker arguments += [_get_full_path_from_file(proto) for proto in protos] 90*cc02d7e2SAndroid Build Coastguard Worker 91*cc02d7e2SAndroid Build Coastguard Worker # create a list of well known proto files if the argument is non-None 92*cc02d7e2SAndroid Build Coastguard Worker well_known_proto_files = [] 93*cc02d7e2SAndroid Build Coastguard Worker if ctx.attr.use_well_known_protos: 94*cc02d7e2SAndroid Build Coastguard Worker f = ctx.attr.well_known_protos.files.to_list()[0].dirname 95*cc02d7e2SAndroid Build Coastguard Worker 96*cc02d7e2SAndroid Build Coastguard Worker # go two levels up so that #import "google/protobuf/..." is correct 97*cc02d7e2SAndroid Build Coastguard Worker arguments.append("-I{0}".format(f + "/../..")) 98*cc02d7e2SAndroid Build Coastguard Worker well_known_proto_files = ctx.attr.well_known_protos.files.to_list() 99*cc02d7e2SAndroid Build Coastguard Worker ctx.actions.run( 100*cc02d7e2SAndroid Build Coastguard Worker inputs = protos + well_known_proto_files, 101*cc02d7e2SAndroid Build Coastguard Worker tools = tools, 102*cc02d7e2SAndroid Build Coastguard Worker outputs = out_files, 103*cc02d7e2SAndroid Build Coastguard Worker executable = ctx.executable._protoc, 104*cc02d7e2SAndroid Build Coastguard Worker arguments = arguments, 105*cc02d7e2SAndroid Build Coastguard Worker ) 106*cc02d7e2SAndroid Build Coastguard Worker 107*cc02d7e2SAndroid Build Coastguard Worker return struct(files = depset(out_files)) # buildifier: disable=rule-impl-return 108*cc02d7e2SAndroid Build Coastguard Worker 109*cc02d7e2SAndroid Build Coastguard Workerdef _label_to_full_file_path(src, package): 110*cc02d7e2SAndroid Build Coastguard Worker if not src.startswith("//"): 111*cc02d7e2SAndroid Build Coastguard Worker # Relative from current package 112*cc02d7e2SAndroid Build Coastguard Worker if not src.startswith(":"): 113*cc02d7e2SAndroid Build Coastguard Worker # "a.proto" -> ":a.proto" 114*cc02d7e2SAndroid Build Coastguard Worker src = ":" + src 115*cc02d7e2SAndroid Build Coastguard Worker src = "//" + package + src 116*cc02d7e2SAndroid Build Coastguard Worker 117*cc02d7e2SAndroid Build Coastguard Worker # Converts //path/to/package:File.ext to path/to/package/File.ext. 118*cc02d7e2SAndroid Build Coastguard Worker src = src.replace("//", "") 119*cc02d7e2SAndroid Build Coastguard Worker src = src.replace(":", "/") 120*cc02d7e2SAndroid Build Coastguard Worker if src.startswith("/"): 121*cc02d7e2SAndroid Build Coastguard Worker # "//:a.proto" -> "/a.proto" so remove the initial slash 122*cc02d7e2SAndroid Build Coastguard Worker return src[1:] 123*cc02d7e2SAndroid Build Coastguard Worker else: 124*cc02d7e2SAndroid Build Coastguard Worker return src 125*cc02d7e2SAndroid Build Coastguard Worker 126*cc02d7e2SAndroid Build Coastguard Workerdef _get_output_file_name_from_proto(proto, fmt): 127*cc02d7e2SAndroid Build Coastguard Worker return proto_path_to_generated_filename( 128*cc02d7e2SAndroid Build Coastguard Worker _GENERATED_PROTOS_DIR + "/" + 129*cc02d7e2SAndroid Build Coastguard Worker _get_directory_from_proto(proto) + _get_slash_or_null_from_proto(proto) + 130*cc02d7e2SAndroid Build Coastguard Worker to_upper_camel_with_extension(_get_file_name_from_proto(proto), "proto"), 131*cc02d7e2SAndroid Build Coastguard Worker fmt, 132*cc02d7e2SAndroid Build Coastguard Worker ) 133*cc02d7e2SAndroid Build Coastguard Worker 134*cc02d7e2SAndroid Build Coastguard Workerdef _get_file_name_from_proto(proto): 135*cc02d7e2SAndroid Build Coastguard Worker return proto.path.rpartition("/")[2] 136*cc02d7e2SAndroid Build Coastguard Worker 137*cc02d7e2SAndroid Build Coastguard Workerdef _get_slash_or_null_from_proto(proto): 138*cc02d7e2SAndroid Build Coastguard Worker """Potentially returns empty (if the file is in the root directory)""" 139*cc02d7e2SAndroid Build Coastguard Worker return proto.path.rpartition("/")[1] 140*cc02d7e2SAndroid Build Coastguard Worker 141*cc02d7e2SAndroid Build Coastguard Workerdef _get_directory_from_proto(proto): 142*cc02d7e2SAndroid Build Coastguard Worker return proto.path.rpartition("/")[0] 143*cc02d7e2SAndroid Build Coastguard Worker 144*cc02d7e2SAndroid Build Coastguard Workerdef _get_full_path_from_file(file): 145*cc02d7e2SAndroid Build Coastguard Worker gen_dir_length = 0 146*cc02d7e2SAndroid Build Coastguard Worker 147*cc02d7e2SAndroid Build Coastguard Worker # if file is generated, then prepare to remote its root 148*cc02d7e2SAndroid Build Coastguard Worker # (including CPU architecture...) 149*cc02d7e2SAndroid Build Coastguard Worker if not file.is_source: 150*cc02d7e2SAndroid Build Coastguard Worker gen_dir_length = len(file.root.path) + 1 151*cc02d7e2SAndroid Build Coastguard Worker 152*cc02d7e2SAndroid Build Coastguard Worker return file.path[gen_dir_length:] 153*cc02d7e2SAndroid Build Coastguard Worker 154*cc02d7e2SAndroid Build Coastguard Workerdef _join_directories(directories): 155*cc02d7e2SAndroid Build Coastguard Worker massaged_directories = [directory for directory in directories if len(directory) != 0] 156*cc02d7e2SAndroid Build Coastguard Worker return "/".join(massaged_directories) 157*cc02d7e2SAndroid Build Coastguard Worker 158*cc02d7e2SAndroid Build Coastguard Workergenerate_objc = rule( 159*cc02d7e2SAndroid Build Coastguard Worker attrs = { 160*cc02d7e2SAndroid Build Coastguard Worker "deps": attr.label_list( 161*cc02d7e2SAndroid Build Coastguard Worker mandatory = True, 162*cc02d7e2SAndroid Build Coastguard Worker allow_empty = False, 163*cc02d7e2SAndroid Build Coastguard Worker providers = [ProtoInfo], 164*cc02d7e2SAndroid Build Coastguard Worker ), 165*cc02d7e2SAndroid Build Coastguard Worker "plugin": attr.label( 166*cc02d7e2SAndroid Build Coastguard Worker default = "@com_github_grpc_grpc//src/compiler:grpc_objective_c_plugin", 167*cc02d7e2SAndroid Build Coastguard Worker executable = True, 168*cc02d7e2SAndroid Build Coastguard Worker providers = ["files_to_run"], 169*cc02d7e2SAndroid Build Coastguard Worker cfg = "exec", 170*cc02d7e2SAndroid Build Coastguard Worker ), 171*cc02d7e2SAndroid Build Coastguard Worker "srcs": attr.string_list( 172*cc02d7e2SAndroid Build Coastguard Worker mandatory = False, 173*cc02d7e2SAndroid Build Coastguard Worker allow_empty = True, 174*cc02d7e2SAndroid Build Coastguard Worker ), 175*cc02d7e2SAndroid Build Coastguard Worker "use_well_known_protos": attr.bool( 176*cc02d7e2SAndroid Build Coastguard Worker mandatory = False, 177*cc02d7e2SAndroid Build Coastguard Worker default = False, 178*cc02d7e2SAndroid Build Coastguard Worker ), 179*cc02d7e2SAndroid Build Coastguard Worker "well_known_protos": attr.label( 180*cc02d7e2SAndroid Build Coastguard Worker default = "@com_google_protobuf//:well_known_type_protos", 181*cc02d7e2SAndroid Build Coastguard Worker ), 182*cc02d7e2SAndroid Build Coastguard Worker "_protoc": attr.label( 183*cc02d7e2SAndroid Build Coastguard Worker default = Label("//external:protocol_compiler"), 184*cc02d7e2SAndroid Build Coastguard Worker executable = True, 185*cc02d7e2SAndroid Build Coastguard Worker cfg = "exec", 186*cc02d7e2SAndroid Build Coastguard Worker ), 187*cc02d7e2SAndroid Build Coastguard Worker }, 188*cc02d7e2SAndroid Build Coastguard Worker output_to_genfiles = True, 189*cc02d7e2SAndroid Build Coastguard Worker implementation = _generate_objc_impl, 190*cc02d7e2SAndroid Build Coastguard Worker) 191*cc02d7e2SAndroid Build Coastguard Worker 192*cc02d7e2SAndroid Build Coastguard Workerdef _group_objc_files_impl(ctx): 193*cc02d7e2SAndroid Build Coastguard Worker suffix = "" 194*cc02d7e2SAndroid Build Coastguard Worker if ctx.attr.gen_mode == _GENERATE_HDRS: 195*cc02d7e2SAndroid Build Coastguard Worker suffix = "h" 196*cc02d7e2SAndroid Build Coastguard Worker elif ctx.attr.gen_mode == _GENERATE_SRCS: 197*cc02d7e2SAndroid Build Coastguard Worker suffix = "pbrpc.m" 198*cc02d7e2SAndroid Build Coastguard Worker elif ctx.attr.gen_mode == _GENERATE_NON_ARC_SRCS: 199*cc02d7e2SAndroid Build Coastguard Worker suffix = "pbobjc.m" 200*cc02d7e2SAndroid Build Coastguard Worker else: 201*cc02d7e2SAndroid Build Coastguard Worker fail("Undefined gen_mode") 202*cc02d7e2SAndroid Build Coastguard Worker out_files = [ 203*cc02d7e2SAndroid Build Coastguard Worker file 204*cc02d7e2SAndroid Build Coastguard Worker for file in ctx.attr.src.files.to_list() 205*cc02d7e2SAndroid Build Coastguard Worker if file.basename.endswith(suffix) 206*cc02d7e2SAndroid Build Coastguard Worker ] 207*cc02d7e2SAndroid Build Coastguard Worker return struct(files = depset(out_files)) # buildifier: disable=rule-impl-return 208*cc02d7e2SAndroid Build Coastguard Worker 209*cc02d7e2SAndroid Build Coastguard Workergenerate_objc_hdrs = rule( 210*cc02d7e2SAndroid Build Coastguard Worker attrs = { 211*cc02d7e2SAndroid Build Coastguard Worker "src": attr.label( 212*cc02d7e2SAndroid Build Coastguard Worker mandatory = True, 213*cc02d7e2SAndroid Build Coastguard Worker ), 214*cc02d7e2SAndroid Build Coastguard Worker "gen_mode": attr.int( 215*cc02d7e2SAndroid Build Coastguard Worker default = _GENERATE_HDRS, 216*cc02d7e2SAndroid Build Coastguard Worker ), 217*cc02d7e2SAndroid Build Coastguard Worker }, 218*cc02d7e2SAndroid Build Coastguard Worker implementation = _group_objc_files_impl, 219*cc02d7e2SAndroid Build Coastguard Worker) 220*cc02d7e2SAndroid Build Coastguard Worker 221*cc02d7e2SAndroid Build Coastguard Workergenerate_objc_srcs = rule( 222*cc02d7e2SAndroid Build Coastguard Worker attrs = { 223*cc02d7e2SAndroid Build Coastguard Worker "src": attr.label( 224*cc02d7e2SAndroid Build Coastguard Worker mandatory = True, 225*cc02d7e2SAndroid Build Coastguard Worker ), 226*cc02d7e2SAndroid Build Coastguard Worker "gen_mode": attr.int( 227*cc02d7e2SAndroid Build Coastguard Worker default = _GENERATE_SRCS, 228*cc02d7e2SAndroid Build Coastguard Worker ), 229*cc02d7e2SAndroid Build Coastguard Worker }, 230*cc02d7e2SAndroid Build Coastguard Worker implementation = _group_objc_files_impl, 231*cc02d7e2SAndroid Build Coastguard Worker) 232*cc02d7e2SAndroid Build Coastguard Worker 233*cc02d7e2SAndroid Build Coastguard Workergenerate_objc_non_arc_srcs = rule( 234*cc02d7e2SAndroid Build Coastguard Worker attrs = { 235*cc02d7e2SAndroid Build Coastguard Worker "src": attr.label( 236*cc02d7e2SAndroid Build Coastguard Worker mandatory = True, 237*cc02d7e2SAndroid Build Coastguard Worker ), 238*cc02d7e2SAndroid Build Coastguard Worker "gen_mode": attr.int( 239*cc02d7e2SAndroid Build Coastguard Worker default = _GENERATE_NON_ARC_SRCS, 240*cc02d7e2SAndroid Build Coastguard Worker ), 241*cc02d7e2SAndroid Build Coastguard Worker }, 242*cc02d7e2SAndroid Build Coastguard Worker implementation = _group_objc_files_impl, 243*cc02d7e2SAndroid Build Coastguard Worker) 244