Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

always produce .a files at the beginning of a build #3385

Merged
merged 38 commits into from
Dec 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d6cb38c
always produce .a files at the beginning of a build
matloob Nov 23, 2022
784c1c0
fix a bad cleanup in stdlib.bzl
matloob Dec 6, 2022
dc93dfb
redefine transition in terms of what's kept
matloob Dec 6, 2022
36c5314
Merge branch 'bazelbuild:master' into go
matloob Dec 7, 2022
04c752c
use go_reset_target for the builder
matloob Dec 7, 2022
b81c415
remove previosly deleted code that came back in a merge`
matloob Dec 7, 2022
8421750
fix buildifier issue
matloob Dec 7, 2022
c45ec9c
try to use tmpdir on WINDOWS
matloob Dec 7, 2022
106e275
try another way of getting gocache dirs for windows
matloob Dec 7, 2022
c3b34ad
add output
matloob Dec 7, 2022
7a79e59
debug
matloob Dec 7, 2022
de594a0
debug2
matloob Dec 7, 2022
78a8e2e
debug 3
matloob Dec 7, 2022
2b05009
debug 4
matloob Dec 7, 2022
0d37f96
debug 5
matloob Dec 7, 2022
f0e29ba
debug 6
matloob Dec 7, 2022
3a35f5b
only compile stdlib .a files for Go 1.20+
matloob Dec 13, 2022
f757ef4
set version to 1.20rc1 for CI testing purposes
matloob Dec 13, 2022
24e601f
fix libs attribute of Go sdk to allow zero libs files
matloob Dec 13, 2022
b252e0e
fix coverage test
matloob Dec 13, 2022
3b8dab0
get only digits of the part before the next dot
matloob Dec 13, 2022
490ec4b
allow empty
matloob Dec 13, 2022
0d3250c
Merge branch 'master' of github.com:matloob/rules_go into go
matloob Dec 13, 2022
25e52fd
set GOEXPERIMENT=nocoverageredesign
matloob Dec 13, 2022
06fd767
conditionally turn off goexperiment based on versioun
matloob Dec 13, 2022
1b41059
rename variable
matloob Dec 13, 2022
1c8389c
fix flag
matloob Dec 13, 2022
bb7eed4
add lcov fix
matloob Dec 13, 2022
6f3008a
address comments, and remove one config of builder
matloob Dec 14, 2022
06ee92d
decide to compile .a files based on whether they exist
matloob Dec 14, 2022
b3dfe4b
Merge branch 'master' of https://github.com/bazelbuild/rules_go into go
matloob Dec 14, 2022
de75424
Merge branch 'master' of https://github.com/bazelbuild/rules_go into go
matloob Dec 15, 2022
80235ea
fix add call
matloob Dec 15, 2022
929b55c
add nocoverageredesign to experiments earlier
matloob Dec 15, 2022
87f47ef
another small fix
matloob Dec 15, 2022
c12a10b
fix double
matloob Dec 15, 2022
108915e
Update go/private/sdk.bzl
matloob Dec 16, 2022
bc8eb25
add a simple test doing a build on 1.20rc1
matloob Dec 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe

go_rules_dependencies()

go_register_toolchains(
version = "1.19.4",
)
go_register_toolchains(version = "1.19.4")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is back to 1.19.4. Given that 1.20 isn't out yet, maybe we should test it in go_bazel_test instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a simple test doing a build in 1.20.


http_archive(
name = "com_google_protobuf",
Expand Down
10 changes: 9 additions & 1 deletion go/private/BUILD.sdk.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
load("@{rules_go_repo_name}//go/private/rules:binary.bzl", "go_tool_binary")
load("@{rules_go_repo_name}//go/private/rules:sdk.bzl", "package_list")
load("@{rules_go_repo_name}//go/private/rules:transition.bzl", "non_go_reset_target")
load("@{rules_go_repo_name}//go/private:go_toolchain.bzl", "declare_go_toolchains")
load("@{rules_go_repo_name}//go:def.bzl", "go_sdk")

Expand All @@ -10,6 +11,7 @@ filegroup(
srcs = glob(
["pkg/{goos}_{goarch}/**/*.a"],
exclude = ["pkg/{goos}_{goarch}/**/cmd/**"],
allow_empty = True,
),
)

Expand Down Expand Up @@ -43,6 +45,7 @@ go_sdk(
root_file = "ROOT",
experiments = {experiments},
tools = [":tools"],
version = "{version}",
)

go_tool_binary(
Expand All @@ -51,6 +54,11 @@ go_tool_binary(
sdk = ":go_sdk",
)

non_go_reset_target(
name = "builder_reset",
dep = ":builder"
)

# TODO(jayconrod): Gazelle depends on this file directly. This dependency
# should be broken, and this rule should be folded into go_sdk.
package_list(
Expand All @@ -61,7 +69,7 @@ package_list(
)

declare_go_toolchains(
builder = ":builder",
builder = ":builder_reset",
host_goos = "{goos}",
sdk = ":go_sdk",
)
Expand Down
3 changes: 2 additions & 1 deletion go/private/actions/stdlib.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def _stdlib_library_to_source(go, attr, source, merge):
source["stdlib"] = _build_stdlib(go)

def _should_use_sdk_stdlib(go):
return (go.mode.goos == go.sdk.goos and
return (go.sdk.libs and # go.sdk.libs is non-empty if sdk ships with precompiled .a files
go.mode.goos == go.sdk.goos and
go.mode.goarch == go.sdk.goarch and
not go.mode.race and # TODO(jayconrod): use precompiled race
not go.mode.msan and
Expand Down
1 change: 1 addition & 0 deletions go/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ GoSDK = provider(
"tools": ("List of executable files in the SDK built for " +
"the execution platform, excluding the go binary file"),
"go": "The go binary file",
"version": "The Go SDK version",
},
)

Expand Down
43 changes: 16 additions & 27 deletions go/private/rules/binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,15 @@ def _go_tool_binary_impl(ctx):
if sdk.goos == "windows":
name += ".exe"

cout = ctx.actions.declare_file(name + ".a")
out = ctx.actions.declare_file(name)
if sdk.goos == "windows":
cmd = "@echo off\n {go} tool compile -o {cout} -trimpath=%cd% {srcs}".format(
gopath = ctx.actions.declare_directory("gopath")
gocache = ctx.actions.declare_directory("gocache")
cmd = "@echo off\nset GOCACHE=%cd%\\{gocache}\nset GOPATH=%cd%\\{gopath}\n{go} build -o {out} -trimpath {srcs}".format(
gopath = gopath.path,
gocache = gocache.path,
go = sdk.go.path.replace("/", "\\"),
cout = cout.path,
out = out.path,
srcs = " ".join([f.path for f in ctx.files.srcs]),
)
bat = ctx.actions.declare_file(name + ".bat")
Expand All @@ -429,39 +433,24 @@ def _go_tool_binary_impl(ctx):
)
ctx.actions.run(
executable = bat,
inputs = sdk.libs + sdk.headers + sdk.tools + ctx.files.srcs + [sdk.go],
outputs = [cout],
env = {"GOROOT": sdk.root_file.dirname}, # NOTE(#2005): avoid realpath in sandbox
mnemonic = "GoToolchainBinaryCompile",
inputs = sdk.headers + sdk.tools + sdk.srcs + ctx.files.srcs + [sdk.go],
outputs = [out, gopath, gocache],
mnemonic = "GoToolchainBinaryBuild",
)
else:
cmd = "{go} tool compile -o {cout} -trimpath=$PWD {srcs}".format(
# Note: GOPATH is needed for Go 1.16.
cmd = "GOCACHE=$(mktemp -d) GOPATH=$(mktemp -d) {go} build -o {out} -trimpath {srcs}".format(
go = sdk.go.path,
cout = cout.path,
out = out.path,
srcs = " ".join([f.path for f in ctx.files.srcs]),
)
ctx.actions.run_shell(
command = cmd,
inputs = sdk.libs + sdk.headers + sdk.tools + ctx.files.srcs + [sdk.go],
outputs = [cout],
env = {"GOROOT": sdk.root_file.dirname}, # NOTE(#2005): avoid realpath in sandbox
mnemonic = "GoToolchainBinaryCompile",
inputs = sdk.headers + sdk.tools + sdk.srcs + sdk.libs + ctx.files.srcs + [sdk.go],
outputs = [out],
mnemonic = "GoToolchainBinaryBuild",
)

out = ctx.actions.declare_file(name)
largs = ctx.actions.args()
largs.add_all(["tool", "link"])
largs.add("-o", out)
largs.add(cout)
ctx.actions.run(
executable = sdk.go,
arguments = [largs],
inputs = sdk.libs + sdk.headers + sdk.tools + [cout],
outputs = [out],
env = {"GOROOT_FINAL": "GOROOT"}, # Suppress go root paths to keep the output reproducible.
mnemonic = "GoToolchainBinary",
)

return [DefaultInfo(
files = depset([out]),
executable = out,
Expand Down
9 changes: 8 additions & 1 deletion go/private/rules/sdk.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def _go_sdk_impl(ctx):
srcs = ctx.files.srcs,
tools = ctx.files.tools,
go = ctx.executable.go,
version = ctx.attr.version,
)]

go_sdk = rule(
Expand Down Expand Up @@ -61,7 +62,10 @@ go_sdk = rule(
"standard library that may be imported."),
),
"libs": attr.label_list(
allow_files = [".a"],
# allow_files is not set to [".a"] because that wouldn't allow
# for zero files to be present, as is the case in Go 1.20+.
# See also https://github.com/bazelbuild/bazel/issues/7516
allow_files = True,
doc = ("Pre-compiled .a files for the standard library, " +
"built for the execution platform"),
),
Expand All @@ -87,6 +91,9 @@ go_sdk = rule(
cfg = "exec",
doc = "The go binary",
),
"version": attr.string(
doc = "The version of the Go SDK.",
),
},
doc = ("Collects information about a Go SDK. The SDK must have a normal " +
"GOROOT directory structure."),
Expand Down
8 changes: 8 additions & 0 deletions go/private/rules/stdlib.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ load(
"CgoContextInfo",
"GoConfigInfo",
)
load(
"//go/private/rules:transition.bzl",
"go_stdlib_transition",
)

def _stdlib_impl(ctx):
go = go_context(ctx)
Expand All @@ -33,12 +37,16 @@ def _stdlib_impl(ctx):

stdlib = rule(
implementation = _stdlib_impl,
cfg = go_stdlib_transition,
attrs = {
"cgo_context_data": attr.label(providers = [CgoContextInfo]),
"_go_config": attr.label(
default = "//:go_config",
providers = [GoConfigInfo],
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
doc = """stdlib builds the standard library for the target configuration
or uses the precompiled standard library from the SDK if it is suitable.""",
Expand Down
29 changes: 29 additions & 0 deletions go/private/rules/transition.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ go_transition = transition(
)

_common_reset_transition_dict = dict({
"@io_bazel_rules_go//go/private:request_nogo": False,
"@io_bazel_rules_go//go/config:static": False,
"@io_bazel_rules_go//go/config:msan": False,
"@io_bazel_rules_go//go/config:race": False,
Expand All @@ -219,6 +220,13 @@ _reset_transition_dict = dict(_common_reset_transition_dict, **{

_reset_transition_keys = sorted([filter_transition_label(label) for label in _reset_transition_dict.keys()])

_stdlib_keep_keys = sorted([
"@io_bazel_rules_go//go/config:msan",
"@io_bazel_rules_go//go/config:race",
"@io_bazel_rules_go//go/config:pure",
"@io_bazel_rules_go//go/config:linkmode",
])

def _go_tool_transition_impl(settings, attr):
"""Sets most Go settings to default values (use for external Go tools).

Expand Down Expand Up @@ -266,6 +274,27 @@ non_go_tool_transition = transition(
outputs = _reset_transition_keys,
)

def _go_stdlib_transition_impl(settings, attr):
"""Sets all Go settings to their default values, except for those affecting the Go SDK.

This transition is similar to _non_go_tool_transition except that it keeps the
parts of the configuration that determine how to build the standard library.
It's used to consolidate the configurations used to build the standard library to limit
the number built.
"""
settings = dict(settings)
for label, value in _reset_transition_dict.items():
if label not in _stdlib_keep_keys:
settings[filter_transition_label(label)] = value
settings[filter_transition_label("@io_bazel_rules_go//go/private:bootstrap_nogo")] = False
return settings

go_stdlib_transition = transition(
implementation = _go_stdlib_transition_impl,
inputs = _reset_transition_keys,
outputs = _reset_transition_keys,
)

def _go_reset_target_impl(ctx):
t = ctx.attr.dep[0] # [0] seems to be necessary with the transition
providers = [t[p] for p in [GoLibrary, GoSource, GoArchive] if p in t]
Expand Down
9 changes: 9 additions & 0 deletions go/private/sdk.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,14 @@ def _sdk_build_file(ctx, platform, version, experiments):
ctx.file("ROOT")
goos, _, goarch = platform.partition("_")

pv = _parse_version(version)
if pv != None and pv[1] >= 20:
# Turn off coverageredesign GOEXPERIMENT on 1.20+
# until rules_go is updated to work with the
# coverage redesign.
if not "nocoverageredesign" in experiments and not "coverageredesign" in experiments:
experiments = experiments + ["nocoverageredesign"]

ctx.template(
"BUILD.bazel",
Label("//go/private:BUILD.sdk.bazel"),
Expand All @@ -359,6 +367,7 @@ def _sdk_build_file(ctx, platform, version, experiments):
"{goarch}": goarch,
"{exe}": ".exe" if goos == "windows" else "",
"{rules_go_repo_name}": "io_bazel_rules_go",
"{version}": version,
"{experiments}": repr(experiments),
},
)
Expand Down
1 change: 1 addition & 0 deletions go/tools/builders/stdlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ You may need to use the flags --cpu=x64_windows --compiler=mingw-gcc.`)
}
}
os.Setenv("CGO_LDFLAGS_ALLOW", b.String())
os.Setenv("GODEBUG", "installgoroot=all")

if len(experiments) > 0 {
os.Setenv("GOEXPERIMENT", strings.Join(experiments, ","))
Expand Down
6 changes: 6 additions & 0 deletions tests/core/build_stdlib/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")

go_bazel_test(
name = "build_stdlib_test",
srcs = ["build_stdlib_test.go"],
)
11 changes: 11 additions & 0 deletions tests/core/build_stdlib/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Building with standard libraries with missing .a files
===========

Tests to ensure that building with Go 1.20 and later versions of Go, which no longer
include precompiled standard library .a files, continues to work

build_stdlib_test
--------------

Test that a simple binary depending on a simple library can build when the WORKSPACE's
go version is set to 1.20rc1.
97 changes: 97 additions & 0 deletions tests/core/build_stdlib/build_stdlib_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2022 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package build_stdlib_test

import (
"bytes"
"os"
"testing"

"github.com/bazelbuild/rules_go/go/tools/bazel_testing"
)

func TestMain(m *testing.M) {
bazel_testing.TestMain(m, bazel_testing.Args{
Main: `
-- BUILD.bazel --
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_binary(
name = "program",
srcs = ["main.go"],
deps = [":library"],
visibility = ["//visibility:public"],
)

go_library(
name = "library",
srcs = ["library.go"],
importpath = "example.com/library"
)
-- main.go --
package main

import "example.com/library"

func main() {
library.F()
}
-- library.go --
package library

func F() {}
`,
})
}

const origWrapSDK = `go_wrap_sdk(
name = "go_sdk",
root_file = "@local_go_sdk//:ROOT",
)

go_register_toolchains()`

const toolchain120 = `go_register_toolchains(version = "1.20rc1")`

func TestBoringcryptoExperimentPresent(t *testing.T) {
mustReplaceInFile(t, "WORKSPACE", origWrapSDK, toolchain120)
defer mustReplaceInFile(t, "WORKSPACE", toolchain120, origWrapSDK)

cmd := bazel_testing.BazelCmd("build", "//:program")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
if err := cmd.Run(); err != nil {
t.Fatal("failed to run bazel build: ", err)
}

}

func mustReplaceInFile(t *testing.T, path, old, new string) {
t.Helper()
if old == new {
return
}
data, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if !bytes.Contains(data, []byte(old)) {
t.Fatalf("bytes to replace %q not found in file %q with contents, %q", old, path, data)
}
data = bytes.ReplaceAll(data, []byte(old), []byte(new))
if err := os.WriteFile(path, data, 0666); err != nil {
t.Fatal(err)
}
}