1# Copyright (C) 2017 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import("../perfetto.gni") 16 17if (host_os == "win") { 18 _host_executable_suffix = ".exe" 19} else { 20 _host_executable_suffix = "" 21} 22 23template("proto_library") { 24 assert(defined(invoker.sources)) 25 proto_sources = invoker.sources 26 27 # All the proto imports should be relative to the project root. 28 proto_in_dir = "//" 29 if (defined(invoker.proto_in_dir)) { 30 proto_in_dir = invoker.proto_in_dir 31 } 32 assert(defined(invoker.proto_out_dir), 33 "proto_out_dir must be explicitly defined") 34 proto_out_dir = invoker.proto_out_dir 35 36 # We don't support generate_python in the standalone build, but still must 37 # check that the caller sets this to false. This is because when building in 38 # the chromium tree, chromium's proto_library.gni in chrome (!= this) defaults 39 # generate_python = true. 40 assert(defined(invoker.generate_python) && !invoker.generate_python) 41 42 import_dirs = [] 43 if (defined(invoker.import_dirs)) { 44 import_dirs = invoker.import_dirs 45 } 46 47 # If false will not generate the default .pb.{cc,h} files. Used for custom 48 # codegen plugins. 49 generate_cc = true 50 if (defined(invoker.generate_cc)) { 51 generate_cc = invoker.generate_cc 52 } 53 54 generate_descriptor = "" 55 if (defined(invoker.generate_descriptor)) { 56 generate_descriptor = invoker.generate_descriptor 57 58 # Include imports to descriptor by default, but use exclude_imports to omit 59 # them if needed. 60 if (defined(invoker.exclude_imports)) { 61 exclude_imports = invoker.exclude_imports 62 } else { 63 exclude_imports = false 64 } 65 } 66 67 if (defined(invoker.generator_plugin_label)) { 68 plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)" 69 plugin_path = 70 get_label_info(plugin_host_label, "root_out_dir") + "/" + 71 get_label_info(plugin_host_label, "name") + _host_executable_suffix 72 generate_with_plugin = true 73 } else if (defined(invoker.generator_plugin_script)) { 74 plugin_path = invoker.generator_plugin_script 75 generate_with_plugin = true 76 } else { 77 generate_with_plugin = false 78 } 79 80 if (generate_with_plugin) { 81 if (defined(invoker.generator_plugin_suffix)) { 82 generator_plugin_suffixes = [ 83 "${invoker.generator_plugin_suffix}.h", 84 "${invoker.generator_plugin_suffix}.cc", 85 ] 86 } else { 87 generator_plugin_suffixes = invoker.generator_plugin_suffixes 88 } 89 } 90 91 out_dir = "$root_gen_dir/" + proto_out_dir 92 rel_out_dir = rebase_path(out_dir, root_build_dir) 93 94 # Prevent unused errors when generating descriptor only. 95 if (generate_descriptor != "") { 96 not_needed([ "rel_out_dir" ]) 97 } 98 99 protos = rebase_path(proto_sources, proto_in_dir) 100 protogens = [] 101 102 if (generate_descriptor != "") { 103 protogens += [ "$out_dir/${generate_descriptor}" ] 104 } 105 106 foreach(proto, protos) { 107 proto_dir = get_path_info(proto, "dir") 108 proto_name = get_path_info(proto, "name") 109 proto_path = proto_dir + "/" + proto_name 110 111 # Prevent unused errors when generating descriptor only. 112 if (generate_descriptor != "") { 113 not_needed([ "proto_path" ]) 114 } 115 116 if (generate_cc) { 117 protogens += [ 118 "$out_dir/$proto_path.pb.h", 119 "$out_dir/$proto_path.pb.cc", 120 ] 121 } 122 if (generate_with_plugin) { 123 foreach(suffix, generator_plugin_suffixes) { 124 protogens += [ "$out_dir/${proto_path}${suffix}" ] 125 } 126 } 127 } 128 129 config_name = "${target_name}_config" 130 if (generate_descriptor == "") { 131 action_name = "${target_name}_gen" 132 source_set_name = target_name 133 } else { 134 action_name = target_name 135 } 136 137 config(config_name) { 138 include_dirs = [ out_dir ] 139 } 140 141 # The XXX_gen action that generates the .pb.{cc,h} files. 142 action(action_name) { 143 if (generate_descriptor == "") { 144 visibility = [ ":$source_set_name" ] 145 } 146 sources = proto_sources 147 outputs = get_path_info(protogens, "abspath") 148 149 if (perfetto_use_system_protobuf) { 150 protoc_rebased_path = "protoc" + _host_executable_suffix # from PATH 151 } else { 152 protoc_label = "//gn:protoc($host_toolchain)" 153 protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" + 154 _host_executable_suffix 155 protoc_rebased_path = "./" + rebase_path(protoc_path, root_build_dir) 156 } 157 script = "//gn/standalone/protoc.py" 158 args = [ 159 # Path should be rebased because |root_build_dir| for current toolchain 160 # may be different from |root_out_dir| of protoc built on host toolchain. 161 protoc_rebased_path, 162 "--proto_path", 163 rebase_path(proto_in_dir, root_build_dir), 164 ] 165 166 foreach(path, import_dirs) { 167 args += [ 168 "--proto_path", 169 rebase_path(path, root_build_dir), 170 ] 171 } 172 173 if (generate_cc) { 174 cc_generator_options_ = "" 175 if (defined(invoker.cc_generator_options)) { 176 cc_generator_options_ = invoker.cc_generator_options 177 } 178 args += [ 179 "--cpp_out", 180 cc_generator_options_ + rel_out_dir, 181 ] 182 } 183 if (generate_descriptor != "") { 184 depfile = "$root_gen_dir/$generate_descriptor.d" 185 186 if (!exclude_imports) { 187 args += [ "--include_imports" ] 188 } 189 args += [ 190 "--descriptor_set_out", 191 rebase_path("$root_gen_dir/$generate_descriptor", root_build_dir), 192 "--dependency_out", 193 rebase_path(depfile, root_build_dir), 194 ] 195 } 196 197 if (generate_with_plugin) { 198 plugin_path_rebased = rebase_path(plugin_path, root_build_dir) 199 plugin_out_args = "" 200 if (defined(invoker.generator_plugin_options)) { 201 plugin_out_args += invoker.generator_plugin_options 202 } 203 plugin_out_args += ":$rel_out_dir" 204 205 args += [ 206 "--plugin=protoc-gen-plugin=$plugin_path_rebased", 207 "--plugin_out=$plugin_out_args", 208 ] 209 } 210 211 args += rebase_path(proto_sources, root_build_dir) 212 213 if (!perfetto_use_system_protobuf) { 214 inputs = [ protoc_path ] 215 deps = [ protoc_label ] 216 } else { 217 inputs = [] 218 deps = [] 219 } 220 221 # TODO(hjd): Avoid adding to deps here this. 222 # When we generate BUILD files we need find the transitive proto, 223 # dependencies, so also add link_deps to actual deps so they show up 224 # in gn desc. 225 if (defined(invoker.link_deps)) { 226 deps += invoker.link_deps 227 } 228 if (generate_with_plugin) { 229 inputs += [ plugin_path ] 230 if (defined(plugin_host_label)) { 231 # Action depends on native generator plugin but for host toolchain only. 232 deps += [ plugin_host_label ] 233 } 234 } 235 236 if (defined(invoker.deps)) { 237 deps += invoker.deps 238 } 239 } # action(action_name) 240 241 # The source_set that builds the generated .pb.cc files. 242 if (generate_descriptor == "") { 243 source_set(source_set_name) { 244 forward_variables_from(invoker, 245 [ 246 "defines", 247 "include_dirs", 248 "public_configs", 249 "testonly", 250 "visibility", 251 ]) 252 253 sources = get_target_outputs(":$action_name") 254 255 configs -= [ "//gn/standalone:extra_warnings" ] 256 if (defined(invoker.extra_configs)) { 257 configs += invoker.extra_configs 258 } 259 260 if (!defined(invoker.public_configs)) { 261 public_configs = [] 262 } 263 264 public_configs += [ ":$config_name" ] 265 266 # Only include the protobuf_gen_config when generating .pb.cc files. 267 # Note that |generate_cc| is false for .{pbzero,ipc,gen etc.}.cc 268 if (generate_cc) { 269 public_configs += [ "//gn:protobuf_gen_config" ] 270 } 271 272 # By default, propagate the config for |include_dirs| to dependent 273 # targets, so that public imports can be resolved to corresponding header 274 # files. In some cases, the embedder target handles include directory 275 # propagation itself, e.g. via a common config. 276 propagate_imports_configs = !defined(invoker.propagate_imports_configs) || 277 invoker.propagate_imports_configs 278 if (propagate_imports_configs) { 279 public_configs += [ ":$config_name" ] 280 } else { 281 configs += [ ":$config_name" ] 282 } 283 284 # Use protobuf_full only for tests. 285 if (defined(invoker.use_protobuf_full) && 286 invoker.use_protobuf_full == true) { 287 deps = [ "//gn:protobuf_full" ] 288 } else if (generate_cc) { 289 deps = [ "//gn:protobuf_lite" ] 290 } else { 291 deps = [] 292 } 293 294 deps += [ ":$action_name" ] 295 if (defined(invoker.deps)) { 296 deps += invoker.deps 297 } 298 } # source_set(source_set_name) 299 } 300} # template 301