third_party.pigweed.src/pw_build/go.gni
Alexei Frolov c15a98852f
Download external Go dependencies in build
This change updates the Go GN integration to download external
dependencies for Go packages before running "go build". These
dependencies are listed in the pw_go_package template using build
metadata and collected to a "go get" invocation.

To support this, the pw_exec template is expanded to allow setting
positional arguments from a file.

Change-Id: If4f6c71f037b35bb041984da9982a1629d1d36b0
2019-12-26 10:39:48 -08:00

158 lines
4.7 KiB
Plaintext

# Copyright 2019 The Pigweed Authors
#
# 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
#
# https://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.
# This file provides GN build integration for Go. These templates are limited,
# supporting only legacy GOPATH-based builds.
import("exec.gni")
import("input_group.gni")
# Defines a Go package.
#
# A Go package consists of one or more Go files in a single directory. The
# package can depend on other Go packages or generated Go code.
#
# Args:
# sources: List of Go source files.
# deps: Optional list of target dependencies.
# external_deps: Optional list of Go package dependencies outside of Pigweed.
# gopath: Root of the GOPATH in which the package is located.
#
# Example:
#
# # In //my_module/go/src/example.com/foo/BUILD.gn
# pw_go_package("foo_package") {
# sources = [ "main.go" ]
# deps = [
# "//my_module:foo_proto_go"
# ]
# external_deps = [
# "github.com/golang/glog"
# ]
# gopath = "//my_module/go"
# }
#
template("pw_go_package") {
assert(defined(invoker.sources), "pw_go_source_set requires sources")
assert(defined(invoker.gopath), "pw_go_source_set requires a GOPATH root")
_gopath = rebase_path(invoker.gopath)
# List the sources in an input group with GOPATH environment metadata.
pw_input_group(target_name) {
inputs = invoker.sources
forward_variables_from(invoker,
[
"deps",
"metadata",
])
if (!defined(metadata)) {
metadata = {
}
}
metadata.gopath = [ "GOPATH+=${_gopath}" ]
if (defined(invoker.external_deps)) {
metadata.external_deps = invoker.external_deps
}
}
}
# Builds a Go executable from a Go package.
#
# The package must include only a main.go file labelled "package main". It may
# depend on other Go packages defined in the build.
#
# Args:
# deps: List of size one specifying the GN path to the Go package target.
# package: Name of the Go package as resolved by the Go compiler.
#
# Example:
#
# # In //my_module/go
# pw_go_executable("foo") {
# deps = [ "//my_module/go/src/example.com/foo:foo_package" ]
# package = "example.com/foo"
# }
#
template("pw_go_executable") {
assert(defined(invoker.deps),
"pw_go_executable requires at least one Go package as a dependency")
assert(defined(invoker.package),
"pw_go_executable requires the name of the package to build")
_metadata_target_name = "${target_name}_pw_go_metadata"
_metadata_file = "$target_gen_dir/${target_name}_pw_go_env.env"
# Collect all the GOPATH metadata from pw_go_package and _pw_go_proto_library
# targets into a plaintext file of environment variable definitions.
generated_file(_metadata_target_name) {
deps = invoker.deps
data_keys = [ "gopath" ]
outputs = [
_metadata_file,
]
}
# Collect all of the external dependencies of the executable and its packages.
_deps_metadata_target_name = "${target_name}_pw_go_deps"
_deps_metadata_file = "$target_gen_dir/${target_name}_pw_go_deps.txt"
generated_file(_deps_metadata_target_name) {
deps = invoker.deps
data_keys = [ "external_deps" ]
outputs = [
_deps_metadata_file,
]
}
_default_gopath = rebase_path("$root_gen_dir/go")
# Create a target to download all external dependencies into the default
# GOPATH in the out directory. This is only run once; "go get" does not
# re-download existing packages.
_download_target_name = "${target_name}_pw_go_get"
pw_exec(_download_target_name) {
program = "go"
args = [ "get" ]
deps = [
":$_deps_metadata_target_name",
]
env = [ "GOPATH=$_default_gopath" ]
args_file = _deps_metadata_file
# If the args file is empty, don't run the "go get" command.
skip_empty_args = true
# Limit download parallelization to 1.
pool = "$dir_pw_build:go_download_pool"
}
# Run a "go build" command with the environment configured from metadata.
pw_exec(target_name) {
program = "go"
args = [
"build",
"-o",
target_out_dir,
invoker.package,
]
deps = [
":$_download_target_name",
":$_metadata_target_name",
]
env = [ "GOPATH+=$_default_gopath" ]
env_file = _metadata_file
}
}