From 8f648765a55d1c881d440e5d2c038835a592a169 Mon Sep 17 00:00:00 2001 From: Son Luong Ngoc Date: Mon, 20 Apr 2026 16:18:16 +0700 Subject: [PATCH 1/2] deps: upgrade gazelle to 0.47.0 The dep-only buildinfo work depends on go_deps repos exposing Gazelle-generated package metadata. With the existing 0.36.0 pin, real go_deps workspaces still produced binaries with empty runtime/debug.ReadBuildInfo().Deps because that metadata was never emitted. Upgrade the main workspace and the BCR test module to Gazelle 0.47.0 and refresh MODULE.bazel.lock so the metadata is available in the supported Bzlmod + go.mod flow. Stay below Gazelle 0.48.0 because its go.work file requires Go 1.24.12, while rules_go CI still runs Go 1.24.0 with GOTOOLCHAIN=local on Linux. --- MODULE.bazel | 2 +- MODULE.bazel.lock | 6 ++++-- tests/bcr/MODULE.bazel | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 38438955ad..9e9fabc3de 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -32,7 +32,7 @@ use_repo( register_toolchains("@go_toolchains//:all") -bazel_dep(name = "gazelle", version = "0.36.0") +bazel_dep(name = "gazelle", version = "0.47.0") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//:go.mod") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index baae45c732..bd694623ad 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -43,8 +43,8 @@ "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", - "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", - "https://bcr.bazel.build/modules/gazelle/0.36.0/source.json": "0823f097b127e0201ae55d85647c94095edfe27db0431a7ae880dcab08dfaa04", + "https://bcr.bazel.build/modules/gazelle/0.47.0/MODULE.bazel": "b61bb007c4efad134aa30ee7f4a8e2a39b22aa5685f005edaa022fbd1de43ebc", + "https://bcr.bazel.build/modules/gazelle/0.47.0/source.json": "aeb2e5df14b7fb298625d75d08b9c65bdb0b56014c5eb89da9e5dd0572280ae6", "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", "https://bcr.bazel.build/modules/googleapis-rules-registry/1.0.0/MODULE.bazel": "97c6a4d413b373d4cc97065da3de1b2166e22cbbb5f4cc9f05760bfa83619e24", "https://bcr.bazel.build/modules/googleapis-rules-registry/1.0.0/source.json": "cf611c836a60e98e2e2ab2de8004f119e9f06878dcf4ea2d95a437b1b7a89fe9", @@ -57,6 +57,8 @@ "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/MODULE.bazel": "ef4f9439e3270fdd6b9fd4dbc3d2f29d13888e44c529a1b243f7a31dfbc2e8e4", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/source.json": "2326db2f6592578177751c3e1f74786b79382cd6008834c9d01ec865b9126a85", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", diff --git a/tests/bcr/MODULE.bazel b/tests/bcr/MODULE.bazel index 2f0dc4a1b9..1453d5d0f8 100644 --- a/tests/bcr/MODULE.bazel +++ b/tests/bcr/MODULE.bazel @@ -18,7 +18,7 @@ local_path_override( path = "../..", ) -bazel_dep(name = "gazelle", version = "0.36.0") +bazel_dep(name = "gazelle", version = "0.47.0") bazel_dep(name = "platforms", version = "1.0.0") bazel_dep(name = "protobuf", version = "29.0-rc2.bcr.1") bazel_dep(name = "rules_cc", version = "0.2.16") From 01e1e77d44bd2a837be0e104f637d657a4e35029 Mon Sep 17 00:00:00 2001 From: Son Luong Ngoc Date: Mon, 20 Apr 2026 16:18:31 +0700 Subject: [PATCH 2/2] link: add external deps to Go build info The new dep-only modinfo path under-reported external dependencies in debug.ReadBuildInfo().Deps because commit-pinned and local override repos had PackageInfo.package_name but an empty package_version, so rules_go dropped them before link time even though their packages contributed to the binary. Populate runtime/debug.ReadBuildInfo().Deps for rules_go binaries by threading external module metadata from analysis into archive and link actions and emitting dep-only modinfo for supported build modes. Match cmd/go's build-info behavior here. In go1.26.2, (1) shows debugModFromModinfo recording missing versions as "(devel)" instead of omitting them, and (2) shows the modinfo parser accepting module records without requiring a non-empty version. Keep PackageInfo entries that have a package_name but an empty package_version, normalize that case to "(devel)", and keep adding a leading "v" for tagged versions. Bazel can surface repo metadata through either package_metadata or applicable_licenses depending on the rule surface, so read both spellings and wire in rules_license for PackageInfo lookup. Extend the builder, starlark, go_bazel_test, and reproducibility coverage, including a versionless dependency case. The new rules_license load also changes the Starlark dependency graph seen by stardoc, so patch rules_license to export the loaded .bzl files to the docs extractor and add explicit doc-generation deps for the core and extras docs targets. That keeps CI doc extraction working after the new metadata lookup is wired in. (1) https://go.dev/src/cmd/go/internal/load/pkg.go#L2335-L2348 (2) https://go.dev/src/runtime/debug/mod.go#L177-L190 --- MODULE.bazel | 6 + docs/BUILD.bazel | 8 + docs/doc_helpers.bzl | 8 +- go/private/actions/archive.bzl | 4 + go/private/actions/link.bzl | 10 +- go/private/context.bzl | 42 +++ go/private/repositories.bzl | 11 + go/private/rules/test.bzl | 4 + go/tools/builders/BUILD.bazel | 10 + go/tools/builders/buildinfo.go | 129 +++++++ go/tools/builders/buildinfo_test.go | 137 +++++++ go/tools/builders/importcfg.go | 42 ++- go/tools/builders/link.go | 18 +- tests/core/go_binary/BUILD.bazel | 5 + tests/core/go_binary/buildinfo_test.go | 341 ++++++++++++++++++ tests/core/starlark/BUILD.bazel | 3 + tests/core/starlark/module_info_tests.bzl | 127 +++++++ .../reproducibility/reproducibility_test.go | 58 ++- third_party/rules_license-stardoc.patch | 22 ++ 19 files changed, 969 insertions(+), 16 deletions(-) create mode 100644 go/tools/builders/buildinfo.go create mode 100644 go/tools/builders/buildinfo_test.go create mode 100644 tests/core/go_binary/buildinfo_test.go create mode 100644 tests/core/starlark/module_info_tests.bzl create mode 100644 third_party/rules_license-stardoc.patch diff --git a/MODULE.bazel b/MODULE.bazel index 9e9fabc3de..b447c1994d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -13,6 +13,12 @@ bazel_dep(name = "rules_proto", version = "7.0.2") bazel_dep(name = "protobuf", version = "29.0", repo_name = "com_google_protobuf") bazel_dep(name = "rules_shell", version = "0.3.0") bazel_dep(name = "rules_cc", version = "0.1.5") +bazel_dep(name = "rules_license", version = "1.0.0") +single_version_override( + module_name = "rules_license", + patch_strip = 1, + patches = ["//third_party:rules_license-stardoc.patch"], +) go_sdk = use_extension("//go:extensions.bzl", "go_sdk") diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index d4742ad53f..4e05e96d53 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -3,11 +3,19 @@ load("//docs:doc_helpers.bzl", "stardoc_with_diff_test", "update_docs") # For each doc file, generate MD from bzl_library, then perform diff test stardoc_with_diff_test( bzl_library_target = "//docs/go/extras:extras", + extra_deps = [ + "@rules_license//rules:providers.bzl", + "@rules_license//rules_gathering:gathering_providers.bzl", + ], out_label = "//docs/go/extras:extras.md", ) stardoc_with_diff_test( bzl_library_target = "//docs/go/core:rules", + extra_deps = [ + "@rules_license//rules:providers.bzl", + "@rules_license//rules_gathering:gathering_providers.bzl", + ], out_label = "//docs/go/core:rules.md", ) diff --git a/docs/doc_helpers.bzl b/docs/doc_helpers.bzl index 058827a96d..15473a3265 100644 --- a/docs/doc_helpers.bzl +++ b/docs/doc_helpers.bzl @@ -14,12 +14,13 @@ load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@bazel_skylib//rules:write_file.bzl", "write_file") -load("@stardoc//stardoc:stardoc.bzl", "stardoc") load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("@stardoc//stardoc:stardoc.bzl", "stardoc") def stardoc_with_diff_test( bzl_library_target, - out_label): + out_label, + extra_deps = []): """Creates a stardoc target coupled with a diff_test for a given bzl_library. This is helpful for minimizing boilerplate when lots of stardoc targets are to be generated. @@ -27,6 +28,7 @@ def stardoc_with_diff_test( Args: bzl_library_target: the label of the bzl_library target to generate documentation for out_label: the label of the output MD file + extra_deps: additional Starlark files or bzl_library targets required for doc extraction """ out_file = out_label.replace("//", "").replace(":", "/") @@ -36,7 +38,7 @@ def stardoc_with_diff_test( name = out_file.replace("/", "_").replace(".md", "-docgen"), out = out_file.replace(".md", "-docgen.md"), input = bzl_library_target + ".bzl", - deps = [bzl_library_target], + deps = [bzl_library_target] + extra_deps, ) # Ensure that the generated MD has been updated in the local source tree diff --git a/go/private/actions/archive.bzl b/go/private/actions/archive.bzl index fa4daad51e..dd53cefa96 100644 --- a/go/private/actions/archive.bzl +++ b/go/private/actions/archive.bzl @@ -193,6 +193,8 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d _copts = tuple(source.copts), _cxxopts = tuple(source.cxxopts), _clinkopts = tuple(source.clinkopts), + _module_path = getattr(source, "_module_path", ""), + _module_version = getattr(source, "_module_version", ""), # Information on dependencies _dep_labels = tuple([d.data.label for d in direct]), @@ -227,4 +229,6 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d cgo_exports = cgo_exports, runfiles = runfiles, _headers = headers, + _module_path = getattr(data, "_module_path", ""), + _module_version = getattr(data, "_module_version", ""), ) diff --git a/go/private/actions/link.bzl b/go/private/actions/link.bzl index 7d8ff5f0f6..fc88eed241 100644 --- a/go/private/actions/link.bzl +++ b/go/private/actions/link.bzl @@ -35,7 +35,14 @@ load( ) def _format_archive(d): - return "{}={}={}".format(d.label, d.importmap, d.file.path) + return "{}={}={}={}={}={}".format( + d.label, + d.importpath, + d.importmap, + d.file.path, + getattr(d, "_module_path", ""), + getattr(d, "_module_version", ""), + ) def emit_link( go, @@ -125,6 +132,7 @@ def emit_link( arcs = depset(test_archives, transitive = [d.transitive for d in archive.direct]) builder_args.add_all(arcs, before_each = "-arc", map_each = _format_archive) + builder_args.add("-go_version", go.sdk.version) builder_args.add("-package_list", go.sdk.package_list) # Build a list of rpaths for dynamic libraries we need to find. diff --git a/go/private/context.bzl b/go/private/context.bzl index 0bd1734ea9..12147614a5 100644 --- a/go/private/context.bzl +++ b/go/private/context.bzl @@ -40,6 +40,7 @@ load( NOGO_INCLUDES = "INCLUDES", ) load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_license//rules:providers.bzl", "PackageInfo") load( "//go/platform:apple.bzl", "apple_ensure_options", @@ -240,6 +241,35 @@ def _tool_args(go): args.use_param_file("-param=%s") return args +def normalize_module_version(version): + if not version: + return "(devel)" + if version == "(devel)": + return version + if version.startswith("v"): + return version + return "v" + version + +def module_info_from_metadata(label, package_metadata = (), applicable_licenses = ()): + if not label.repo_name and not label.workspace_root: + return struct(path = "", version = "") + + # Bazel may surface repo-level metadata through either spelling depending on + # the version and rule surface, so probe both. + for metadata_group in (package_metadata, applicable_licenses): + for metadata in metadata_group: + if PackageInfo not in metadata: + continue + info = metadata[PackageInfo] + if not info.package_name: + continue + return struct( + path = info.package_name, + version = normalize_module_version(info.package_version), + ) + + return struct(path = "", version = "") + def _merge_embed(source, embed): s = get_source(embed) source["srcs"] = s.srcs + source["srcs"] @@ -249,6 +279,10 @@ def _merge_embed(source, embed): source["x_defs"].update(s.x_defs) source["gc_goopts"] = source["gc_goopts"] + s.gc_goopts source["runfiles"] = source["runfiles"].merge(s.runfiles) + module_path = getattr(s, "_module_path", "") + if not source["_module_path"] and module_path: + source["_module_path"] = module_path + source["_module_version"] = getattr(s, "_module_version", "") if s.cgo: if source["cgo"]: @@ -354,6 +388,12 @@ def new_go_info( if deps == None: deps = [get_archive(dep) for dep in getattr(attr, "deps", [])] + module_info = module_info_from_metadata( + go.label, + getattr(attr, "package_metadata", ()), + getattr(attr, "applicable_licenses", ()), + ) + go_info = { "name": go.label.name if not name else name, "label": go.label, @@ -378,6 +418,8 @@ def new_go_info( "cxxopts": _expand_opts(go, "cxxopts", getattr(attr, "cxxopts", [])), "clinkopts": _expand_opts(go, "clinkopts", getattr(attr, "clinkopts", [])), "pgoprofile": getattr(attr, "pgoprofile", None), + "_module_path": module_info.path, + "_module_version": module_info.version, } for e in getattr(attr, "embed", []): diff --git a/go/private/repositories.bzl b/go/private/repositories.bzl index 94adead5c1..2b81eb5640 100644 --- a/go/private/repositories.bzl +++ b/go/private/repositories.bzl @@ -341,6 +341,17 @@ def go_rules_dependencies(force = False): url = "https://github.com/bazelbuild/rules_cc/releases/download/0.1.5/rules_cc-0.1.5.tar.gz", ) + # Required for reading Gazelle-generated PackageInfo metadata. + wrapper( + http_archive, + name = "rules_license", + sha256 = "26d4021f6898e23b82ef953078389dd49ac2b5618ac564ade4ef87cced147b38", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/1.0.0/rules_license-1.0.0.tar.gz", + "https://github.com/bazelbuild/rules_license/releases/download/1.0.0/rules_license-1.0.0.tar.gz", + ], + ) + def _go_host_compatible_sdk_label_impl(ctx): ctx.file("BUILD.bazel") ctx.file("defs.bzl", """HOST_COMPATIBLE_SDK = Label("@go_sdk//:ROOT")""") diff --git a/go/private/rules/test.bzl b/go/private/rules/test.bzl index 911a92496d..5c0d883600 100644 --- a/go/private/rules/test.bzl +++ b/go/private/rules/test.bzl @@ -727,6 +727,8 @@ def _recompile_external_deps(go, external_go_info, internal_archive, library_lab copts = list(arc_data._copts), cxxopts = list(arc_data._cxxopts), clinkopts = list(arc_data._clinkopts), + _module_path = getattr(arc_data, "_module_path", ""), + _module_version = getattr(arc_data, "_module_version", ""), ) # If this archive needs to be recompiled, use go.archive. @@ -747,6 +749,8 @@ def _recompile_external_deps(go, external_go_info, internal_archive, library_lab runfiles = go_info.runfiles, mode = go.mode, _headers = internal_archive._headers, + _module_path = getattr(arc_data, "_module_path", ""), + _module_version = getattr(arc_data, "_module_version", ""), ) label_to_archive[label] = archive diff --git a/go/tools/builders/BUILD.bazel b/go/tools/builders/BUILD.bazel index 9665e29bd3..3ebd29d5de 100644 --- a/go/tools/builders/BUILD.bazel +++ b/go/tools/builders/BUILD.bazel @@ -80,6 +80,15 @@ go_test( ], ) +go_test( + name = "buildinfo_test", + size = "small", + srcs = [ + "buildinfo.go", + "buildinfo_test.go", + ], +) + go_test( name = "nogo_version_test", size = "small", @@ -101,6 +110,7 @@ filegroup( "ar.go", "asm.go", "builder.go", + "buildinfo.go", "cc.go", "cgo2.go", "compilepkg.go", diff --git a/go/tools/builders/buildinfo.go b/go/tools/builders/buildinfo.go new file mode 100644 index 0000000000..034435a188 --- /dev/null +++ b/go/tools/builders/buildinfo.go @@ -0,0 +1,129 @@ +// Copyright 2026 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 main + +import ( + "runtime/debug" + "sort" + "strconv" + "strings" +) + +const ( + // Match cmd/go's modinfo framing markers: + // https://go.dev/src/cmd/go/internal/modload/build.go#L29-L30 + buildInfoStart = "\x30\x77\xaf\x0c\x92\x74\x08\x02\x41\xe1\xc1\x07\xe6\xd6\x18\xe6" + buildInfoEnd = "\xf9\x32\x43\x31\x86\x18\x20\x72\x00\x82\x42\x10\x41\x16\xd8\xf2" +) + +type moduleInfo struct { + path string + version string +} + +func buildInfoDeps(modules []moduleInfo) []*debug.Module { + seen := map[moduleInfo]struct{}{} + unique := make([]moduleInfo, 0, len(modules)) + for _, module := range modules { + if module.path == "" || module.version == "" { + continue + } + if _, ok := seen[module]; ok { + continue + } + seen[module] = struct{}{} + unique = append(unique, module) + } + + sort.Slice(unique, func(i, j int) bool { + if unique[i].path != unique[j].path { + return unique[i].path < unique[j].path + } + return unique[i].version < unique[j].version + }) + + deps := make([]*debug.Module, 0, len(unique)) + for _, module := range unique { + deps = append(deps, &debug.Module{ + Path: module.path, + Version: module.version, + }) + } + return deps +} + +func modInfoData(modules []moduleInfo) string { + deps := buildInfoDeps(modules) + if len(deps) == 0 { + return buildInfoStart + buildInfoEnd + } + + // debug.BuildInfo.String was added after Go 1.17. Emit the dep-only + // modinfo format directly so older SDK builders still compile. + var buf strings.Builder + for _, dep := range deps { + buf.WriteString("dep\t") + buf.WriteString(dep.Path) + buf.WriteByte('\t') + buf.WriteString(dep.Version) + buf.WriteString("\t\n") + } + return buildInfoStart + buf.String() + buildInfoEnd +} + +func shouldEmitBuildInfo(goVersion, buildmode string) bool { + switch buildmode { + case "c-archive", "c-shared", "plugin": + return false + default: + return supportsBuildInfo(goVersion) + } +} + +func supportsBuildInfo(goVersion string) bool { + if goVersion == "" { + return true + } + goVersion = strings.TrimPrefix(goVersion, "go") + parts := strings.SplitN(goVersion, ".", 3) + if len(parts) != 2 { + if len(parts) == 3 { + parts = parts[:2] + } else { + // Keep build info enabled for newer or non-standard version strings + // we don't recognize. + return true + } + } + minor := parts[1] + for i := 0; i < len(minor); i++ { + if minor[i] < '0' || minor[i] > '9' { + minor = minor[:i] + break + } + } + if minor == "" { + return true + } + major, err := strconv.Atoi(parts[0]) + if err != nil { + return true + } + minorVersion, err := strconv.Atoi(minor) + if err != nil { + return true + } + return major > 1 || (major == 1 && minorVersion >= 18) +} diff --git a/go/tools/builders/buildinfo_test.go b/go/tools/builders/buildinfo_test.go new file mode 100644 index 0000000000..fb192296cd --- /dev/null +++ b/go/tools/builders/buildinfo_test.go @@ -0,0 +1,137 @@ +// Copyright 2026 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 main + +import ( + "runtime/debug" + "slices" + "strings" + "testing" +) + +func parseModInfoData(t *testing.T, data string) *debug.BuildInfo { + t.Helper() + + info, found := strings.CutPrefix(data, buildInfoStart) + if !found { + t.Fatalf("modinfo missing start marker: %q", data) + } + info, found = strings.CutSuffix(info, buildInfoEnd) + if !found { + t.Fatalf("modinfo missing end marker: %q", data) + } + + parsed, err := debug.ParseBuildInfo(info) + if err != nil { + t.Fatalf("ParseBuildInfo(%q): %v", info, err) + } + return parsed +} + +func TestBuildInfoDepsSortAndDedup(t *testing.T) { + deps := buildInfoDeps([]moduleInfo{ + {path: "golang.org/x/text", version: "v0.15.0"}, + {path: "github.com/google/go-cmp", version: "v0.6.0"}, + {path: "golang.org/x/text", version: "v0.15.0"}, + {path: "", version: "v1.0.0"}, + {path: "example.com/missing/version", version: ""}, + }) + + got := make([]string, 0, len(deps)) + for _, dep := range deps { + got = append(got, dep.Path+"@"+dep.Version) + } + want := []string{ + "github.com/google/go-cmp@v0.6.0", + "golang.org/x/text@v0.15.0", + } + if !slices.Equal(got, want) { + t.Fatalf("got deps %v; want %v", got, want) + } +} + +func TestModInfoDataRoundTrip(t *testing.T) { + info := parseModInfoData(t, modInfoData([]moduleInfo{ + {path: "golang.org/x/sync", version: "v0.8.0"}, + {path: "github.com/google/go-cmp", version: "v0.6.0"}, + {path: "github.com/google/go-cmp", version: "v0.6.0"}, + })) + + if info.Path != "" { + t.Fatalf("got Path %q; want empty", info.Path) + } + if info.Main.Path != "" || info.Main.Version != "" { + t.Fatalf("got Main %+v; want empty", info.Main) + } + + got := make([]string, 0, len(info.Deps)) + for _, dep := range info.Deps { + got = append(got, dep.Path+"@"+dep.Version) + } + want := []string{ + "github.com/google/go-cmp@v0.6.0", + "golang.org/x/sync@v0.8.0", + } + if !slices.Equal(got, want) { + t.Fatalf("got deps %v; want %v", got, want) + } +} + +func TestModInfoDataWithoutDeps(t *testing.T) { + info := parseModInfoData(t, modInfoData(nil)) + if len(info.Deps) != 0 { + t.Fatalf("got %d deps; want 0", len(info.Deps)) + } +} + +func TestModInfoDataFormat(t *testing.T) { + got := modInfoData([]moduleInfo{ + {path: "github.com/google/go-cmp", version: "v0.6.0"}, + {path: "golang.org/x/sync", version: "v0.8.0"}, + }) + want := buildInfoStart + + "dep\tgithub.com/google/go-cmp\tv0.6.0\t\n" + + "dep\tgolang.org/x/sync\tv0.8.0\t\n" + + buildInfoEnd + if got != want { + t.Fatalf("got %q; want %q", got, want) + } +} + +func TestShouldEmitBuildInfo(t *testing.T) { + testCases := []struct { + name string + goVersion string + buildmode string + want bool + }{ + {name: "default version", goVersion: "", want: true}, + {name: "go117", goVersion: "1.17", want: false}, + {name: "go117_patch", goVersion: "1.17.1", want: false}, + {name: "go117_rc", goVersion: "1.17rc1", want: false}, + {name: "go118", goVersion: "1.18", want: true}, + {name: "go_prefix", goVersion: "go1.18.3", want: true}, + {name: "plugin", goVersion: "1.24.0", buildmode: "plugin", want: false}, + {name: "unknown", goVersion: "devel go1.26-abcdef", want: true}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if got := shouldEmitBuildInfo(tc.goVersion, tc.buildmode); got != tc.want { + t.Fatalf("shouldEmitBuildInfo(%q, %q) = %t; want %t", tc.goVersion, tc.buildmode, got, tc.want) + } + }) + } +} diff --git a/go/tools/builders/importcfg.go b/go/tools/builders/importcfg.go index c25763a02c..4eef8343ba 100644 --- a/go/tools/builders/importcfg.go +++ b/go/tools/builders/importcfg.go @@ -30,6 +30,7 @@ import ( type archive struct { label, importPath, packagePath, file string importPathAliases []string + modulePath, moduleVersion string } // checkImports verifies that each import in files refers to a @@ -154,7 +155,7 @@ func buildImportcfgFileForCompile(imports map[string]*archive, installSuffix, di return filename, nil } -func buildImportcfgFileForLink(archives []archive, stdPackageListPath, installSuffix, dir string) (string, error) { +func buildImportcfgFileForLink(archives []archive, stdPackageListPath, installSuffix, dir, modinfo string) (string, error) { buf := &bytes.Buffer{} goroot, ok := os.LookupEnv("GOROOT") if !ok { @@ -177,8 +178,15 @@ func buildImportcfgFileForLink(archives []archive, stdPackageListPath, installSu if err := scanner.Err(); err != nil { return "", err } + if modinfo != "" { + fmt.Fprintf(buf, "modinfo %q\n", modinfo) + } depsSeen := map[string]string{} for _, arc := range archives { + label := arc.label + if label == "" { + label = arc.importPath + } if prevLabel, ok := depsSeen[arc.packagePath]; ok { return "", fmt.Errorf(` package conflict error: %s: multiple copies of package passed to linker: @@ -187,13 +195,10 @@ package conflict error: %s: multiple copies of package passed to linker: Set "importmap" to different paths or use 'bazel cquery' to ensure only one package with this path is linked.`, arc.packagePath, - arc.importPath, + label, prevLabel) } - // TODO(zbarsky): The labels are empty, and `importPath` contains the label. - // The parsing is incorrect because arrchiveMultiFlag assuming the formatting from - // `compilepkg.bzl` but `_format_archive` in `link.bzl` formats differently. - depsSeen[arc.packagePath] = arc.importPath + depsSeen[arc.packagePath] = label fmt.Fprintf(buf, "packagefile %s=%s\n", arc.packagePath, arc.file) } f, err := ioutil.TempFile(dir, "importcfg") @@ -270,3 +275,28 @@ func (m *archiveMultiFlag) Set(v string) error { *m = append(*m, a) return nil } + +type linkArchiveMultiFlag []archive + +func (m *linkArchiveMultiFlag) String() string { + if m == nil || len(*m) == 0 { + return "" + } + return fmt.Sprint(*m) +} + +func (m *linkArchiveMultiFlag) Set(v string) error { + parts := strings.Split(v, "=") + if len(parts) != 6 { + return fmt.Errorf("badly formed -arc flag: %s", v) + } + *m = append(*m, archive{ + label: parts[0], + importPath: parts[1], + packagePath: parts[2], + file: abs(parts[3]), + modulePath: parts[4], + moduleVersion: parts[5], + }) + return nil +} diff --git a/go/tools/builders/link.go b/go/tools/builders/link.go index 11dc0abfe1..3445c6791e 100644 --- a/go/tools/builders/link.go +++ b/go/tools/builders/link.go @@ -39,13 +39,14 @@ func link(args []string) error { builderArgs, toolArgs := splitArgs(args) stamps := multiFlag{} xdefs := multiFlag{} - archives := archiveMultiFlag{} + archives := linkArchiveMultiFlag{} flags := flag.NewFlagSet("link", flag.ExitOnError) goenv := envFlags(flags) + goVersion := flags.String("go_version", "", "The SDK Go version from rules_go, without the leading 'go' prefix (for example 1.24.3).") main := flags.String("main", "", "Path to the main archive.") packagePath := flags.String("p", "", "Package path of the main archive.") outFile := flags.String("o", "", "Path to output file.") - flags.Var(&archives, "arc", "Label, package path, and file name of a dependency, separated by '='") + flags.Var(&archives, "arc", "Label, import path, package path, file name, module path, and module version of a dependency, separated by '='") packageList := flags.String("package_list", "", "The file containing the list of standard library packages") buildmode := flags.String("buildmode", "", "Build mode used.") flags.Var(&xdefs, "X", "A string variable to replace in the linked binary (repeated).") @@ -91,7 +92,18 @@ func link(args []string) error { } // Build an importcfg file. - importcfgName, err := buildImportcfgFileForLink(archives, *packageList, goenv.installSuffix, filepath.Dir(*outFile)) + modinfo := "" + if shouldEmitBuildInfo(*goVersion, *buildmode) { + modules := make([]moduleInfo, 0, len(archives)) + for _, arc := range archives { + modules = append(modules, moduleInfo{ + path: arc.modulePath, + version: arc.moduleVersion, + }) + } + modinfo = modInfoData(modules) + } + importcfgName, err := buildImportcfgFileForLink([]archive(archives), *packageList, goenv.installSuffix, filepath.Dir(*outFile), modinfo) if err != nil { return err } diff --git a/tests/core/go_binary/BUILD.bazel b/tests/core/go_binary/BUILD.bazel index 59048e46e2..b4f4263d72 100644 --- a/tests/core/go_binary/BUILD.bazel +++ b/tests/core/go_binary/BUILD.bazel @@ -23,6 +23,11 @@ go_bazel_test( srcs = ["configurable_attribute_good_test.go"], ) +go_bazel_test( + name = "buildinfo_test", + srcs = ["buildinfo_test.go"], +) + go_binary( name = "hello", srcs = ["hello.go"], diff --git a/tests/core/go_binary/buildinfo_test.go b/tests/core/go_binary/buildinfo_test.go new file mode 100644 index 0000000000..54cfa06164 --- /dev/null +++ b/tests/core/go_binary/buildinfo_test.go @@ -0,0 +1,341 @@ +// Copyright 2026 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 buildinfo_test + +import ( + "encoding/json" + "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_binary( + name = "with_dep", + srcs = ["with_dep.go"], + deps = ["@com_github_google_go_cmp//cmp:go_default_library"], +) + +go_binary( + name = "stdlib_only", + srcs = ["stdlib_only.go"], +) + +go_binary( + name = "with_versionless_dep", + srcs = ["with_versionless_dep.go"], + deps = ["@com_example_versionless//:go_default_library"], +) +-- with_dep.go -- +package main + +import ( + "encoding/json" + "os" + "runtime/debug" + + "github.com/google/go-cmp/cmp" +) + +type dep struct { + Path string ` + "`json:\"path\"`" + ` + Version string ` + "`json:\"version\"`" + ` +} + +type output struct { + OK bool ` + "`json:\"ok\"`" + ` + MainPath string ` + "`json:\"main_path\"`" + ` + MainVersion string ` + "`json:\"main_version\"`" + ` + Deps []dep ` + "`json:\"deps\"`" + ` +} + +func main() { + _ = cmp.Equal("same", "same") + + info, ok := debug.ReadBuildInfo() + out := output{OK: ok} + if info != nil { + out.MainPath = info.Main.Path + out.MainVersion = info.Main.Version + for _, module := range info.Deps { + out.Deps = append(out.Deps, dep{Path: module.Path, Version: module.Version}) + } + } + _ = json.NewEncoder(os.Stdout).Encode(out) +} + +-- stdlib_only.go -- +package main + +import ( + "encoding/json" + "os" + "runtime/debug" +) + +type output struct { + OK bool ` + "`json:\"ok\"`" + ` + MainPath string ` + "`json:\"main_path\"`" + ` + MainVersion string ` + "`json:\"main_version\"`" + ` + DepCount int ` + "`json:\"dep_count\"`" + ` +} + +func main() { + info, ok := debug.ReadBuildInfo() + out := output{OK: ok} + if info != nil { + out.MainPath = info.Main.Path + out.MainVersion = info.Main.Version + out.DepCount = len(info.Deps) + } + _ = json.NewEncoder(os.Stdout).Encode(out) +} + +-- with_versionless_dep.go -- +package main + +import ( + "encoding/json" + "os" + "runtime/debug" + + versionless "example.com/versionless" +) + +type dep struct { + Path string ` + "`json:\"path\"`" + ` + Version string ` + "`json:\"version\"`" + ` +} + +type output struct { + OK bool ` + "`json:\"ok\"`" + ` + MainPath string ` + "`json:\"main_path\"`" + ` + MainVersion string ` + "`json:\"main_version\"`" + ` + Deps []dep ` + "`json:\"deps\"`" + ` +} + +func main() { + _ = versionless.Name() + + info, ok := debug.ReadBuildInfo() + out := output{OK: ok} + if info != nil { + out.MainPath = info.Main.Path + out.MainVersion = info.Main.Version + for _, module := range info.Deps { + out.Deps = append(out.Deps, dep{Path: module.Path, Version: module.Version}) + } + } + _ = json.NewEncoder(os.Stdout).Encode(out) +} + +-- deps/com_github_google_go_cmp/MODULE.bazel -- +module(name = "com_github_google_go_cmp") + +bazel_dep(name = "rules_go", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_license", version = "1.0.0") + +-- deps/com_github_google_go_cmp/BUILD.bazel -- +load("@rules_license//rules:package_info.bzl", "package_info") + +package_info( + name = "gazelle_generated_package_info", + package_name = "github.com/google/go-cmp", + package_version = "0.6.0", + visibility = ["//:__subpackages__"], +) + +-- deps/com_github_google_go_cmp/cmp/BUILD.bazel -- +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "cmp", + srcs = ["cmp.go"], + importpath = "github.com/google/go-cmp/cmp", + applicable_licenses = ["//:gazelle_generated_package_info"], + visibility = ["//visibility:public"], +) + +alias( + name = "go_default_library", + actual = ":cmp", + visibility = ["//visibility:public"], +) + +-- deps/com_github_google_go_cmp/cmp/cmp.go -- +package cmp + +func Equal(x, y string) bool { + return x == y +} + +-- deps/com_example_versionless/MODULE.bazel -- +module(name = "com_example_versionless") + +bazel_dep(name = "rules_go", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_license", version = "1.0.0") + +-- deps/com_example_versionless/BUILD.bazel -- +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@rules_license//rules:package_info.bzl", "package_info") + +package_info( + name = "gazelle_generated_package_info", + package_name = "example.com/versionless", + package_version = "", + visibility = ["//:__subpackages__"], +) + +go_library( + name = "versionless", + srcs = ["versionless.go"], + importpath = "example.com/versionless", + applicable_licenses = [":gazelle_generated_package_info"], + visibility = ["//visibility:public"], +) + +alias( + name = "go_default_library", + actual = ":versionless", + visibility = ["//visibility:public"], +) + +-- deps/com_example_versionless/versionless.go -- +package versionless + +func Name() string { + return "versionless" +} +`, + ModuleFileSuffix: ` +bazel_dep(name = "rules_license", version = "1.0.0") +bazel_dep(name = "com_github_google_go_cmp") +bazel_dep(name = "com_example_versionless") + +local_path_override( + module_name = "com_github_google_go_cmp", + path = "deps/com_github_google_go_cmp", +) + +local_path_override( + module_name = "com_example_versionless", + path = "deps/com_example_versionless", +) +`, + }) +} + +type dep struct { + Path string `json:"path"` + Version string `json:"version"` +} + +type withDepOutput struct { + OK bool `json:"ok"` + MainPath string `json:"main_path"` + MainVersion string `json:"main_version"` + Deps []dep `json:"deps"` +} + +type stdlibOnlyOutput struct { + OK bool `json:"ok"` + MainPath string `json:"main_path"` + MainVersion string `json:"main_version"` + DepCount int `json:"dep_count"` +} + +func TestReadBuildInfoDeps(t *testing.T) { + stdout, err := bazel_testing.BazelOutput("run", "//:with_dep") + if err != nil { + t.Fatal(err) + } + + var got withDepOutput + if err := json.Unmarshal(stdout, &got); err != nil { + t.Fatalf("unmarshal output %q: %v", stdout, err) + } + if !got.OK { + t.Fatalf("ReadBuildInfo returned ok=false: %+v", got) + } + if got.MainPath != "" || got.MainVersion != "" { + t.Fatalf("got Main %q %q; want empty", got.MainPath, got.MainVersion) + } + if len(got.Deps) == 0 { + t.Fatalf("got no deps: %+v", got) + } + + foundCmp := false + for _, dep := range got.Deps { + if dep.Path == "github.com/google/go-cmp" && dep.Version == "v0.6.0" { + foundCmp = true + break + } + } + if !foundCmp { + t.Fatalf("missing github.com/google/go-cmp@v0.6.0 in %+v", got.Deps) + } +} + +func TestReadBuildInfoWithoutMetadata(t *testing.T) { + stdout, err := bazel_testing.BazelOutput("run", "//:stdlib_only") + if err != nil { + t.Fatal(err) + } + + var got stdlibOnlyOutput + if err := json.Unmarshal(stdout, &got); err != nil { + t.Fatalf("unmarshal output %q: %v", stdout, err) + } + if !got.OK { + t.Fatalf("ReadBuildInfo returned ok=false: %+v", got) + } + if got.MainPath != "" || got.MainVersion != "" { + t.Fatalf("got Main %q %q; want empty", got.MainPath, got.MainVersion) + } + if got.DepCount != 0 { + t.Fatalf("got %d deps; want 0", got.DepCount) + } +} + +func TestReadBuildInfoVersionlessDep(t *testing.T) { + stdout, err := bazel_testing.BazelOutput("run", "//:with_versionless_dep") + if err != nil { + t.Fatal(err) + } + + var got withDepOutput + if err := json.Unmarshal(stdout, &got); err != nil { + t.Fatalf("unmarshal output %q: %v", stdout, err) + } + if !got.OK { + t.Fatalf("ReadBuildInfo returned ok=false: %+v", got) + } + + foundVersionless := false + for _, dep := range got.Deps { + if dep.Path == "example.com/versionless" && dep.Version == "(devel)" { + foundVersionless = true + break + } + } + if !foundVersionless { + t.Fatalf("missing example.com/versionless@(devel) in %+v", got.Deps) + } +} diff --git a/tests/core/starlark/BUILD.bazel b/tests/core/starlark/BUILD.bazel index 3c10ffb7ad..245aebf334 100644 --- a/tests/core/starlark/BUILD.bazel +++ b/tests/core/starlark/BUILD.bazel @@ -1,5 +1,6 @@ load(":common_tests.bzl", "common_test_suite") load(":context_tests.bzl", "context_test_suite") +load(":module_info_tests.bzl", "module_info_test_suite") load(":provider_tests.bzl", "provider_test_suite") load(":sdk_tests.bzl", "sdk_test_suite") @@ -7,6 +8,8 @@ common_test_suite() context_test_suite() +module_info_test_suite() + provider_test_suite() sdk_test_suite() diff --git a/tests/core/starlark/module_info_tests.bzl b/tests/core/starlark/module_info_tests.bzl new file mode 100644 index 0000000000..9caf8b132a --- /dev/null +++ b/tests/core/starlark/module_info_tests.bzl @@ -0,0 +1,127 @@ +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_license//rules:package_info.bzl", "package_info") +load("//go/private:context.bzl", "module_info_from_metadata") + +ModuleInfoProbeInfo = provider() + +def _module_info_probe_impl(ctx): + info = module_info_from_metadata( + Label(ctx.attr.module_label), + getattr(ctx.attr, "package_metadata", ()), + getattr(ctx.attr, "applicable_licenses", ()), + ) + return [ModuleInfoProbeInfo( + path = info.path, + version = info.version, + )] + +module_info_probe = rule( + implementation = _module_info_probe_impl, + attrs = { + "module_label": attr.string(mandatory = True), + "package_metadata": attr.label_list(), + }, +) + +def _package_metadata_module_info_test_impl(ctx): + env = analysistest.begin(ctx) + info = analysistest.target_under_test(env)[ModuleInfoProbeInfo] + asserts.equals(env, "github.com/google/go-cmp", info.path) + asserts.equals(env, "v0.6.0", info.version) + return analysistest.end(env) + +package_metadata_module_info_test = analysistest.make(_package_metadata_module_info_test_impl) + +def _applicable_licenses_module_info_test_impl(ctx): + env = analysistest.begin(ctx) + info = analysistest.target_under_test(env)[ModuleInfoProbeInfo] + asserts.equals(env, "golang.org/x/sync", info.path) + asserts.equals(env, "v0.8.0", info.version) + return analysistest.end(env) + +applicable_licenses_module_info_test = analysistest.make(_applicable_licenses_module_info_test_impl) + +def _main_workspace_module_info_test_impl(ctx): + env = analysistest.begin(ctx) + info = analysistest.target_under_test(env)[ModuleInfoProbeInfo] + asserts.equals(env, "", info.path) + asserts.equals(env, "", info.version) + return analysistest.end(env) + +main_workspace_module_info_test = analysistest.make(_main_workspace_module_info_test_impl) + +def _versionless_module_info_test_impl(ctx): + env = analysistest.begin(ctx) + info = analysistest.target_under_test(env)[ModuleInfoProbeInfo] + asserts.equals(env, "example.com/versionless", info.path) + asserts.equals(env, "(devel)", info.version) + return analysistest.end(env) + +versionless_module_info_test = analysistest.make(_versionless_module_info_test_impl) + +def module_info_test_suite(): + package_info( + name = "cmp_package_info", + package_name = "github.com/google/go-cmp", + package_version = "0.6.0", + ) + + module_info_probe( + name = "package_metadata_probe", + module_label = "@com_github_google_go_cmp//cmp:go_default_library", + package_metadata = [":cmp_package_info"], + tags = ["manual"], + ) + + package_metadata_module_info_test( + name = "package_metadata_module_info_test", + target_under_test = ":package_metadata_probe", + ) + + package_info( + name = "sync_package_info", + package_name = "golang.org/x/sync", + package_version = "0.8.0", + ) + + module_info_probe( + name = "applicable_licenses_probe", + module_label = "@org_golang_x_sync//errgroup:go_default_library", + applicable_licenses = [":sync_package_info"], + tags = ["manual"], + ) + + applicable_licenses_module_info_test( + name = "applicable_licenses_module_info_test", + target_under_test = ":applicable_licenses_probe", + ) + + module_info_probe( + name = "main_workspace_probe", + module_label = "//tests/core/starlark:main_workspace_probe", + package_metadata = [":cmp_package_info"], + tags = ["manual"], + ) + + main_workspace_module_info_test( + name = "main_workspace_module_info_test", + target_under_test = ":main_workspace_probe", + ) + + package_info( + name = "versionless_package_info", + package_name = "example.com/versionless", + package_version = "", + ) + + module_info_probe( + name = "versionless_probe", + module_label = "@com_github_google_go_cmp//cmp:go_default_library", + package_metadata = [":versionless_package_info"], + tags = ["manual"], + ) + + versionless_module_info_test( + name = "versionless_module_info_test", + target_under_test = ":versionless_probe", + ) diff --git a/tests/integration/reproducibility/reproducibility_test.go b/tests/integration/reproducibility/reproducibility_test.go index 45866afe24..31c5959822 100644 --- a/tests/integration/reproducibility/reproducibility_test.go +++ b/tests/integration/reproducibility/reproducibility_test.go @@ -46,6 +46,7 @@ go_library( go_binary( name = "hello", srcs = ["hello.go"], + deps = ["@com_github_google_go_cmp//cmp:go_default_library"], ) go_binary( @@ -64,12 +65,15 @@ go_binary( -- hello.go -- package main -import "fmt" +import ( + "fmt" + + "github.com/google/go-cmp/cmp" +) func main() { - fmt.Println("hello") + fmt.Println("hello", cmp.Equal("same", "same")) } - -- add.h -- #ifdef __cplusplus extern "C" { @@ -126,6 +130,54 @@ func main() { fmt.Println("In C++, 2 + 2 = ", AddCPP(2, 2)) } +-- deps/com_github_google_go_cmp/MODULE.bazel -- +module(name = "com_github_google_go_cmp") + +bazel_dep(name = "rules_go", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_license", version = "1.0.0") + +-- deps/com_github_google_go_cmp/BUILD.bazel -- +load("@rules_license//rules:package_info.bzl", "package_info") + +package_info( + name = "gazelle_generated_package_info", + package_name = "github.com/google/go-cmp", + package_version = "0.6.0", + visibility = ["//:__subpackages__"], +) + +-- deps/com_github_google_go_cmp/cmp/BUILD.bazel -- +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "cmp", + srcs = ["cmp.go"], + importpath = "github.com/google/go-cmp/cmp", + applicable_licenses = ["//:gazelle_generated_package_info"], + visibility = ["//visibility:public"], +) + +alias( + name = "go_default_library", + actual = ":cmp", + visibility = ["//visibility:public"], +) + +-- deps/com_github_google_go_cmp/cmp/cmp.go -- +package cmp + +func Equal(x, y string) bool { + return x == y +} + +`, + ModuleFileSuffix: ` +bazel_dep(name = "com_github_google_go_cmp") + +local_path_override( + module_name = "com_github_google_go_cmp", + path = "deps/com_github_google_go_cmp", +) `, }) } diff --git a/third_party/rules_license-stardoc.patch b/third_party/rules_license-stardoc.patch new file mode 100644 index 0000000000..bf5ac974f2 --- /dev/null +++ b/third_party/rules_license-stardoc.patch @@ -0,0 +1,22 @@ +diff -urN a/rules/BUILD b/rules/BUILD +--- a/rules/BUILD 2000-01-01 00:00:00.000000000 -0000 ++++ b/rules/BUILD 2000-01-01 00:00:00.000000000 -0000 +@@ -47,5 +47,5 @@ + exports_files( + glob([ + "*.bzl", + ]), +- visibility = ["//doc_build:__pkg__"], ++ visibility = ["//visibility:public"], + ) +diff -urN a/rules_gathering/BUILD b/rules_gathering/BUILD +--- a/rules_gathering/BUILD 2000-01-01 00:00:00.000000000 -0000 ++++ b/rules_gathering/BUILD 2000-01-01 00:00:00.000000000 -0000 +@@ -29,5 +29,5 @@ + exports_files( + glob([ + "*.bzl", + ]), +- visibility = ["//doc_build:__pkg__"], ++ visibility = ["//visibility:public"], + )