Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 1 | # Copyright 2019 The Pigweed Authors |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| 4 | # use this file except in compliance with the License. You may obtain a copy of |
| 5 | # the License at |
| 6 | # |
| 7 | # https://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, WITHOUT |
| 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | # License for the specific language governing permissions and limitations under |
| 13 | # the License. |
| 14 | |
| 15 | # This file provides GN build integration for Go. These templates are limited, |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 16 | # supporting only legacy GOPATH-based builds. |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 17 | |
| 18 | import("exec.gni") |
| 19 | import("input_group.gni") |
| 20 | |
| 21 | # Defines a Go package. |
| 22 | # |
| 23 | # A Go package consists of one or more Go files in a single directory. The |
| 24 | # package can depend on other Go packages or generated Go code. |
| 25 | # |
| 26 | # Args: |
| 27 | # sources: List of Go source files. |
| 28 | # deps: Optional list of target dependencies. |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 29 | # external_deps: Optional list of Go package dependencies outside of Pigweed. |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 30 | # gopath: Root of the GOPATH in which the package is located. |
| 31 | # |
| 32 | # Example: |
| 33 | # |
| 34 | # # In //my_module/go/src/example.com/foo/BUILD.gn |
| 35 | # pw_go_package("foo_package") { |
| 36 | # sources = [ "main.go" ] |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 37 | # deps = [ |
| 38 | # "//my_module:foo_proto_go" |
| 39 | # ] |
| 40 | # external_deps = [ |
| 41 | # "github.com/golang/glog" |
| 42 | # ] |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 43 | # gopath = "//my_module/go" |
| 44 | # } |
| 45 | # |
| 46 | template("pw_go_package") { |
| 47 | assert(defined(invoker.sources), "pw_go_source_set requires sources") |
| 48 | assert(defined(invoker.gopath), "pw_go_source_set requires a GOPATH root") |
| 49 | |
| 50 | _gopath = rebase_path(invoker.gopath) |
| 51 | |
| 52 | # List the sources in an input group with GOPATH environment metadata. |
| 53 | pw_input_group(target_name) { |
| 54 | inputs = invoker.sources |
| 55 | forward_variables_from(invoker, |
| 56 | [ |
| 57 | "deps", |
| 58 | "metadata", |
| 59 | ]) |
| 60 | if (!defined(metadata)) { |
| 61 | metadata = { |
| 62 | } |
| 63 | } |
| 64 | metadata.gopath = [ "GOPATH+=${_gopath}" ] |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 65 | |
| 66 | if (defined(invoker.external_deps)) { |
| 67 | metadata.external_deps = invoker.external_deps |
| 68 | } |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 69 | } |
| 70 | } |
| 71 | |
| 72 | # Builds a Go executable from a Go package. |
| 73 | # |
| 74 | # The package must include only a main.go file labelled "package main". It may |
| 75 | # depend on other Go packages defined in the build. |
| 76 | # |
| 77 | # Args: |
| 78 | # deps: List of size one specifying the GN path to the Go package target. |
| 79 | # package: Name of the Go package as resolved by the Go compiler. |
| 80 | # |
| 81 | # Example: |
| 82 | # |
| 83 | # # In //my_module/go |
| 84 | # pw_go_executable("foo") { |
| 85 | # deps = [ "//my_module/go/src/example.com/foo:foo_package" ] |
| 86 | # package = "example.com/foo" |
| 87 | # } |
| 88 | # |
| 89 | template("pw_go_executable") { |
| 90 | assert(defined(invoker.deps), |
| 91 | "pw_go_executable requires at least one Go package as a dependency") |
| 92 | assert(defined(invoker.package), |
| 93 | "pw_go_executable requires the name of the package to build") |
| 94 | |
| 95 | _metadata_target_name = "${target_name}_pw_go_metadata" |
| 96 | _metadata_file = "$target_gen_dir/${target_name}_pw_go_env.env" |
| 97 | |
| 98 | # Collect all the GOPATH metadata from pw_go_package and _pw_go_proto_library |
| 99 | # targets into a plaintext file of environment variable definitions. |
| 100 | generated_file(_metadata_target_name) { |
| 101 | deps = invoker.deps |
| 102 | data_keys = [ "gopath" ] |
Rob Mohr | a0ba54f | 2020-02-27 11:43:49 -0800 | [diff] [blame] | 103 | outputs = [ _metadata_file ] |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 104 | } |
| 105 | |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 106 | # Collect all of the external dependencies of the executable and its packages. |
| 107 | _deps_metadata_target_name = "${target_name}_pw_go_deps" |
| 108 | _deps_metadata_file = "$target_gen_dir/${target_name}_pw_go_deps.txt" |
| 109 | generated_file(_deps_metadata_target_name) { |
| 110 | deps = invoker.deps |
| 111 | data_keys = [ "external_deps" ] |
Rob Mohr | a0ba54f | 2020-02-27 11:43:49 -0800 | [diff] [blame] | 112 | outputs = [ _deps_metadata_file ] |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | _default_gopath = rebase_path("$root_gen_dir/go") |
| 116 | |
| 117 | # Create a target to download all external dependencies into the default |
| 118 | # GOPATH in the out directory. This is only run once; "go get" does not |
| 119 | # re-download existing packages. |
| 120 | _download_target_name = "${target_name}_pw_go_get" |
| 121 | pw_exec(_download_target_name) { |
| 122 | program = "go" |
| 123 | args = [ "get" ] |
Alexei Frolov | ca9cf60 | 2019-12-26 13:00:03 -0800 | [diff] [blame] | 124 | deps = [ ":$_deps_metadata_target_name" ] + invoker.deps |
Rob Mohr | bf3a3af | 2021-05-04 13:48:34 -0700 | [diff] [blame] | 125 | env = [ |
| 126 | "GO111MODULE=off", |
| 127 | "GOPATH=$_default_gopath", |
| 128 | ] |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 129 | args_file = _deps_metadata_file |
| 130 | |
| 131 | # If the args file is empty, don't run the "go get" command. |
| 132 | skip_empty_args = true |
| 133 | |
| 134 | # Limit download parallelization to 1. |
| 135 | pool = "$dir_pw_build:go_download_pool" |
| 136 | } |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 137 | |
| 138 | # Run a "go build" command with the environment configured from metadata. |
| 139 | pw_exec(target_name) { |
| 140 | program = "go" |
| 141 | args = [ |
| 142 | "build", |
| 143 | "-o", |
Wyatt Hepler | 8224a64 | 2020-07-29 08:55:56 -0700 | [diff] [blame] | 144 | rebase_path(target_out_dir), |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 145 | invoker.package, |
| 146 | ] |
| 147 | deps = [ |
Alexei Frolov | c15a988 | 2019-12-23 14:29:02 -0800 | [diff] [blame] | 148 | ":$_download_target_name", |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 149 | ":$_metadata_target_name", |
| 150 | ] |
Rob Mohr | bf3a3af | 2021-05-04 13:48:34 -0700 | [diff] [blame] | 151 | env = [ |
| 152 | "GO111MODULE=off", |
| 153 | "GOPATH+=$_default_gopath", |
| 154 | ] |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 155 | env_file = _metadata_file |
Wyatt Hepler | 8224a64 | 2020-07-29 08:55:56 -0700 | [diff] [blame] | 156 | |
| 157 | _binary_name = get_path_info(invoker.package, "name") |
| 158 | |
| 159 | if (host_os == "win") { |
| 160 | _extension = ".exe" |
| 161 | } else { |
| 162 | _extension = "" |
| 163 | } |
| 164 | |
| 165 | outputs = [ "$target_out_dir/$_binary_name$_extension" ] |
Alexei Frolov | def1471 | 2019-12-23 13:03:32 -0800 | [diff] [blame] | 166 | } |
| 167 | } |