Build Go Targets¶
Blade uses go_library, go_binary, and go_test to build Go packages.
There is also a go_package convenience wrapper that auto-detects the package type.
Configuration¶
Before using go targets, configure the Go toolchain in BLADE_ROOT:
go_config(
go = '/usr/local/go/bin/go', # required
go_home = '/usr/local/go', # GOPATH / build cache; optional (empty = go default)
)
Blade builds Go in module mode only: each target's package must sit under a
go.mod (the nearest one at or above the target's directory is its module).
GOPATH-mode projects are not supported. A workspace may contain multiple modules;
for local cross-module imports use a go.work
file or replace directives, which go resolves.
go_library¶
Build a Go package as a library.
Attributes:
srcs: Go source files. All.gofiles in the same directory must belong to the same Go package.deps: Other go_library or proto_library targets with Go output.extra_goflags: Extra flags passed to the Go compiler (list[str]orstr).visibility: Visibility specification.tags: Build tags.
A go_library has no linkable artifact (the Go build cache replaced the
GOPATH archive). Building one compile-checks the package (go build) and emits a
stamp; consumers depend on it for ordering and visibility and let go recompile
the package. A go_library is optional — a pure-Go package with no cross-language
dependency needs no Blade target, since go build of a consuming go_binary/
go_test pulls it in.
go_binary¶
Build a Go executable.
Attributes are the same as go_library.
A go_binary is built from its srcs in file mode (go build <srcs...>), not
by whole package. This means a single directory holding several main files can
be split into separate go_binary targets — one per program.
go_test¶
Build and run a Go test binary.
go_test(
name = 'mylib_test',
srcs = [
'mylib_test.go',
],
deps = [
':mylib',
],
testdata = [
'testdata/config.json',
],
)
Additional attributes:
testdata: Test data files, similar to other test targets.
go_package¶
Convenience wrapper that automatically detects whether a directory contains a library or a command.
Blade scans the current directory for .go files:
- If any file has
package main, ago_binaryis created. - Otherwise, a
go_libraryis created. - If
*_test.gofiles exist, ago_testis created automatically.
The generated targets are named after name: the go_binary/go_library takes
name, and the auto-created test is <name>_test.
Dependencies¶
A go target's deps lists other Blade targets it must be built with — other
go_library targets and proto_library targets that emit Go code. Blade builds
those first.
Within one module you generally don't need to declare Go→Go deps: go build
resolves intra-module imports from the source itself. Declare a dep when it
crosses a language/build boundary Blade must order — a proto_library (generated
code) or a cc_library (cgo) — or when you want visibility / dependency
governance on it.
Pull in third-party packages (e.g. github.com/...) the normal Go way:
declare them in go.mod (or a go.work for multiple local modules). Blade
delegates to go, which resolves, downloads, and builds them — you do not
list them in Blade deps.
Using Protobuf with Go¶
Depend on a proto_library to generate and import Go protobuf code:
go_binary(
name = 'service',
srcs = ['service.go'],
deps = [
'//proto:myproto', # proto_library target
],
)
The .proto must set option go_package to its in-module import path — the
import path of the .proto's own directory within the Go module:
Blade generates the .pb.go into the build directory — not the source tree —
and builds consuming go targets with go build -overlay, which maps the generated
file into its in-module location just for the build. The source tree stays clean:
nothing to commit, and blade build regenerates the .pb.go when the .proto
changes, ordered before the consuming go target.
Because the generated file lives only in the build directory, it is visible only
to Blade's build. A plain go build, gopls/IDEs, and external importers of your
module do not see it — which is fine for Go that is internal to your Blade build.
For a package you publish (imported outside your Blade build), generate the
.pb.go yourself, check it in beside the .proto, and build it as an ordinary
go_library — a real source file that tooling and external importers resolve
normally. Don't route external consumers through the overlay-generated Go.
Requires the protoc-gen-go plugin — proto_library_config(protoc_go_plugin=...)
in BLADE_ROOT. (proto_library also emits C++, so the C++ protobuf toolchain
must be configured as usual.)
Using C/C++ with cgo¶
A go target can call into a Blade cc_library through Go's
cgo. List the cc_library in deps and use
import "C" in the Go source:
package main
/*
#include "greeter/greeter.h"
*/
import "C"
import "fmt"
func main() { fmt.Println(C.GoString(C.greet())) }
Blade wires the dependency into the cgo build: the cc_library's exported include
dirs become CGO_CFLAGS, and its static archive plus its transitive libraries
and system libs become CGO_LDFLAGS — so the C preamble's #include resolves
and the linker finds the C symbols. The archive is built before the go link.
Notes:
- The C preamble sees the workspace root and the build dir on its include
path, so headers are included by their workspace-relative path (e.g.
#include "greeter/greeter.h"), matching how cc targets include headers. - cgo can only call the C ABI. A C++
cc_librarymust exposeextern "C"entry points; Blade adds the C++ runtime (-lstdc++/-lc++) to the link, so a C++ archive links cleanly. - Only
cc_librarydeps are linked. Aproto_librarydep contributes its Go (§ Protobuf), never its C++ archive. - This is the only supported direction — a Go target using C/C++. The reverse (a
cc_binaryembedding Go) is a non-goal: each Go archive carries a whole Go runtime, and a process can't host two.