blob: a2a469dc6f2b588ad8423631a0b87c5bb0287c8c [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# TODO(vardhan): Currently, the compiler generates type info and calls the
# generators. Sever this, and have generators consume compiled output from an
# intermediate file.
import("//build/config/fuchsia/sdk.gni")
import("//packages/gn/packages.gni")
declare_args() {
# Generate Dart code from fidl bindings.
generate_fidl_for_dart = packages_have_dart
# Generate Go code from fidl bindings.
generate_fidl_for_go = packages_have_go
# Generate Rust code from fidl bindings.
generate_fidl_for_rust = packages_have_rust
}
if (generate_fidl_for_dart) {
import("//build/dart/dart_package.gni")
}
if (generate_fidl_for_rust) {
import("//build/rust/rust_library.gni")
}
# Generate C++/JavaScript/Java/Python/Dart/Go source files from fidl files. The
# output files will go under the generated file directory tree with the same
# path as each input file.
#
# Parameters:
#
# sources (optional if one of the deps sets listed below is present)
# List of source .fidl files to compile.
#
# deps (optional)
# Note: this can contain only other fidl targets.
#
# public_deps (optional)
# Note: this can contain only other fidl targets.
#
# import_dirs (optional)
# List of import directories that will get added when processing sources.
#
# testonly (optional)
#
# visibility (optional)
template("fidl") {
assert(
defined(invoker.sources) || defined(invoker.deps) ||
defined(invoker.public_deps),
"\"sources\" or \"deps\" must be defined for the $target_name template.")
cpp_sources_suffix = "cpp_sources"
cpp_sources_target_name = "${target_name}_${cpp_sources_suffix}"
if (defined(invoker.sources)) {
legacy_gen_path = rebase_path(
"${root_build_dir}/host_x64/legacy_generators/run_code_generators.py")
fidl_tool = rebase_path("${root_build_dir}/host_x64/fidl")
generator_cpp_outputs = [
"{{source_gen_dir}}/{{source_file_part}}-common.cc",
"{{source_gen_dir}}/{{source_file_part}}-common.h",
"{{source_gen_dir}}/{{source_file_part}}-internal.h",
"{{source_gen_dir}}/{{source_file_part}}-sync.cc",
"{{source_gen_dir}}/{{source_file_part}}-sync.h",
"{{source_gen_dir}}/{{source_file_part}}.h",
"{{source_gen_dir}}/{{source_file_part}}.cc",
]
if (generate_fidl_for_dart) {
generator_dart_outputs =
[ "{{source_gen_dir}}/{{source_file_part}}.dart" ]
}
if (generate_fidl_for_go) {
go_gen_path = rebase_path("${root_build_dir}/host_x64/fidl-go")
generator_go_outputs = [ "${root_gen_dir}/go/src/{{source_dir}}/{{source_name_part}}/{{source_name_part}}.core.go" ]
}
# TODO(vardhan): We can't have both .mojom and .fidl coexist because of
# this hardcoded '_fidl' suffix. Has to do with python imports not handling
# '.fidl/.mojom' in names. Investigate putting in a package instead.
generator_python_outputs =
[ "{{source_gen_dir}}/{{source_name_part}}_fidl.py" ]
if (generate_fidl_for_rust) {
rust_gen_path = rebase_path("${root_build_dir}/host_x64/fidl-rust")
generator_rust_outputs =
# "{{source_gen_dir}}/${target_name}/src/{{source_name_part}}.rs" would be
# a cleaner directory structure for the generated crate, but would require
# changes to the generator
[ "{{source_gen_dir}}/{{source_name_part}}.rs" ]
}
}
generator_python_zip_output = "$target_out_dir/${target_name}_python.pyzip"
if (generate_fidl_for_rust) {
generator_rust_crate_output = "$target_gen_dir/${target_name}"
map_target = "${target_name}_map"
}
if (defined(invoker.sources)) {
generator_target_name = target_name + "__generator"
action_foreach(generator_target_name) {
script = "/usr/bin/env"
public_deps = [
"//garnet/public/lib/fidl/compiler:fidl(//build/toolchain:host_x64)",
]
deps = [
"//garnet/public/lib/fidl/compiler/legacy_generators(//build/toolchain:host_x64)",
]
if (generate_fidl_for_rust) {
deps += [
":$map_target",
"//garnet/public/lib/fidl/compiler:fidl-rust(//build/toolchain:host_x64)",
]
}
if (generate_fidl_for_go) {
deps += [ "//garnet/public/lib/fidl/compiler:fidl-go(//build/toolchain:host_x64)" ]
}
if (defined(invoker.generate_type_info) && invoker.generate_type_info) {
deps += [ "//garnet/public/lib/fidl/compiler/interfaces:interfaces" ]
}
sources = invoker.sources
# In case one of our |sources| depends/imports another one of our |sources|:
inputs = invoker.sources
outputs = generator_cpp_outputs + generator_python_outputs
if (generate_fidl_for_dart) {
outputs += generator_dart_outputs
}
if (generate_fidl_for_rust) {
outputs += generator_rust_outputs
}
if (generate_fidl_for_go) {
outputs += generator_go_outputs
}
generators = legacy_gen_path
if (generate_fidl_for_go) {
generators += "," + go_gen_path
}
if (generate_fidl_for_rust) {
generators += "," + rust_gen_path
}
args = [
fidl_tool,
"gen",
"--src-root-path",
rebase_path("//", root_build_dir),
"-I",
rebase_path("//", root_build_dir),
"--output-dir",
rebase_path(root_gen_dir),
"--no-gen-imports",
"--generators",
generators,
]
if (generate_fidl_for_rust) {
# Plumb map to generator (for Rust)
args += [
"--gen-arg",
"map-file=" + rebase_path("${generator_rust_crate_output}_map.txt",
root_build_dir),
]
}
if (defined(invoker.generate_type_info) && invoker.generate_type_info) {
args += [
"--gen-arg",
"generate-type-info",
]
}
if (generate_fidl_for_dart) {
if (defined(ignore_dart_package_annotations) &&
ignore_dart_package_annotations) {
args += [
"--gen-arg",
"dart_ignore-package-annotations",
]
}
}
foreach(import_dir, sdk_dirs) {
args += [
"-I",
rebase_path(import_dir, root_build_dir),
]
}
if (defined(invoker.import_dirs)) {
foreach(import_dir, invoker.import_dirs) {
args += [
"-I",
rebase_path(import_dir, root_build_dir),
]
}
}
args += [ "{{source}}" ]
}
}
# Some re-usable variables for the C++ source sets:
cpp_public_deps = []
if (defined(invoker.public_deps)) {
cpp_public_deps += invoker.public_deps
}
if (defined(invoker.sources)) {
cpp_public_deps += [ ":$generator_target_name" ]
}
cpp_deps = []
if (defined(invoker.deps)) {
cpp_deps += invoker.deps
}
source_set(target_name) {
if (defined(invoker.visibility)) {
visibility = invoker.visibility
}
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
public_configs = [ "//garnet/public:config" ]
public_deps = [
"//garnet/public/lib/fidl/cpp/bindings",
]
public_deps += cpp_public_deps
if (defined(invoker.sources)) {
public_deps += [ ":${cpp_sources_target_name}" ]
}
deps = cpp_deps
}
# This target provides C++ support for serialization without requiring any
# support from the OS. (The other C++ bindings assume message pipes, etc.)
source_set("${target_name}_data_only") {
if (defined(invoker.visibility)) {
visibility = invoker.visibility
}
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
public_configs = [ "//garnet/public:config" ]
public_deps = [
"//garnet/public/lib/fidl/cpp/bindings:serialization",
]
public_deps += cpp_public_deps
if (defined(invoker.sources)) {
public_deps += [ ":${cpp_sources_target_name}" ]
}
deps = cpp_deps
}
all_deps = []
if (defined(invoker.deps)) {
all_deps += invoker.deps
}
if (defined(invoker.public_deps)) {
all_deps += invoker.public_deps
}
group("${target_name}__is_fidl") {
}
# Explicitly ensure that all dependencies (invoker.deps and
# invoker.public_deps) are fidl targets themselves.
group("${target_name}__check_deps_are_all_fidl") {
deps = []
foreach(d, all_deps) {
name = get_label_info(d, "label_no_toolchain")
toolchain = get_label_info(d, "toolchain")
deps += [ "${name}__is_fidl(${toolchain})" ]
}
}
action("${target_name}_python") {
script = "//garnet/public/lib/fidl/build/zip.py"
deps = []
zip_inputs = []
if (defined(invoker.sources)) {
inputs = process_file_template(invoker.sources, generator_python_outputs)
deps += [ ":$generator_target_name" ]
}
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
# //mojo/something:something and we can append "_python" to get the python
# dependency name.
full_name = get_label_info(d, "label_no_toolchain")
dep_name = get_label_info(d, "name")
dep_target_out_dir = get_label_info(d, "target_out_dir")
deps += [ "${full_name}_python" ]
zip_inputs += [ "$dep_target_out_dir/${dep_name}_python.pyzip" ]
}
output = generator_python_zip_output
outputs = [
output,
]
rebase_base_dir = rebase_path(target_gen_dir, root_build_dir)
if (defined(invoker.sources)) {
rebase_inputs = rebase_path(inputs, root_build_dir)
}
rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir)
rebase_output = rebase_path(output, root_build_dir)
args = [
"--base-dir=$rebase_base_dir",
"--zip-inputs=$rebase_zip_inputs",
"--output=$rebase_output",
]
if (defined(invoker.sources)) {
args += [ "--inputs=$rebase_inputs" ]
}
}
if (generate_fidl_for_rust) {
rust_crate_target_name = "${target_name}_rust"
action(rust_crate_target_name) {
script = "//garnet/public/lib/fidl/build/make_crate.py"
deps = []
dep_inputs = []
if (defined(invoker.sources)) {
inputs = process_file_template(invoker.sources, generator_rust_outputs)
deps += [ ":$generator_target_name" ]
}
foreach(d, all_deps) {
# Resolve the name, so that a target //fidl/something becomes
# //fidl/something:something and we can append "_rust" to get the rust
# dependency name.
full_name = get_label_info(d, "label_no_toolchain")
dep_name = get_label_info(d, "name")
dep_target_gen_dir = get_label_info(d, "target_gen_dir")
deps += [ "${full_name}_rust" ]
dep_inputs += [ "$dep_target_gen_dir/${dep_name}" ]
}
output_base = generator_rust_crate_output
outputs = [
"$output_base/Cargo.toml",
"$output_base/src/lib.rs",
]
rebase_gen_dir = rebase_path(root_gen_dir)
if (defined(invoker.sources)) {
rebase_inputs = rebase_path(inputs, root_build_dir)
}
rebase_dep_inputs = rebase_path(dep_inputs, root_gen_dir)
rebase_output = rebase_path(output_base, root_gen_dir)
rebase_srcroot = rebase_path("//", root_build_dir)
args = [
"--gen-dir=$rebase_gen_dir",
"--dep-inputs=$rebase_dep_inputs",
"--output=$rebase_output",
"--srcroot=$rebase_srcroot",
]
if (defined(invoker.sources)) {
args += [ "--inputs=$rebase_inputs" ]
}
}
rust_library("${target_name}_rust_library") {
name = exec_script("//garnet/public/lib/fidl/build/label_to_crate.py",
[ rebase_path(generator_rust_crate_output,
root_gen_dir) ],
"trim string")
source_dir = generator_rust_crate_output
deps = []
foreach(d, all_deps) {
# Resolve the name, so that a target //fidl/something becomes
# //fidl/something:something and we can append "_rust_library" to get the
# rust dependency name.
full_name = get_label_info(d, "label_no_toolchain")
deps += [ "${full_name}_rust_library" ]
}
deps += [
"//garnet/public/lib/fidl/rust/fidl",
"//garnet/public/rust/crates/tokio-fuchsia",
"//garnet/public/rust/crates/fuchsia-zircon",
"//third_party/rust-crates:futures-0.1.16",
]
non_rust_deps = [ ":${rust_crate_target_name}" ]
}
# Creates a map from fidl file to GN build target which supplies it. Used primarily
# for resolving dependencies in the Rust binding generation.
save_target = target_name
action(map_target) {
script = "//garnet/public/lib/fidl/build/make_map.py"
deps = []
foreach(d, all_deps) {
# Resolve the name, so that a target //fidl/something becomes
# //fidl/something:something and we can append "_map" to get the map
# dependency name.
full_name = get_label_info(d, "label_no_toolchain")
deps += [ "${full_name}_map" ]
}
if (defined(invoker.deps)) {
map_deps = []
foreach(d, invoker.deps) {
dep_name = get_label_info(d, "name")
dep_target_gen_dir = get_label_info(d, "target_gen_dir")
map_deps += [ "$dep_target_gen_dir/${dep_name}_map.txt" ]
}
rebase_map_deps = rebase_path(map_deps, root_build_dir)
}
if (defined(invoker.public_deps)) {
map_public_deps = []
foreach(d, invoker.public_deps) {
dep_name = get_label_info(d, "name")
dep_target_gen_dir = get_label_info(d, "target_gen_dir")
map_public_deps += [ "$dep_target_gen_dir/${dep_name}_map.txt" ]
}
rebase_map_public_deps = rebase_path(map_public_deps, root_build_dir)
}
output_fn = "${generator_rust_crate_output}_map.txt"
outputs = [
output_fn,
]
if (defined(invoker.sources)) {
arg_sources = invoker.sources
}
rebase_output = rebase_path(output_fn, root_build_dir)
target_dir = get_label_info("${save_target}", "label_no_toolchain")
args = [
"--target=$target_dir",
"--output=$rebase_output",
]
if (defined(invoker.sources)) {
args += [ "--sources=$arg_sources" ]
}
if (defined(invoker.deps)) {
args += [ "--map-deps=$rebase_map_deps" ]
}
if (defined(invoker.public_deps)) {
args += [ "--map-public-deps=$rebase_map_public_deps" ]
}
}
}
if (defined(invoker.sources)) {
# The generated C++ source files. The main reason to introduce this target
# is so that lib/fidl/cpp/bindings can depend on fidl interfaces without
# circular dependencies. It means that the target is missing the dependency
# on lib/fidl/cpp/bindings. No external targets should depend directly on
# this target *except* lib/fidl/cpp/bindings and other *_cpp_sources
# targets.
source_set(cpp_sources_target_name + "__common") {
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
sources = process_file_template(
invoker.sources,
[
"{{source_gen_dir}}/{{source_file_part}}-common.cc",
"{{source_gen_dir}}/{{source_file_part}}-common.h",
"{{source_gen_dir}}/{{source_file_part}}-internal.h",
])
public_configs = [ "//garnet/public:config" ]
deps = [
":$generator_target_name",
"//garnet/public/lib/fidl/compiler/interfaces:interfaces__generator",
"//garnet/public/lib/fidl/cpp/bindings",
]
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
# //mojo/something:something and we can append cpp_sources_suffix to
# get the cpp dependency name.
full_name = get_label_info(d, "label_no_toolchain")
deps += [ "${full_name}_${cpp_sources_suffix}" ]
}
}
source_set(cpp_sources_target_name) {
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
sources = process_file_template(
invoker.sources,
[
"{{source_gen_dir}}/{{source_file_part}}.h",
"{{source_gen_dir}}/{{source_file_part}}.cc",
"{{source_gen_dir}}/{{source_file_part}}-sync.cc",
"{{source_gen_dir}}/{{source_file_part}}-sync.h",
])
public_configs =
[ "//garnet/public/lib/fidl/cpp/bindings:bindings_config" ]
deps = [
":$generator_target_name",
":${cpp_sources_target_name}__common",
"//garnet/public/lib/fidl/compiler/interfaces:interfaces__generator",
"//garnet/public/lib/fidl/cpp/bindings",
]
foreach(d, all_deps) {
# Resolve the name, so that a target //mojo/something becomes
# //mojo/something:something and we can append cpp_sources_suffix to
# get the cpp dependency name.
full_name = get_label_info(d, "label_no_toolchain")
deps += [ "${full_name}_${cpp_sources_suffix}" ]
}
}
}
if (generate_fidl_for_dart) {
# Compute the Dart package name in advance to ensure it does not contain the
# "_dart" suffix.
# See //build/dart/dart_package.gni for more details.
target_label = get_label_info(":$target_name", "label_no_toolchain")
# This target is used to generate Dart package information
dart_package("${target_name}_dart") {
generator_label = ":$generator_target_name($target_toolchain)"
package_label = target_label
source_dir = get_label_info(generator_label, "target_gen_dir")
# Disable analysis. FIDL targets in a same build file will share a gen (and
# therefore source) directory which confuses the analyzer trying to process
# every single file in the directory but not having the right packages set
# up.
disable_analysis = true
generated_code = true
deps = [
"//topaz/public/lib/fidl/dart",
]
fidl_deps = []
if (defined(invoker.deps)) {
fidl_deps += invoker.deps
}
if (defined(invoker.public_deps)) {
fidl_deps += invoker.public_deps
}
# Depend on the generated Dart package for all of our fidl dependencies.
foreach(d, fidl_deps) {
dep_label = get_label_info(d, "label_no_toolchain")
deps += [ "${dep_label}_dart" ]
}
non_dart_deps = []
if (defined(invoker.sources)) {
non_dart_deps += [ generator_label ]
}
}
}
}