Skip to content

Commit

Permalink
Add go_cross_test rule for cross-compiling tests.
Browse files Browse the repository at this point in the history
Works the same as the `go_cross_binary` rule.
Because of [this](bazelbuild/bazel#15224) bazel issue,
there's no way to access the underlying `go_test` rule's `env`
info provider. So until bazel 5.3.0 becomes the `rules_go` minimum bazel
version, I see no way of passing through the `go_test` rule's `env` to
the `go_cross_test`. This means any `env` set will not be used when the
`go_cross_test` test is run, which is a little unfortunate. However, I
think `go_cross_test` is still useful in the meantime despite this
limitation.

Signed-off-by: James Bartlett <[email protected]>
  • Loading branch information
JamesMBartlett committed Aug 22, 2022
1 parent 18992d5 commit ab1a106
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 52 deletions.
3 changes: 2 additions & 1 deletion docs/go/core/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,12 @@ load("//go/private/rules:binary.bzl", _go_binary = "go_binary")
load("//go/private/rules:test.bzl", _go_test = "go_test")
load("//go/private/rules:source.bzl", _go_source = "go_source")
load("//go/private/tools:path.bzl", _go_path = "go_path")
load("//go/private/rules:cross.bzl", _go_cross_binary = "go_cross_binary")
load("//go/private/rules:cross.bzl", _go_cross_binary = "go_cross_binary", _go_cross_test = "go_cross_test")

go_library = _go_library
go_binary = _go_binary
go_test = _go_test
go_source = _go_source
go_path = _go_path
go_cross_binary = _go_cross_binary
go_cross_test = _go_cross_test
40 changes: 37 additions & 3 deletions docs/go/core/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,43 @@ This wraps an executable built by `go_binary` to cross compile it
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="go_cross_binary-name"></a>name | A unique name for this target. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | |
| <a id="go_cross_binary-platform"></a>platform | The platform to cross compile the <code>target</code> for. If unspecified, the <code>target</code> will be compiled with the same platform as it would've with the original <code>go_binary</code> rule. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
| <a id="go_cross_binary-sdk_version"></a>sdk_version | The golang SDK version to use for compiling the <code>target</code>. Supports specifying major, minor, and/or patch versions, eg. <code>"1"</code>, <code>"1.17"</code>, or <code>"1.17.1"</code>. The first Go SDK provider installed in the repo's workspace (via <code>go_download_sdk</code>, <code>go_wrap_sdk</code>, etc) that matches the specified version will be used for compiling the given <code>target</code>. If unspecified, the <code>target</code> will be compiled with the same SDK as it would've with the original <code>go_binary</code> rule. Transitions <code>target</code> by changing the <code>--@io_bazel_rules_go//go/toolchain:sdk_version</code> build flag to the value provided for <code>sdk_version</code> here. | String | optional | "" |
| <a id="go_cross_binary-target"></a>target | Go binary target to transition to the given platform and/or sdk_version. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required | |
| <a id="go_cross_binary-platform"></a>platform | The platform to cross compile the <code>target</code> for. If unspecified, the <code>target</code> will be compiled with the same platform as it would've with the original <code>go_binary</code> rule. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
| <a id="go_cross_binary-sdk_version"></a>sdk_version | The golang SDK version to use for compiling the <code>target</code>. Supports specifying major, minor, and/or patch versions, eg. <code>"1"</code>, <code>"1.17"</code>, or <code>"1.17.1"</code>. The first Go SDK provider installed in the repo's workspace (via <code>go_download_sdk</code>, <code>go_wrap_sdk</code>, etc) that matches the specified version will be used for compiling the given <code>target</code>. If unspecified, the <code>target</code> will be compiled with the same SDK as it would've with the original <code>go_binary</code> rule. Transitions <code>target</code> by changing the <code>--@io_bazel_rules_go//go/toolchain:sdk_version</code> build flag to the value provided for <code>sdk_version</code> here. | String | optional | "" |
| <a id="go_cross_binary-target"></a>target | <code>go_binary</code> target to transition to the given platform and/or sdk_version. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required | |





<a id="#go_cross_test"></a>

## go_cross_test

<pre>
go_cross_test(<a href="#go_cross_test-name">name</a>, <a href="#go_cross_test-platform">platform</a>, <a href="#go_cross_test-sdk_version">sdk_version</a>, <a href="#go_cross_test-target">target</a>)
</pre>

This wraps a test built by `go_test` to cross compile it
for a different platform, and/or compile it using a different version
of the golang SDK.<br><br>
Warning: Any `env` set in the `go_test` rule, will not be passed through
to the `go_cross_test` rule due to a <a href=https://github.com/bazelbuild/bazel/issues/15224>bug</a>
in bazel.
**Providers:**
<ul>
<li>[GoArchive]</li>
</ul>


### **Attributes**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="go_cross_test-name"></a>name | A unique name for this target. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | |
| <a id="go_cross_test-platform"></a>platform | The platform to cross compile the <code>target</code> for. If unspecified, the <code>target</code> will be compiled with the same platform as it would've with the original <code>go_test</code> rule. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
| <a id="go_cross_test-sdk_version"></a>sdk_version | The golang SDK version to use for compiling the <code>target</code>. Supports specifying major, minor, and/or patch versions, eg. <code>"1"</code>, <code>"1.17"</code>, or <code>"1.17.1"</code>. The first Go SDK provider installed in the repo's workspace (via <code>go_download_sdk</code>, <code>go_wrap_sdk</code>, etc) that matches the specified version will be used for compiling the given <code>target</code>. If unspecified, the <code>target</code> will be compiled with the same SDK as it would've with the original <code>go_test</code> rule. Transitions <code>target</code> by changing the <code>--@io_bazel_rules_go//go/toolchain:sdk_version</code> build flag to the value provided for <code>sdk_version</code> here. | String | optional | "" |
| <a id="go_cross_test-target"></a>target | <code>go_test</code> target to transition to the given platform and/or sdk_version. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required | |



Expand Down
3 changes: 3 additions & 0 deletions go/def.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ load(
load(
"//go/private/rules:cross.bzl",
_go_cross_binary = "go_cross_binary",
_go_cross_test = "go_cross_test",
)

# TOOLS_NOGO is a list of all analysis passes in
Expand Down Expand Up @@ -170,6 +171,8 @@ go_path = _go_path

# See docs/go/core/rules.md#go_cross_binary for full documentation.
go_cross_binary = _go_cross_binary
# See docs/go/core/rules.md#go_cross_binary for full documentation.
go_cross_test = _go_cross_test

def go_vet_test(*args, **kwargs):
fail("The go_vet_test rule has been removed. Please migrate to nogo instead, which supports vet tests.")
Expand Down
103 changes: 66 additions & 37 deletions go/private/rules/cross.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ def _error_script(ctx):
ctx.actions.write(error_script, UNIX_ERR_SCRIPT.format(errmsg), is_executable = True)
return error_script

def _get_test_info_providers():
providers = []

# Once https://github.com/bazelbuild/bazel/pull/15766 is in the minimum bazel version (probably 5.3.0).
# We can enable passing through of test environment info.
# providers = [RunEnvironmentInfo]
return providers

def _go_cross_impl(ctx):
old_default_info = ctx.attr.target[DefaultInfo]
old_executable = old_default_info.files_to_run.executable
Expand Down Expand Up @@ -89,44 +97,50 @@ def _go_cross_impl(ctx):
GoArchive,
OutputGroupInfo,
CcInfo,
]
InstrumentedFilesInfo,
] + _get_test_info_providers()
if provider in ctx.attr.target
]
return [new_default_info] + providers

_go_cross_kwargs = {
"implementation": _go_cross_impl,
"attrs": {
"target": attr.label(
doc = """Go binary target to transition to the given platform and/or sdk_version.
""",
providers = [GoLibrary, GoSource, GoArchive],
mandatory = True,
),
"platform": attr.label(
doc = """The platform to cross compile the `target` for.
If unspecified, the `target` will be compiled with the
same platform as it would've with the original `go_binary` rule.
""",
),
"sdk_version": attr.string(
doc = """The golang SDK version to use for compiling the `target`.
Supports specifying major, minor, and/or patch versions, eg. `"1"`,
`"1.17"`, or `"1.17.1"`. The first Go SDK provider installed in the
repo's workspace (via `go_download_sdk`, `go_wrap_sdk`, etc) that
matches the specified version will be used for compiling the given
`target`. If unspecified, the `target` will be compiled with the same
SDK as it would've with the original `go_binary` rule.
Transitions `target` by changing the `--@io_bazel_rules_go//go/toolchain:sdk_version`
build flag to the value provided for `sdk_version` here.
""",
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
"cfg": go_cross_transition,
"doc": """This wraps an executable built by `go_binary` to cross compile it
def _go_cross_kwargs_for_target_type(target_type):
return {
"implementation": _go_cross_impl,
"attrs": {
"target": attr.label(
doc = """`{target_type}` target to transition to the given platform and/or sdk_version.
""".format(target_type = target_type),
providers = [GoArchive],
mandatory = True,
),
"platform": attr.label(
doc = """The platform to cross compile the `target` for.
If unspecified, the `target` will be compiled with the
same platform as it would've with the original `{target_type}` rule.
""".format(target_type = target_type),
),
"sdk_version": attr.string(
doc = """The golang SDK version to use for compiling the `target`.
Supports specifying major, minor, and/or patch versions, eg. `"1"`,
`"1.17"`, or `"1.17.1"`. The first Go SDK provider installed in the
repo's workspace (via `go_download_sdk`, `go_wrap_sdk`, etc) that
matches the specified version will be used for compiling the given
`target`. If unspecified, the `target` will be compiled with the same
SDK as it would've with the original `{target_type}` rule.
Transitions `target` by changing the `--@io_bazel_rules_go//go/toolchain:sdk_version`
build flag to the value provided for `sdk_version` here.
""".format(target_type = target_type),
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
"cfg": go_cross_transition,
}

go_cross_binary = rule(
executable = True,
doc = """This wraps an executable built by `go_binary` to cross compile it
for a different platform, and/or compile it using a different version
of the golang SDK.<br><br>
**Providers:**
Expand All @@ -136,6 +150,21 @@ _go_cross_kwargs = {
<li>[GoArchive]</li>
</ul>
""",
}

go_cross_binary = rule(executable = True, **_go_cross_kwargs)
**_go_cross_kwargs_for_target_type("go_binary")
)
go_cross_test = rule(
executable = True,
test = True,
doc = """This wraps a test built by `go_test` to cross compile it
for a different platform, and/or compile it using a different version
of the golang SDK.<br><br>
Warning: Any `env` set in the `go_test` rule, will not be passed through
to the `go_cross_test` rule due to a <a href=https://github.com/bazelbuild/bazel/issues/15224>bug</a>
in bazel.
**Providers:**
<ul>
<li>[GoArchive]</li>
</ul>
""",
**_go_cross_kwargs_for_target_type("go_test")
)
55 changes: 44 additions & 11 deletions tests/core/cross/sdk_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,34 @@ import (
)

type testcase struct {
Name, SDKVersion, expectedVersion string
Name, SDKVersion, ExpectedVersion string
}

var testCases = []testcase{
{
Name: "major_version",
SDKVersion: "1",
expectedVersion: "go1.16",
ExpectedVersion: "go1.16",
},
{
Name: "minor_version",
SDKVersion: "1.16",
expectedVersion: "go1.16",
ExpectedVersion: "go1.16",
},
{
Name: "patch_version",
SDKVersion: "1.16.0",
expectedVersion: "go1.16",
ExpectedVersion: "go1.16",
},
{
Name: "1_17_minor_version",
SDKVersion: "1.17",
expectedVersion: "go1.17",
ExpectedVersion: "go1.17",
},
{
Name: "1_17_patch_version",
SDKVersion: "1.17.1",
expectedVersion: "go1.17.1",
ExpectedVersion: "go1.17.1",
},
}

Expand Down Expand Up @@ -91,19 +91,47 @@ import (
func main() {
fmt.Print(runtime.Version())
}
-- test.go --
package test
import (
"runtime"
"testing"
)
var WantVersion = ""
func TestVersion(t *testing.T) {
gotVersion := runtime.Version()
if WantVersion != gotVersion {
t.Logf("wanted %s, got %s", WantVersion, gotVersion)
t.Fail()
}
}
-- BUILD.bazel --
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_cross_binary")
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_cross_binary", "go_test", "go_cross_test")
go_binary(
name = "print_version",
srcs = ["main.go"],
)
{{range .TestCases}}
go_cross_binary(
name = "{{.Name}}",
name = "{{.Name}}_binary",
target = ":print_version",
sdk_version = "{{.SDKVersion}}",
)
go_test(
name = "{{.Name}}_test_w_env",
srcs = ["test.go"],
x_defs = {"WantVersion": "{{.ExpectedVersion}}"},
)
go_cross_test(
name = "{{.Name}}_test",
target = ":{{.Name}}_test_w_env",
sdk_version = "{{.SDKVersion}}",
)
{{end}}
`))
tmplValues := struct{
Expand All @@ -122,14 +150,19 @@ go_cross_binary(
func Test(t *testing.T) {
for _, test := range testCases {
t.Run(test.Name, func(t *testing.T) {
output, err := bazel_testing.BazelOutput("run", fmt.Sprintf("//:%s", test.Name))
output, err := bazel_testing.BazelOutput("run", fmt.Sprintf("//:%s_binary", test.Name))
if err != nil {
t.Fatal(err)
}
actualVersion := string(output)
if actualVersion != test.expectedVersion {
t.Fatal("actual", actualVersion, "vs expected", test.expectedVersion)
if actualVersion != test.ExpectedVersion {
t.Fatal("actual", actualVersion, "vs expected", test.ExpectedVersion)
}

err = bazel_testing.RunBazel("test", fmt.Sprintf("//:%s_test", test.Name))
if err != nil {
t.Fatal(err)
}
})
}
}

0 comments on commit ab1a106

Please sign in to comment.