diff --git a/plugins/heph-go/skills/heph-go/references/go-plugin.md b/plugins/heph-go/skills/heph-go/references/go-plugin.md index e955962..f702e53 100644 --- a/plugins/heph-go/skills/heph-go/references/go-plugin.md +++ b/plugins/heph-go/skills/heph-go/references/go-plugin.md @@ -46,6 +46,7 @@ plugins: |------------|----------------------|--------------|-------------| | `gotool` | `string` | **required** | Go toolchain to use. Set to a pinned version like `"1.26.4"` (hermetic SDK downloaded from `go.dev/dl`), `"host"` (use the `go` binary already on the host's `PATH`), or a target address like `"//@heph/bin:go"` (use the toolchain a target produces). | | `govet` | `string` (target addr) | the plugin's own published `heph-govet` build | The `heph-govet` binary lint/format targets run — see "Linting and formatting" below. | +| `cctool` | `string` (target addr) | the host's `cc` via the `hostbin` provider (`//@heph/bin:cc`) | The C compiler a race-detector build stages where it needs cgo — see "Race detector" below. Only resolved when such a build actually runs. | | `checksums` | `map[string, string]` | `{}` | Expected SHA-256 digests for hermetic SDK tarballs, keyed `"//"` (e.g. `"1.26.4/linux/amd64"`), and for `govet` release downloads, keyed `"govet///"`. Look up SDK values at https://go.dev/dl/?mode=json. Without an entry the download is unverified (warning logged). SDK entries have no effect when `gotool = "host"`. | | `skip` | `string[]` | `[]` | Workspace-relative glob patterns for directories to exclude from Go package discovery. Each pattern is matched against the directory's workspace-relative path. | | `walk_db` | path | `/heph-plugin-go-fswalk.db` | Path to the filesystem walk cache database. | @@ -89,11 +90,13 @@ For a normal package the provider produces (the two you reference directly): | `:build` | The library, or binary for `package main`. | — | | `:test` | The package's in-package tests. | `test`, `go-test` | -There is also `:xtest` for external (`package foo_test`) tests. A number of -internal variants exist to make compilation and linking agree -(`build_test_lib`, `build_xtest_lib`, `build_testmain_lib`, `testmain`, -`embed_test`, etc., plus a per-package `_golist`). These are implementation -detail — don't depend on them by hand; depend on `:build`, `:test`, `:xtest`. +There is also `:xtest` for external (`package foo_test`) tests, and their +race-detector counterparts `:test_race` / `:xtest_race` (labels `test-race`, +`go-test-race` — see "Race detector" below). A number of internal variants +exist to make compilation and linking agree (`build_test_lib`, +`build_xtest_lib`, `build_testmain_lib`, `testmain`, `embed_test`, etc., plus a +per-package `_golist`). These are implementation detail — don't depend on them +by hand; depend on `:build`, `:test`, `:xtest`, `:test_race`, `:xtest_race`. Inspect what exists: @@ -115,6 +118,40 @@ only read these (e.g. in a dep graph); never write them by hand. Because module + version are part of the address, a dependency bump changes the address and invalidates only the targets importing it. +## Race detector + +Every package with tests also gets `:test_race` and `:xtest_race` — `test` and +`xtest`, compiled and linked with Go's race detector. + +```bash +heph run //lib/auth:test_race # run this package's tests under the race detector +heph run 'label(test-race)' # every race-detector test in the workspace +``` + +Race instrumentation covers the whole program, standard library included, so +race targets are several times slower to build and run than `test`/`xtest`. +They carry the `test-race`/`go-test-race` labels instead of `test`/`go-test`, +so `heph run 'label(test)'` keeps meaning the ordinary suite. Run both +together with `label(test) || label(test-race)`. + +`:test_race`/`:xtest_race` accept the same `@v=NAME` variant selection and the +same `provider_state(test = {...})` config (`env`, `pass_env`, `pre_run`, …) as +`:test`/`:xtest`. On Linux, a race build always links `buildmode = "exe"`, even +if the selected variant declares `buildmode = "pie"` — Go's race detector +doesn't support PIE there. On darwin the variant's declared buildmode is +honored as-is. + +A race build needs a C compiler everywhere except darwin, where Go's race +runtime has no cgo dependency. On Linux, the `cctool` provider option picks +which C compiler to stage (defaults to the host's `cc` via `hostbin`, resolved +only when a race build that needs cgo actually runs): + +```yaml title=".hephconfig" +options: + gotool: "1.26.4" + cctool: "//@heph/bin:cc" # default; point elsewhere for a hermetic compiler +``` + ## Linting and formatting A Go module gets `lint-check`, `lint`, `format-check`, and `format` targets the diff --git a/website/docs/plugins/go.md b/website/docs/plugins/go.md index c1d23d7..e3606f9 100644 --- a/website/docs/plugins/go.md +++ b/website/docs/plugins/go.md @@ -63,6 +63,7 @@ plugins: |--------|------|---------|-------------| | `gotool` | `string` | **required** | Go toolchain to use. Set to a pinned version like `"1.26.4"` to download the SDK hermetically from `go.dev/dl`, `"host"` to use the `go` binary already on the host's `PATH`, or a target address like `"//@heph/bin:go"` to use the toolchain a target produces. | | `govet` | `string` (target address) | the plugin's own published `heph-govet` build | The `heph-govet` binary that [lint and format targets](#linting-and-formatting) run. See [Pinning the analyzer binary](#pinning-the-analyzer-binary). | +| `cctool` | `string` (target address) | the host's `cc`, via [hostbin](./hostbin.md) (`//@heph/bin:cc`) | The C compiler a [race-detector](#race-detector) build stages where it needs cgo. Only resolved when such a build actually runs. | | `checksums` | `map[string, string]` | `{}` | Expected SHA-256 digests for hermetic SDK tarballs, keyed `"//"` (e.g. `"1.26.4/linux/amd64"`), and for `govet` release downloads, keyed `"govet///"`. Look up SDK values at [go.dev/dl/?mode=json](https://go.dev/dl/?mode=json). When a key is missing the download is unverified (a warning is logged). SDK checksums have no effect when `gotool = "host"`. | | `skip` | `string[]` | `[]` | Workspace-relative glob patterns for directories to exclude from Go package discovery. | | `walk_db` | path | `/heph-plugin-go-fswalk.db` | Path to the filesystem walk cache database. | @@ -156,6 +157,48 @@ heph run //cmd/server:build # compile the binary heph run //lib/auth:test # run the package's tests ``` +## Race detector + +Every package with tests also gets `:test_race` and `:xtest_race` — `test` and +`xtest`, compiled and linked with Go's race detector. + +| Target | Builds | Labels | +|---------------|----------------------------------------------|------------------------------| +| `:test_race` | The package's tests, with `-race`. | `test-race`, `go-test-race` | +| `:xtest_race` | The package's external tests, with `-race`. | `test-race`, `go-test-race` | + +```bash title="terminal" +heph run //lib/auth:test_race # run this package's tests under the race detector +heph run 'label(test-race)' # every race-detector test in the workspace +``` + +Race instrumentation covers the whole program, standard library included, so +race targets are several times slower to build and run than `test`/`xtest`. +That's why they carry the `test-race`/`go-test-race` labels instead of +`test`/`go-test`: `heph run 'label(test)'` keeps meaning the ordinary suite. +Run both together with `label(test) || label(test-race)`. + +`:test_race`/`:xtest_race` accept the same `@v=NAME` variant selection and the +same `provider_state(test = {...})` configuration — `env`, `pass_env`, +`pre_run`, and so on — as `:test`/`:xtest`. See [Test environment](#test-environment). +On Linux, a race build always links with `buildmode = "exe"`, even if the +selected variant declares `buildmode = "pie"` — Go's race detector doesn't +support PIE there. On darwin the variant's declared buildmode is honored as-is. + +A race build needs a C compiler everywhere except darwin, where Go's race +runtime has no cgo dependency. On Linux, the `cctool` option picks which C +compiler to stage — it defaults to the host's `cc`, found through the +[hostbin](./hostbin.md) provider: + +```yaml title=".hephconfig" +options: + gotool: "1.26.4" + cctool: "//@heph/bin:cc" # default; point elsewhere for a hermetic compiler +``` + +`cctool` is resolved only when a race build that needs cgo actually runs — an +ordinary build, and a darwin race build, never touch it. + ## Linting and formatting A Go module gets four extra targets the moment it has a `.golangci.yml` (or