blob: 8f1828874d05acd6b4cd0ee29a20a292f4880daf [file] [log] [blame]
# Copyright 2018 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Compile protocol buffers.
#
# Paramaeters:
# proto_in_dir
# Input directory.
# proto_out_dir
# Output directory.
# proto_lib_dirs (optional)
# Directories to search for protos a proto file depends on.
# proto_in_dir and "${sysroot}/usr/share/proto" are always included.
# sources
# The proto file paths.
# configs (optional)
# Configs applied to the generated library.
# deps (optional)
# Deps applied to the generated library.
# gen_python (optional)
# If true, generates Python binding.
# gen_grpc (optional)
# If true, generates C++ GRPC.
# gen_grpc_gmock (optional)
# If true, along with gen_grpc, generates C++ GRPC gmock objects as well.
# gen_cpp_mode (optional)
# If defined, ignores the OPTIMIZE_FOR lines in protos and generates code
# with the specified optimization mode (lite or speed). For fuzzer builds
# this defaults to speed to support libprotobuf-mutator.
# use_pic (optional)
# If true, generates a position independent code instead of position independent executable.
# standalone
# If true, generates a library that can be referred from other packages.
# Otherwise it generates a thin archive assuming it's used inside the same package only.
# install_package
# If true, install the static library and its headers.
template("proto_library") {
forward_variables_from(invoker, [ "install_package" ])
if (!defined(install_package)) {
install_package = false
}
install_config_targets = []
if (install_package) {
# Install the static library. Assume target_name does not have a lib prefix
# which means we can't use static_library's install_path, so we have to
# create the install_config target for it ourself.
install_config_name = "_${target_name}-lib-install_config"
install_config(install_config_name) {
sources = [ "${root_build_dir}/lib${invoker.target_name}.a" ]
install_path = "${libdir}"
}
install_config_targets += [ ":${install_config_name}" ]
# Install the generated protobuf headers.
install_config_name = "_${target_name}-headers-install_config"
install_config(install_config_name) {
sources = []
install_path = ""
foreach(source, invoker.sources) {
# NB: This path logic is synced with the protobuf action below.
source = rebase_path(source, invoker.proto_in_dir)
source = string_replace(source, ".proto", "")
sources += [ "${root_gen_dir}/${invoker.proto_out_dir}/${source}.pb.h" ]
source_install_path =
"/usr/${invoker.proto_out_dir}/" + get_path_info(source, "dir")
if (install_path == "") {
install_path = source_install_path
} else {
# We can only install into one path, so double check all the source
# files implicitly go to that.
assert(install_path == source_install_path)
}
}
}
install_config_targets += [ ":${install_config_name}" ]
}
action_name = "${target_name}_gen"
action(action_name) {
visibility = [ ":*" ]
forward_variables_from(invoker,
[
"proto_in_dir",
"proto_out_dir",
"gen_python",
"gen_grpc",
"gen_grpc_gmock",
"gen_cpp_mode",
# Sources might be generated by actions in deps,
# which must be explicitly specified.
"public_deps",
"sources",
])
deps = install_config_targets
if (defined(invoker.deps)) {
deps += invoker.deps
}
cc_dir = "${root_gen_dir}/${proto_out_dir}"
proto_in_dir = rebase_path(proto_in_dir)
proto_out_dir = rebase_path(proto_out_dir)
proto_lib_dirs = [
proto_in_dir,
"${sysroot}/usr/share/proto",
]
if (defined(invoker.proto_lib_dirs)) {
proto_lib_dirs += rebase_path(invoker.proto_lib_dirs)
}
if (!defined(gen_python)) {
gen_python = false
}
if (!defined(gen_grpc)) {
gen_grpc = false
}
if (gen_grpc && !defined(gen_grpc_gmock)) {
gen_grpc_gmock = false
}
if (defined(gen_cpp_mode)) {
gen_cpp_mode = "${gen_cpp_mode}:"
} else if (use.fuzzer || use.proto_force_optimize_speed) {
gen_cpp_mode = "speed:"
} else {
gen_cpp_mode = ""
}
script = "//common-mk/file_generator_wrapper.py"
args = [ "protoc" ]
foreach(source, sources) {
args += [ rebase_path(source, proto_in_dir) ]
}
foreach(x, proto_lib_dirs) {
args += [
"--proto_path",
x,
]
}
outputs = []
if (gen_python) {
python_dir = "${root_gen_dir}/${proto_out_dir}/py"
args += [
"--python_out",
"${python_dir}",
]
foreach(source, sources) {
source = rebase_path(source, proto_in_dir)
source = string_replace(source, ".proto", "")
outputs += [ "${python_dir}/${source}_pb.py" ]
}
}
if (gen_grpc) {
if (gen_grpc_gmock) {
args += [ "--grpc_out=generate_mock_code=true:${cc_dir}" ]
foreach(source, sources) {
source = rebase_path(source, proto_in_dir)
source = string_replace(source, ".proto", "")
outputs += [ "${cc_dir}/${source}_mock.grpc.pb.h" ]
}
} else {
args += [ "--grpc_out=${cc_dir}" ]
}
grpc_cpp_plugin = "/usr/bin/grpc_cpp_plugin"
args += [
"--plugin=protoc-gen-grpc=${grpc_cpp_plugin}",
"--cpp_out=${gen_cpp_mode}${cc_dir}",
]
foreach(source, sources) {
source = rebase_path(source, proto_in_dir)
source = string_replace(source, ".proto", "")
outputs += [
"${cc_dir}/${source}.grpc.pb.cc",
"${cc_dir}/${source}.grpc.pb.h",
"${cc_dir}/${source}.pb.cc",
"${cc_dir}/${source}.pb.h",
]
}
}
if (!gen_grpc && !gen_python) {
args += [ "--cpp_out=${gen_cpp_mode}${cc_dir}" ]
foreach(source, sources) {
source = rebase_path(source, proto_in_dir)
source = string_replace(source, ".proto", "")
outputs += [
"${cc_dir}/${source}.pb.cc",
"${cc_dir}/${source}.pb.h",
]
}
}
}
all_dependent_config_name = "_${target_name}_all_dependent_config"
config(all_dependent_config_name) {
# Allows for dependents to include protoc-generated header files with relative path from
# root_gen_dir i.e. in the form of "${proto_out_dir}/<generated file basename>".
include_dirs = [ root_gen_dir ]
}
static_library(target_name) {
forward_variables_from(
invoker,
[
"defines",
"public_configs",
"public_deps",
"visibility",
"proto_out_dir",
# TODO(oka): we should not have to use all_dependent_pkg_deps here, because there is no
# inherent reason that all users of this target should depend on some external
# dependency. Remove this after no user uses it.
"all_dependent_pkg_deps",
])
if (defined(invoker.configs)) {
configs += invoker.configs
}
if (defined(invoker.use_pic) && invoker.use_pic) {
configs -= [ "//common-mk:pie" ]
configs += [ "//common-mk:pic" ]
}
if (defined(invoker.standalone) && invoker.standalone) {
configs -= [ "//common-mk:use_thin_archive" ]
configs += [
"//common-mk:nouse_thin_archive",
# Generated code. Cannot modify individual symbol attributes there easily.
# gnlint: disable=GnLintVisibilityFlags
"//common-mk:visibility_default",
]
} else {
assert(!install_package, "install_package requires standalone=true")
}
all_dependent_configs = [ ":${all_dependent_config_name}" ]
if (defined(invoker.all_dependent_configs)) {
all_dependent_configs += invoker.all_dependent_configs
}
sources = get_target_outputs(":${action_name}")
include_dirs = [ "${root_gen_dir}/${proto_out_dir}" ]
deps = [ ":${action_name}" ]
if (defined(invoker.deps)) {
deps += invoker.deps
}
cflags_cc = [
# Protobuf 3.7.0 introduced generated code that is sometimes unreachable.
"-Wno-unreachable-code",
# Protobuf 3.11.4 generates deprecated declarations which lead to warnings
# that shouldn't be treated as errors in generated code.
# TODO(crbug.com/1082873): Reenable deprecated declarations.
"-Wno-deprecated-declarations",
]
}
}
# Compile protocol buffers to Go.
#
# Parameters:
# proto_in_dir
# Input directory.
# proto_out_dir
# Output directory. Relative to gen directory.
# sources
# The proto file paths.
# gen_grpc (optional)
# If true, generates Go GRPC.
# import_mapping (optional)
# List of mapping to convert imports in .proto file to go package names.
# The format is "foo/bar.proto=quux/shme".
# proto_lib_dirs (optional)
# Directories to search for protos a proto file depends on.
# proto_in_dir and "${sysroot}/usr/share/proto" are added by default.
template("goproto_library") {
action(target_name) {
forward_variables_from(invoker,
[
"proto_out_dir",
"sources",
])
# For go, it is necessary to generate the code in one command line,
# otherwise file descriptor var name will conflict.
# cf) https://github.com/golang/protobuf/issues/109
proto_in_dir = rebase_path(invoker.proto_in_dir)
# Build protoc command line to run.
script = "//common-mk/file_generator_wrapper.py"
proto_lib_dirs = [
proto_in_dir,
"${sysroot}/usr/share/proto",
]
if (defined(invoker.proto_lib_dirs)) {
proto_lib_dirs += rebase_path(invoker.proto_lib_dirs)
}
go_plugin_parameters = []
if (defined(invoker.gen_grpc) && invoker.gen_grpc) {
go_plugin_parameters += [ "plugins=grpc" ]
}
if (defined(invoker.import_mapping)) {
foreach(x, invoker.import_mapping) {
go_plugin_parameters += [ "M" + x ]
}
}
go_out_prefix = string_join(",", go_plugin_parameters)
args = [ "protoc" ]
foreach(x, proto_lib_dirs) {
args += [
"--proto_path",
x,
]
}
args += [
"--go_out",
# go_out_prefix can be empty, so we can always add a colon here.
"${go_out_prefix}:${root_gen_dir}/${proto_out_dir}",
]
foreach(source, sources) {
args += [ rebase_path(source) ]
}
# Output dependency.
outputs = []
foreach(source, invoker.sources) {
name = get_path_info(source, "name")
outputs += [ "${root_gen_dir}/${proto_out_dir}/${name}.pb.go" ]
}
}
}
# Compile protocol buffers to Perfetto protozero (.pbzero.h) headers.
#
# Parameters:
# proto_in_dir
# Input directory.
# proto_out_dir
# Output directory. Relative to gen directory.
# sources
# The proto file paths.
#
template("protozero_library") {
action(target_name) {
forward_variables_from(invoker,
[
"proto_in_dir",
"proto_out_dir",
"sources",
])
proto_in_dir = rebase_path(invoker.proto_in_dir)
# Build protoc command line to run.
script = "//common-mk/file_generator_wrapper.py"
proto_lib_dirs = [
proto_in_dir,
"/usr/include/proto",
]
args = [ "protoc" ]
foreach(x, proto_lib_dirs) {
args += [
"--proto_path",
x,
]
}
args += [
"--plugin",
"protoc-gen-plugin=/usr/libexec/protozero_plugin",
"--plugin_out=wrapper_namespace=pbzero:${root_gen_dir}/${proto_out_dir}",
]
foreach(source, sources) {
args += [ rebase_path(source) ]
}
# Output dependency.
outputs = []
foreach(source, invoker.sources) {
name = get_path_info(source, "name")
outputs += [ "${root_gen_dir}/${proto_out_dir}/${name}.pbzero.h" ]
}
}
}