blob: 1a23a97ad1bff0aacb071a6332c06c0c611b8b67 [file] [log] [blame] [edit]
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("../perfetto.gni")
if (host_os == "win") {
_host_executable_suffix = ".exe"
} else {
_host_executable_suffix = ""
}
template("proto_library") {
assert(defined(invoker.sources))
proto_sources = invoker.sources
# All the proto imports should be relative to the project root.
proto_in_dir = "//"
if (defined(invoker.proto_in_dir)) {
proto_in_dir = invoker.proto_in_dir
}
assert(defined(invoker.proto_out_dir),
"proto_out_dir must be explicitly defined")
proto_out_dir = invoker.proto_out_dir
# We don't support generate_python in the standalone build, but still must
# check that the caller sets this to false. This is because when building in
# the chromium tree, chromium's proto_library.gni in chrome (!= this) defaults
# generate_python = true.
assert(defined(invoker.generate_python) && !invoker.generate_python)
import_dirs = []
if (defined(invoker.import_dirs)) {
import_dirs = invoker.import_dirs
}
# If false will not generate the default .pb.{cc,h} files. Used for custom
# codegen plugins.
generate_cc = true
if (defined(invoker.generate_cc)) {
generate_cc = invoker.generate_cc
}
generate_descriptor = ""
if (defined(invoker.generate_descriptor)) {
generate_descriptor = invoker.generate_descriptor
# Include imports to descriptor by default, but use exclude_imports to omit
# them if needed.
if (defined(invoker.exclude_imports)) {
exclude_imports = invoker.exclude_imports
} else {
exclude_imports = false
}
}
if (defined(invoker.generator_plugin_label)) {
plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)"
plugin_path =
get_label_info(plugin_host_label, "root_out_dir") + "/" +
get_label_info(plugin_host_label, "name") + _host_executable_suffix
generate_with_plugin = true
} else if (defined(invoker.generator_plugin_script)) {
plugin_path = invoker.generator_plugin_script
generate_with_plugin = true
} else {
generate_with_plugin = false
}
if (generate_with_plugin) {
if (defined(invoker.generator_plugin_suffix)) {
generator_plugin_suffixes = [
"${invoker.generator_plugin_suffix}.h",
"${invoker.generator_plugin_suffix}.cc",
]
} else {
generator_plugin_suffixes = invoker.generator_plugin_suffixes
}
}
out_dir = "$root_gen_dir/" + proto_out_dir
rel_out_dir = rebase_path(out_dir, root_build_dir)
# Prevent unused errors when generating descriptor only.
if (generate_descriptor != "") {
not_needed([ "rel_out_dir" ])
}
protos = rebase_path(proto_sources, proto_in_dir)
protogens = []
if (generate_descriptor != "") {
protogens += [ "$out_dir/${generate_descriptor}" ]
}
foreach(proto, protos) {
proto_dir = get_path_info(proto, "dir")
proto_name = get_path_info(proto, "name")
proto_path = proto_dir + "/" + proto_name
# Prevent unused errors when generating descriptor only.
if (generate_descriptor != "") {
not_needed([ "proto_path" ])
}
if (generate_cc) {
protogens += [
"$out_dir/$proto_path.pb.h",
"$out_dir/$proto_path.pb.cc",
]
}
if (generate_with_plugin) {
foreach(suffix, generator_plugin_suffixes) {
protogens += [ "$out_dir/${proto_path}${suffix}" ]
}
}
}
config_name = "${target_name}_config"
if (generate_descriptor == "") {
action_name = "${target_name}_gen"
source_set_name = target_name
} else {
action_name = target_name
}
config(config_name) {
include_dirs = [ out_dir ]
}
# The XXX_gen action that generates the .pb.{cc,h} files.
action(action_name) {
if (generate_descriptor == "") {
visibility = [ ":$source_set_name" ]
}
sources = proto_sources
outputs = get_path_info(protogens, "abspath")
if (perfetto_use_system_protobuf) {
protoc_rebased_path = "protoc" + _host_executable_suffix # from PATH
} else {
protoc_label = "//gn:protoc($host_toolchain)"
protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" +
_host_executable_suffix
protoc_rebased_path = "./" + rebase_path(protoc_path, root_build_dir)
}
script = "//gn/standalone/protoc.py"
args = [
# Path should be rebased because |root_build_dir| for current toolchain
# may be different from |root_out_dir| of protoc built on host toolchain.
protoc_rebased_path,
"--proto_path",
rebase_path(proto_in_dir, root_build_dir),
]
foreach(path, import_dirs) {
args += [
"--proto_path",
rebase_path(path, root_build_dir),
]
}
metadata = {
proto_import_dirs = import_dirs
}
if (generate_cc) {
cc_generator_options_ = ""
if (defined(invoker.cc_generator_options)) {
cc_generator_options_ = invoker.cc_generator_options
}
args += [
"--cpp_out",
cc_generator_options_ + rel_out_dir,
]
}
if (generate_descriptor != "") {
depfile = "$root_gen_dir/$generate_descriptor.d"
if (!exclude_imports) {
args += [ "--include_imports" ]
}
args += [
"--descriptor_set_out",
rebase_path("$root_gen_dir/$generate_descriptor", root_build_dir),
"--dependency_out",
rebase_path(depfile, root_build_dir),
]
}
if (generate_with_plugin) {
plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
plugin_out_args = ""
if (defined(invoker.generator_plugin_options)) {
plugin_out_args += invoker.generator_plugin_options
}
plugin_out_args += ":$rel_out_dir"
args += [
"--plugin=protoc-gen-plugin=$plugin_path_rebased",
"--plugin_out=$plugin_out_args",
]
}
args += rebase_path(proto_sources, root_build_dir)
if (!perfetto_use_system_protobuf) {
inputs = [ protoc_path ]
deps = [ protoc_label ]
} else {
inputs = []
deps = []
}
# TODO(hjd): Avoid adding to deps here this.
# When we generate BUILD files we need find the transitive proto,
# dependencies, so also add link_deps to actual deps so they show up
# in gn desc.
if (defined(invoker.link_deps)) {
deps += invoker.link_deps
}
if (generate_with_plugin) {
inputs += [ plugin_path ]
if (defined(plugin_host_label)) {
# Action depends on native generator plugin but for host toolchain only.
deps += [ plugin_host_label ]
}
}
if (defined(invoker.deps)) {
deps += invoker.deps
}
} # action(action_name)
# The source_set that builds the generated .pb.cc files.
if (generate_descriptor == "") {
source_set(source_set_name) {
forward_variables_from(invoker,
[
"defines",
"include_dirs",
"public_configs",
"testonly",
"visibility",
])
sources = get_target_outputs(":$action_name")
configs -= [ "//gn/standalone:extra_warnings" ]
if (defined(invoker.extra_configs)) {
configs += invoker.extra_configs
}
if (!defined(invoker.public_configs)) {
public_configs = []
}
public_configs += [ ":$config_name" ]
# Only include the protobuf_gen_config when generating .pb.cc files.
# Note that |generate_cc| is false for .{pbzero,ipc,gen etc.}.cc
if (generate_cc) {
public_configs += [ "//gn:protobuf_gen_config" ]
}
# By default, propagate the config for |include_dirs| to dependent
# targets, so that public imports can be resolved to corresponding header
# files. In some cases, the embedder target handles include directory
# propagation itself, e.g. via a common config.
propagate_imports_configs = !defined(invoker.propagate_imports_configs) ||
invoker.propagate_imports_configs
if (propagate_imports_configs) {
public_configs += [ ":$config_name" ]
} else {
configs += [ ":$config_name" ]
}
# Use protobuf_full only for tests.
if (defined(invoker.use_protobuf_full) &&
invoker.use_protobuf_full == true) {
deps = [ "//gn:protobuf_full" ]
} else if (generate_cc) {
deps = [ "//gn:protobuf_lite" ]
} else {
deps = []
}
deps += [ ":$action_name" ]
if (defined(invoker.deps)) {
deps += invoker.deps
}
} # source_set(source_set_name)
}
} # template