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