Skip to content

Commit

Permalink
Keep build tags that affect the stdlib build
Browse files Browse the repository at this point in the history
Since 8d309d5, all `gotags` were cleared from the configuration when
building the standard library. This is not correct as some tags, such
as `timetzdata`, do affect the standard library build.

This commit adds a tool that scrapes the list of build tags relevant
for the standard library from Go SDK sources and keeps those tags that
are relevant for Go 1.18-1.20.
  • Loading branch information
fmeum committed Mar 24, 2023
1 parent ea3cc4f commit ee06970
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 0 deletions.
46 changes: 46 additions & 0 deletions go/private/rules/transition.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ _stdlib_keep_keys = sorted([
"//go/config:race",
"//go/config:pure",
"//go/config:linkmode",
"//go/config:tags",
])

def _go_tool_transition_impl(settings, _attr):
Expand Down Expand Up @@ -268,6 +269,7 @@ def _go_stdlib_transition_impl(settings, _attr):
for label, value in _reset_transition_dict.items():
if label not in _stdlib_keep_keys:
settings[label] = value
settings["//go/config:tags"] = [t for t in settings["//go/config:tags"] if t in _TAG_AFFECTS_STDLIB]
settings["//go/private:bootstrap_nogo"] = False
return settings

Expand Down Expand Up @@ -433,3 +435,47 @@ go_cross_transition = transition(
inputs = TRANSITIONED_GO_CROSS_SETTING_KEYS,
outputs = TRANSITIONED_GO_CROSS_SETTING_KEYS,
)

# A list of Go build tags that potentially affect the build of the standard
# library.
#
# This should be updated to contain the union of all tags relevant for all
# versions of Go that are still relevant.
#
# Currently supported versions: 1.18, 1.19, 1.20
#
# To regenerate, run and paste the output of
# bazel run //go/tools/internal/stdlib_tags:stdlib_tags -- path/to/go_sdk_1/src ...
_TAG_AFFECTS_STDLIB = {
"alpha": None,
"appengine": None,
"asan": None,
"boringcrypto": None,
"cmd_go_bootstrap": None,
"compiler_bootstrap": None,
"debuglog": None,
"faketime": None,
"gc": None,
"gccgo": None,
"gen": None,
"generate": None,
"gofuzz": None,
"ignore": None,
"libfuzzer": None,
"m68k": None,
"math_big_pure_go": None,
"msan": None,
"netcgo": None,
"netgo": None,
"nethttpomithttp2": None,
"nios2": None,
"noopt": None,
"osusergo": None,
"purego": None,
"race": None,
"sh": None,
"shbe": None,
"tablegen": None,
"testgo": None,
"timetzdata": None,
}
14 changes: 14 additions & 0 deletions go/tools/internal/stdlib_tags/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
name = "stdlib_tags_lib",
srcs = ["stdlib_tags.go"],
importpath = "github.com/bazelbuild/rules_go/go/tools/internal/stdlib_tags",
visibility = ["//visibility:private"],
)

go_binary(
name = "stdlib_tags",
embed = [":stdlib_tags_lib"],
visibility = ["//go/tools:__subpackages__"],
)
174 changes: 174 additions & 0 deletions go/tools/internal/stdlib_tags/stdlib_tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package main

import (
"bufio"
"fmt"
"go/build/constraint"
"log"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
)

var goVersionRegex = regexp.MustCompile(`^go1.(\d+)$`)

// Used to update the list of tags affecting the standard library kept in
// transitions.bzl.
func main() {
if len(os.Args) < 2 {
log.Fatal("usage: stdlib_tags <go SDK src directory>...")
}

filteredTags, err := extractBuildTags(os.Args[1:]...)
if err != nil {
log.Fatal(err.Error())
}

fmt.Printf("_TAG_AFFECTS_STDLIB = {\n")
for _, tag := range filteredTags {
fmt.Printf(" %q: None,\n", tag)
}
fmt.Printf("}\n")
}

func extractBuildTags(sdkPaths ...string) ([]string, error) {
tags := make(map[string]struct{})
for _, dir := range sdkPaths {
err := filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
if d.IsDir() {
if d.Name() == "testdata" {
return filepath.SkipDir
}
return nil
}
if filepath.Ext(path) != ".go" {
return nil
}
if strings.HasSuffix(filepath.Base(path), "_test.go") {
return nil
}
return walkFile(path, tags)
})
if err != nil {
return nil, fmt.Errorf("%s: %w", dir, err)
}
}

filteredTags := make([]string, 0, len(tags))
for tag := range tags {
if !shouldExclude(tag) {
filteredTags = append(filteredTags, tag)
}
}
sort.Strings(filteredTags)

return filteredTags, nil
}

func shouldExclude(tag string) bool {
// Set via CGO_ENABLED
return tag == "cgo" ||
// Set via GOARCH and GOOS
knownOS[tag] || knownArch[tag] || tag == "unix" ||
// Set via GOEXPERIMENT and GOAMD64
strings.HasPrefix(tag, "goexperiment.") || strings.HasPrefix(tag, "amd64.") ||
// Set implicitly
goVersionRegex.MatchString(tag)
}

func walkFile(path string, tags map[string]struct{}) error {
file, err := os.Open(path)
if err != nil {
return err
}

scanner := bufio.NewScanner(file)
// The Go SDK contains some very long lines in vendored files (minified JS).
scanner.Buffer(make([]byte, 0, 128*1024), 1024*1024)
for scanner.Scan() {
line := scanner.Text()
if !isConstraint(line) {
continue
}
c, err := constraint.Parse(line)
if err != nil {
continue
}
walkConstraint(c, tags)
}

if err = scanner.Err(); err != nil {
return fmt.Errorf("%s: %w", path, err)
}
return nil
}

func walkConstraint(c constraint.Expr, tags map[string]struct{}) {
switch c.(type) {
case *constraint.AndExpr:
walkConstraint(c.(*constraint.AndExpr).X, tags)
walkConstraint(c.(*constraint.AndExpr).Y, tags)
case *constraint.OrExpr:
walkConstraint(c.(*constraint.OrExpr).X, tags)
walkConstraint(c.(*constraint.OrExpr).Y, tags)
case *constraint.NotExpr:
walkConstraint(c.(*constraint.NotExpr).X, tags)
case *constraint.TagExpr:
tags[c.(*constraint.TagExpr).Tag] = struct{}{}
}
}

func isConstraint(line string) bool {
return constraint.IsPlusBuild(line) || constraint.IsGoBuild(line)
}

// Taken from
// https://github.com/golang/go/blob/3d5391ed87d813110e10b954c62bf7ed578b591f/src/go/build/syslist.go
var knownOS = map[string]bool{
"aix": true,
"android": true,
"darwin": true,
"dragonfly": true,
"freebsd": true,
"hurd": true,
"illumos": true,
"ios": true,
"js": true,
"linux": true,
"nacl": true,
"netbsd": true,
"openbsd": true,
"plan9": true,
"solaris": true,
"windows": true,
"zos": true,
}

var knownArch = map[string]bool{
"386": true,
"amd64": true,
"amd64p32": true,
"arm": true,
"armbe": true,
"arm64": true,
"arm64be": true,
"loong64": true,
"mips": true,
"mipsle": true,
"mips64": true,
"mips64le": true,
"mips64p32": true,
"mips64p32le": true,
"ppc": true,
"ppc64": true,
"ppc64le": true,
"riscv": true,
"riscv64": true,
"s390": true,
"s390x": true,
"sparc": true,
"sparc64": true,
"wasm": true,
}

0 comments on commit ee06970

Please sign in to comment.