Add support for GOSSAFUNC/-ssafunc SSA debug flags in rules_go
Description
Background: The Go compiler’s SSA backend can emit an interactive HTML dump of the SSA IR for a given function when you set the GOSSAFUNC environment variable:
GOSSAFUNC=MyFunc go build
This produces an ssa.html file showing all compilation phases, inlining decisions, and optimizations for MyFunc, which is invaluable when investigating performance regressions, validating correctness, or understanding the compiler’s IR transformations.
Description
This produces an ssa.html file showing all compilation phases, inlining decisions, and optimizations for MyFunc, which is invaluable when investigating performance regressions, validating correctness, or understanding the compiler’s IR transformations.
Problem
Currently, rules_go offers no way to request SSA debug output from within a Bazel build:
- Passing
--action_env=GOSSAFUNC=…has no effect, because Bazel’s sandbox strips most Go toolchain environment variables. - There is no dedicated
ssafuncattribute (or extension ofgc_goopts) ongo_binary,go_library, orgo_test. - Teams must build outside Bazel (via plain
go build) to inspect SSA dumps, breaking hermeticity and reproducibility.
Proposal
-
Add a new
ssafuncattribute togo_binary,go_library, andgo_test:go_binary( name = "myapp", srcs = ["main.go"], ssafunc = ["main", "(*MyType).Compute"], importpath = "github.com/example/myapp", ) -
Wire
ssafuncinto the compile action by either:- Setting
GOSSAFUNC=<fn>in the sandboxed environment, or - Passing
-ssafunc=<fn>togo tool compileonce available upstream.
- Setting
-
Emit the SSA HTML into the build output directory:
bazel build //:myapp open bazel-bin/myapp.ssa.html -
Document the feature in the rules_go README alongside
gc_gooptsandgc_linkopts.
Example
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
go_binary(
name = "server",
srcs = ["server.go"],
ssafunc = ["(*Server).handleRequest", "helperFunc"],
importpath = "github.com/example/server",
)
Building this target will produce bazel-bin/server.ssa.html, allowing developers to inspect SSA IR directly from a Bazel build.
Can --ssafunc be passed in via gc_goopts? In that case we could just check whether it's been passed and if so add the emitted file to an ssa output group (via OutputGroupInfo) that users can request.
I would prefer that over adding a dedicated attribute. We have many already and there appears to be a way to get by with freeform flags that matches what you would do with regular Go.
Would you be interested in working on a PR for this?
Hi Fabian, thanks for replying. I think the issue is currently Go only supports GOSSAFUNC as an environment variable, and there is no --ssafunc command line flag yet.
Let me know if passing GOSSAFUNC to gc_goopts will work in this case. If so, I'm happy to work on a PR for this.
Meanwhile, I will also check with the Go community to see if they can support --ssafunc.
@jayconrod What do you think of having Go actions inherit --action_env? It's been "marketed" as a best practice for some time in the past, but it also leaks the (by default non-hermetic) PATH into otherwise perfectly hermetic Go actions. It's also frequently abused in ways that hurt build and in particular cache performance.
I'm looking for a way to cover the many env variables go cares about without introducing too many attributes.
I'd rather not inherit --action_env if there's any other way to do it. I'm especially concerned about cache busting. Isn't this basically why we're recompiling protoc all the time?
I also don't think this should be controlled by attribute on go_binary: it's a property of the configuration, not a property of the target.
Could be controlled with a custom build setting maybe? It would need to be something the rules are aware of because we'd need to declare an additional output file.
Is it clear that one wouldn't want to enable this for particular targets?
In the C++ world, this would probably be solved with features, which you set both per-target and globally, as well as a custom output group that exports the files. A build setting would be more in line with the rest of the config in rules_go, but can't be controlled per target.
I guess I'm curious about how it would be used. @lollllcat could you say more about that? I've never actually used this feature, but I assume since the output is HTML it's meant to be human-readable. Would you read that file directly in a browser, or would it be consumed by some other rule?