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

go_test: linker conflict when external test indirectly imports library under test #1877

Closed
robfig opened this issue Dec 31, 2018 · 43 comments · Fixed by #2553 or #2579
Closed

go_test: linker conflict when external test indirectly imports library under test #1877

robfig opened this issue Dec 31, 2018 · 43 comments · Fixed by #2553 or #2579
Labels

Comments

@robfig
Copy link
Contributor

robfig commented Dec 31, 2018

EDIT by jayconrod on 2020-07-21: Previous title was "Conflicting package heights due to external test"

The error messages for this issue now look like this:

 package conflict error: k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/equality: package imports k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1
	  was compiled with: //staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library
	but was linked with: //staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_test
This sometimes happens when an external test (package ending with _test)
imports a package that imports the library being tested. This is not supported.

Using rules_go 0.16.5, I got the "conflicting package heights" error from a mix of internal and external tests, even though I believe that should be supported (ea0abdd). I'm not doing anything unusual in my BUILD or Go files, and almost everything was auto-generated by Gazelle. Upon fixing it, Gazelle prints warnings that I shouldn't be separating the targets.

Error log:

INFO: Build options have changed, discarding analysis cache.
INFO: Analysed 85 targets (260 packages loaded, 8534 targets configured).
INFO: Found 85 targets...
ERROR: /Users/robfig/alpha/gocode/src/corp/it/apps/zendesk/BUILD.bazel:17:1: GoCompile gocode/src/corp/it/apps/zendesk/darwin_amd64_stripped/go_default_test%/corp/it/apps/zendesk_test.a failed (Exit 1) compile failed: error executing command
  (cd /private/var/tmp/_bazel_robfig/1db08896ecff7e5e96a745981c3b77e6/execroot/corp && \
  exec env - \
    APPLE_SDK_PLATFORM='' \
    APPLE_SDK_VERSION_OVERRIDE='' \
    CGO_ENABLED=1 \
    GOARCH=amd64 \
    GOOS=darwin \
    GOROOT=external/go_sdk \
    GOROOT_FINAL=GOROOT \
    PATH=external/local_config_cc:/bin:/usr/bin \
    XCODE_VERSION_OVERRIDE=9.4.1 \
  bazel-out/host/bin/external/io_bazel_rules_go/go/tools/builders/darwin_amd64_stripped/compile -sdk external/go_sdk -installsuffix darwin_amd64 -src gocode/src/corp/it/apps/zendesk/client.go -src gocode/src/corp/it/apps/zendesk/models.go -src gocode/src/corp/it/apps/zendesk/blackbox_test.go -src gocode/src/corp/it/apps/zendesk/client_test.go -src gocode/src/corp/it/apps/zendesk/models_test.go -arc 'corp/it/worker/config=corp/it/worker/config=bazel-out/darwin-fastbuild/bin/gocode/src/corp/it/worker/config/darwin_amd64_stripped/go_default_library%/corp/it/worker/config.a' -arc 'github.com/stretchr/testify/assert=github.com/stretchr/testify/assert=bazel-out/darwin-fastbuild/bin/external/com_github_stretchr_testify/assert/darwin_amd64_stripped/go_default_library%/github.com/stretchr/testify/assert.a' -arc 'corp/it/apps=corp/it/apps=bazel-out/darwin-fastbuild/bin/gocode/src/corp/it/apps/darwin_amd64_stripped/go_default_library%/corp/it/apps.a' -arc 'github.com/corp/glog=github.com/corp/glog=bazel-out/darwin-fastbuild/bin/external/com_github_corp_glog/darwin_amd64_stripped/go_default_library%/github.com/corp/glog.a' -arc 'corp/it/apps/zendesk=corp/it/apps/zendesk=bazel-out/darwin-fastbuild/bin/gocode/src/corp/it/apps/zendesk/darwin_amd64_stripped/go_default_test%/corp/it/apps/zendesk.a' -o bazel-out/darwin-fastbuild/bin/gocode/src/corp/it/apps/zendesk/darwin_amd64_stripped/go_default_test%/corp/it/apps/zendesk_test.a -package_list bazel-out/host/bin/external/go_sdk/packages.txt -testfilter only -- -trimpath . -p corp/it/apps/zendesk_test)

Use --sandbox_debug to see verbose messages from the sandbox: compile failed: error executing command
  ... [DUPE ERROR MESSAGE AS ABOVE] ...

Use --sandbox_debug to see verbose messages from the sandbox
GoCompile: error running compiler: exit status 2
/private/var/tmp/_bazel_robfig/1db08896ecff7e5e96a745981c3b77e6/sandbox/darwin-sandbox/399/execroot/corp/gocode/src/corp/it/apps/zendesk/blackbox_test.go:11:2: internal compiler error: conflicting package heights 18 and 16 for path "corp/it/apps/zendesk"

Please file a bug report including a short program that triggers the error.
https://golang.org/issue/new

WORKSPACE

http_archive(
    name = "io_bazel_rules_go",
    url = "https://github.com/bazelbuild/rules_go/releases/download/0.16.5/rules_go-0.16.5.tar.gz",
    sha256 = "7be7dc01f1e0afdba6c8eb2b43d2fa01c743be1b9273ab1eaf6c233df078d705",
)

BUILD file

# //gocode/src/corp/it/apps/okta/BUILD.bazel
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
    name = "go_default_library",
    srcs = [
        "client.go",
        "common.go",
        "const.go",
        "models.go",
    ],
    importpath = "corp/it/apps/okta",
    visibility = ["//visibility:public"],
    deps = [
        "//gocode/src/corp/it/apps:go_default_library",
        "@com_github_corp_errgo//:go_default_library",
        "@com_github_corp_glog//:go_default_library",
    ],
)

go_test(
    name = "go_default_test",
    srcs = [
        "blackbox_test.go",
        "client_test.go",
        "models_test.go",
    ],
    embed = [":go_default_library"],
    deps = [
        "//gocode/src/corp/it/apps:go_default_library",
        "//gocode/src/corp/it/worker/config:go_default_library",
        "@com_github_stretchr_testify//assert:go_default_library",
        "@com_github_corp_errgo//:go_default_library",
    ],
)

Go file (package + imports)

// blackbox_test.go
package okta_test

import (
	"os"
	"testing"
	"corp/it/apps"
	"corp/it/apps/okta"
	"corp/it/worker/config"
)

// tests

Splitting up the BUILD file in the typical way fixes the problem:

go_test(
    name = "go_default_test",
    srcs = [
        "client_test.go",
        "models_test.go",
    ],
    embed = [":go_default_library"],
    deps = [
        "//gocode/src/corp/it/apps:go_default_library",
        "//gocode/src/corp/it/worker/config:go_default_library",
        "@com_github_stretchr_testify//assert:go_default_library",
        "@com_github_corp_errgo//:go_default_library",
    ],
)

go_test(
    name = "go_default_xtest",
    srcs = ["blackbox_test.go"],
    deps = [
        ":go_default_library",
        "//gocode/src/corp/it/apps:go_default_library",
        "//gocode/src/corp/it/worker/config:go_default_library",
        "@com_github_stretchr_testify//assert:go_default_library",
        "@com_github_corp_errgo//:go_default_library",
    ],
)

but results in this warning on subsequent gazelle runs

gazelle: /Users/robfig/alpha/gocode/src/corp/it/apps/okta/BUILD.bazel: go_default_xtest is no longer necessary. Run 'gazelle fix' to squash with go_default_test.
@jayconrod
Copy link
Contributor

Could you post a minimal test case that reproduces this? The smaller the better.

"Conflicting package height" errors generally mean that different versions of the same package are used in a build. Those errors are difficult to analyze.

@robfig
Copy link
Contributor Author

robfig commented Jan 21, 2019

Here's a minimal test case:
https://github.com/robfig/packageheights-example

Run this to see the error:

$ bazel test b:go_default_test

The source of the issue appears to be due to these two factors:

  1. A combination of "external" and non-external tests in the same target

  2. An external test that depends upon a package which would create a cycle if it
    were part of the same package as the code under test.

In this case, the dependencies look like:

a/a.go -> b/b.go
b/b_test.go -> b/b.go
b/b_external_test.go -> a/a.go, b/b.go

package "b" is not allowed to depend upon package "a", but package "b_test" should be allowed to.

@jayconrod
Copy link
Contributor

bazel test @org_golang_x_net//bpf:go_default_test also reproduces this issue.

It seems like the external test package bpf_test imports packages that transitively import the library under test. go build dictates that these libraries should be recompiled to depend on the internal test package instead.

@AustinSchuh
Copy link
Contributor

What about automatically creating 2 go_test rules, one for each package?

@jayconrod
Copy link
Contributor

We used to do that (go_default_xtest). We squashed them because it was a bit messy and it was hard for external tests to depend on definitions in internal tests.

It doesn't really solve this problem though. Try running go list -test -json golang.org/x/net/bpf. golang.org/x/net/bpf_test (external test package) imports golang.org/x/net/bpf [golang.org/x/net/bpf.test] (internal test package). It also imports golang.org/x/net/ipv4 [golang.org/x/net/bpf.test]. That's where the problem is. We get the error because @org_golang_x_net//ipv4:go_default_library is compiled with @org_golang_x_net//bpf:go_default_library, not the internal test package produced by @org_golang_x_net//bpf:go_default_test.

In order to fix this, we'd need to recompile every transitive dependency of @org_golang_x_net//bpf:go_default_test that transitively depends on @org_golang_x_net//bpf:go_default_library. I think we could do that with an aspect, but I'd like to get rid of our current cross-compiling aspect before we think about introducing another one, even in narrow cases like this.

@asf-stripe
Copy link

asf-stripe commented May 16, 2019

Chiming in that we're getting bitten by this too, using rules_go 0.18.2, and gazelle 0.17.0.

The repository I'm trying to test under bazel is not going to get BUILD files checked in anytime soon (so we have to rely on gazelle-generated build files), and this bug is preventing us from making progress pulling its tests into bazel. Is there a workaround we could use in the meantime?

The best I can come up with is by manually excluding the external test files. /:

@jayconrod
Copy link
Contributor

@asf-stripe The build files will require some adjustment to work around this. If you're okay with excluding some test sources, that may just be a matter of deleting something from srcs after Gazelle runs or adding # gazelle:exclude some_test.go before Gazelle runs. If you're using go_repository to pull in this repo, it lets you apply patches after Gazelle runs.

@asf-stripe
Copy link

asf-stripe commented May 16, 2019

Right, I use

    patch_cmds = [
      # Exclude package-external tests from the test run, due to the
      # "conflicting package heights" bug in rules_go at
      # https://github.com/bazelbuild/rules_go/issues/1877:
      """for external_test_file in $(grep -l '^package.*_test$' $(find . -name '*_test.go')) ; do
            bn=$(basename $external_test_file)
            dir=$(dirname $external_test_file)
            sed -i.bak "s#\\"$bn\\",#\\# removed $bn due to https://github.com/bazelbuild/rules_go/issues/1877 #" $dir/BUILD.bazel
         done
      """
    ],

at the moment, and I feel very very disgusted; but it does work... I guess I'll ask around if we're comfortable running like this.

grailbot pushed a commit to grailbio/bio that referenced this issue Mar 3, 2020
Summary:
My changes to github.com/grailbio/bio/encoding/bam in D42945 apparently caused
a Go compiler import-related error:

    /home/grail-builder/.cache/bazel/_bazel_grail-builder/b20b5481828eeefc6fcc4ab4c0b87731/sandbox/processwrapper-sandbox/724/execroot/grail/go/src/github.com/grailbio/bio/encoding/bam/shard_test.go:9:2: internal compiler error: conflicting package heights 21 and 19 for path "github.com/grailbio/bio/encoding/bam"
    Please file a bug report including a short program that triggers the error.
    https://golang.org/issue/new

My best guess is this is a bug in rules_go, maybe [1877](bazelbuild/rules_go#1877) or something similar.
I wasn't able to make a small repro case in [my own branch](https://github.com/josh-newman/bio/tree/gazelle), unfortunately.
However, I guessed this multipath dependency was the problem:

          .--------------.
         /                \
  bam_test -> bamprovider -> bam

And with this revision, I no longer encounter the issue with D42945's `vcontext`
fix, so maybe this is really the issue.

Test Plan: Existing builds and tests.

Reviewers: sbagaria

Reviewed By: sbagaria

Maniphest Tasks: T30452

Differential Revision: https://phabricator.grailbio.com/D42946

fbshipit-source-id: 27a256b
@jayconrod jayconrod changed the title Conflicting package heights due to external test (rules_go 0.16.5) Conflicting package heights due to external test Jun 24, 2020
@jayconrod
Copy link
Contributor

This should be addressed before Go 1.15 ships. 1.15 will trigger link errors in additional tests, since the new linker verifies that hashes of export data match hashes that were seen at compile time (#2535).

I've been thinking about how to implement this. It's at the edge of not being feasible, so I'm leaning toward explicitly not supporting it and providing a clear error message.

To recap, suppose we have a package A with internal and external tests. The external test imports package B, which imports A. Normally, when B is built, it would be built with the library A. However, when building A's tests, we don't pass the library A to the linker; we pass A's internal test package (which embeds the library's sources). So B needs to be recompiled against A's internal test package. We also need to recompile anything that transitively imports B. And we need to do this for every test with this pattern. This scales very poorly: O(n*t) compilations for n packages, with t tests in the worst case.

I don't think there's a practical way to recompile a graph of packages in go_test itself. GoArchive doesn't carry enough information. We could recompile direct dependencies but not transitive dependencies, since we only have a depset of GoArchiveData to pass to the linker.

So we'd be stuck with an aspect. That would need to be gated by a flag on a go_test wrapper to avoid the expense of triggering it for the majority of tests, which don't need it. The aspect would carry the list of embedded targets from the root go_test, and it would replace dependencies on those targets with dependencies on the go_test internal test.

I think this would work, assuming it wouldn't introduce circular dependencies I haven't thought about. Again though, it's complicated, and it enables a pattern which is very costly. It's probably better to just provide a clear error message and encourage developers to avoid this pattern.

@robfig
Copy link
Contributor Author

robfig commented Jun 25, 2020

This is probably a dumb question: what does the Go CLI do, and what is the barrier from Bazel doing the same?

@jayconrod
Copy link
Contributor

The go command recompiles packages that import the library under test to import the internal test package instead. It also recompiles everything that imports recompiled packages, and so on. That's the O(n*t) behavior.

It's harder to do this in rules_go, since individual rules don't have access to the full configured target graph. We'd have to either carry additional information in providers (whether we use it or not), or we'd have to use an aspect (same, but more automatic). Either way, it's pretty expensive.

@robfig
Copy link
Contributor Author

robfig commented Jun 25, 2020

Ah, I assumed that the go command managed to avoid the O(n*t) behavior somehow. Makes sense, thanks for the explanation.

@robfig
Copy link
Contributor Author

robfig commented Jun 25, 2020

To clarify - without support, a package will be able to have internal tests or external tests, but not both?

That limitation seems ok, with a clear message. We don't have many packages with external tests to start with, so the number of affected packages would certainly be small, and there's always a workaround. Go compiles so quickly that the processing time is not a significant factor in my mind, but keeping the rules simpler presumably has maintenance benefits and avoids the opportunity cost.

@jayconrod
Copy link
Contributor

You can have both internal tests and external tests, and when the external test imports the library under test, it will get the internal test package (which embeds the library under test and can inject test doubles)... but you can't have an external test that imports another package that imports the library under test.

When you import another go_library, it's just built as a regular go_library instead of being built in an alternative configuration for the test that needs it.

jayconrod pushed a commit to jayconrod/rules_go that referenced this issue Jul 1, 2020
In general, packages should be compiled with the same dependencies
they're linked against. We haven't been too strict about this in the
past, and there are two common situations where this might not happen:
1) go_proto_library and go_library targets are linked for the same
package, 2) an external test imports a library that imports the
package being tested.

Analysis will now detect both problems and will pass a descriptive
message to the GoLink action. Making this a hard error would be an
incompatible change, so for now, it will be reported if the
incompatible_package_conflict_is_error setting is enabled (bazelbuild#1374) or
if the linker fails.

Fixes bazelbuild#1877
Updates bazelbuild#1374
Updates bazelbuild#2535
jayconrod pushed a commit that referenced this issue Jul 6, 2020
…2553)

In general, packages should be compiled with the same dependencies
they're linked against. We haven't been too strict about this in the
past, and there are two common situations where this might not happen:
1) go_proto_library and go_library targets are linked for the same
package, 2) an external test imports a library that imports the
package being tested.

Analysis will now detect both problems and will pass a descriptive
message to the GoLink action. Making this a hard error would be an
incompatible change, so for now, it will be reported if the
incompatible_package_conflict_is_error setting is enabled (#1374) or
if the linker fails.

Fixes #1877
Updates #1374
Updates #2535
jayconrod pushed a commit to jayconrod/rules_go that referenced this issue Jul 7, 2020
All of these tests fail to link because the external test package
indirectly imports the internal test package. See bazelbuild#1877 for the
original issue.

This pattern is difficult to implement in Bazel, since it requires an
aspect to recompile test dependencies. It's generally possible to
work around it, so now this fails with a descriptive error message.

Fixes bazelbuild#2535
jayconrod pushed a commit that referenced this issue Jul 7, 2020
…#2554)

All of these tests fail to link because the external test package
indirectly imports the internal test package. See #1877 for the
original issue.

This pattern is difficult to implement in Bazel, since it requires an
aspect to recompile test dependencies. It's generally possible to
work around it, so now this fails with a descriptive error message.

Fixes #2535
jayconrod pushed a commit that referenced this issue Jul 8, 2020
…2553)

In general, packages should be compiled with the same dependencies
they're linked against. We haven't been too strict about this in the
past, and there are two common situations where this might not happen:
1) go_proto_library and go_library targets are linked for the same
package, 2) an external test imports a library that imports the
package being tested.

Analysis will now detect both problems and will pass a descriptive
message to the GoLink action. Making this a hard error would be an
incompatible change, so for now, it will be reported if the
incompatible_package_conflict_is_error setting is enabled (#1374) or
if the linker fails.

Fixes #1877
Updates #1374
Updates #2535
jayconrod pushed a commit that referenced this issue Jul 8, 2020
…2553)

In general, packages should be compiled with the same dependencies
they're linked against. We haven't been too strict about this in the
past, and there are two common situations where this might not happen:
1) go_proto_library and go_library targets are linked for the same
package, 2) an external test imports a library that imports the
package being tested.

Analysis will now detect both problems and will pass a descriptive
message to the GoLink action. Making this a hard error would be an
incompatible change, so for now, it will be reported if the
incompatible_package_conflict_is_error setting is enabled (#1374) or
if the linker fails.

Fixes #1877
Updates #1374
Updates #2535
jayconrod pushed a commit that referenced this issue Jul 22, 2020
…2579)

go_test, like 'go test', splits tests into two separate archives: an
internal archive ('package foo') and an external archive
('package foo_test'). The library under test is embedded into the internal
archive. The external archive may import it and may depend on symbols
defined in the internal test files.

To avoid conflicts, the library under test must not be linked into the test
binary, since the internal test archive embeds the same sources.
Libraries imported by the external test that transitively import the
library under test must be recompiled too, or the linker will complain that
export data they were compiled with doesn't match the export data they
are linked with.

This PR adds a function, used in go_test, that identifies which
archives may need to be recompiled, then declares new output files and
actions to recompile them. This is an unfortunately an expensive
process requiring O(V+E) time and space in the size of the test's
dependency graph for each test.

Fixes #1877
@jayconrod
Copy link
Contributor

Hopefully #2579 should fix this issue. Please try it out and comment if you find that anything is still broken.

If it works, I'll backport it and tag a point release this week.

@fishy
Copy link
Contributor

fishy commented Jul 22, 2020

@jayconrod : I tried 464eb9c on the current master version of Baseplate.go and it no longer show the warnings when we run bazel test //...:all. When on v0.23.5 it shows 3 warnings.

@jayconrod
Copy link
Contributor

Glad to hear that! I'm also no longer seeing the warning on @bazel_gazelle//repo:go_default_test. I added some golang.org/x/... tests to rules_go CI that had been broken by this, and they seem to work now.

justaugustus added a commit to justaugustus/repo-infra that referenced this issue Jul 23, 2020
Should fix bazelbuild/rules_go/issues/1877

Signed-off-by: Stephen Augustus <saugustus@vmware.com>
justaugustus added a commit to justaugustus/repo-infra that referenced this issue Jul 23, 2020
Should address bazelbuild/rules_go/issues/1877

Signed-off-by: Stephen Augustus <saugustus@vmware.com>
jayconrod pushed a commit that referenced this issue Jul 23, 2020
…2579)

go_test, like 'go test', splits tests into two separate archives: an
internal archive ('package foo') and an external archive
('package foo_test'). The library under test is embedded into the internal
archive. The external archive may import it and may depend on symbols
defined in the internal test files.

To avoid conflicts, the library under test must not be linked into the test
binary, since the internal test archive embeds the same sources.
Libraries imported by the external test that transitively import the
library under test must be recompiled too, or the linker will complain that
export data they were compiled with doesn't match the export data they
are linked with.

This PR adds a function, used in go_test, that identifies which
archives may need to be recompiled, then declares new output files and
actions to recompile them. This is an unfortunately an expensive
process requiring O(V+E) time and space in the size of the test's
dependency graph for each test.

Fixes #1877
jayconrod pushed a commit that referenced this issue Jul 23, 2020
…2579)

go_test, like 'go test', splits tests into two separate archives: an
internal archive ('package foo') and an external archive
('package foo_test'). The library under test is embedded into the internal
archive. The external archive may import it and may depend on symbols
defined in the internal test files.

To avoid conflicts, the library under test must not be linked into the test
binary, since the internal test archive embeds the same sources.
Libraries imported by the external test that transitively import the
library under test must be recompiled too, or the linker will complain that
export data they were compiled with doesn't match the export data they
are linked with.

This PR adds a function, used in go_test, that identifies which
archives may need to be recompiled, then declares new output files and
actions to recompile them. This is an unfortunately an expensive
process requiring O(V+E) time and space in the size of the test's
dependency graph for each test.

Fixes #1877
jayconrod pushed a commit to jayconrod/rules_go that referenced this issue Jul 23, 2020
For compatibility with Bazel 1.2.0

Updates bazelbuild#1877
jayconrod pushed a commit that referenced this issue Jul 23, 2020
For compatibility with Bazel 1.2.0

Updates #1877
jayconrod pushed a commit that referenced this issue Jul 23, 2020
For compatibility with Bazel 1.2.0

Updates #1877
jayconrod pushed a commit that referenced this issue Jul 23, 2020
For compatibility with Bazel 1.2.0

Updates #1877
@jayconrod
Copy link
Contributor

Point releases with this fix are out now. Please give them a try: v0.22.9, v0.23.6.

fishy added a commit to fishy/baseplate.go that referenced this issue Jul 23, 2020
Upgrade rules_go to v0.23.6, which fixed
bazelbuild/rules_go#1877 that's affecting us.

Also add 'size = "small"' to breakerbp's test target.
fishy added a commit to reddit/baseplate.go that referenced this issue Jul 23, 2020
Upgrade rules_go to v0.23.6, which fixed
bazelbuild/rules_go#1877 that's affecting us.

Also add 'size = "small"' to breakerbp's test target.
@ajwerner
Copy link

ajwerner commented Feb 6, 2022

This sometimes happens when an external test (package ending with _test)
imports a package that imports the library being tested. This is not supported.

This is a totally valid thing to do in go. Should we have a separate tracking issue to support it?

@linzhp
Copy link
Contributor

linzhp commented Feb 7, 2022

@ajwerner I think this is fixed. Have you tried?

@miracvbasaran
Copy link

I am still having an issue with this with go version 1.20, bazel version 6.4.0, io_bazel_rules_go version 0.42.0 and bazel_gazelle version 0.33.0:

link: package conflict error: cloud.google.com/go/iam/apiv1/iampb: package imports google.golang.org/genproto/googleapis/api/annotations
	  was compiled with: @org_golang_google_genproto_googleapis_api//annotations:annotations
	but was linked with: @org_golang_google_genproto//googleapis/api/annotations:annotations
See https://github.com/bazelbuild/rules_go/issues/1877.

Are there any fixes I can make on my side?

@jmhodges
Copy link
Contributor

jmhodges commented Dec 22, 2023

@miracvbasaran ran into this while debugging some other problem and happen to know one possible answer: That Go code you're building might have a dependency on google.golang.org/genproto/googleapis/api but the target is defined as depending on @org_golang_google_genproto//googleapis/api/annotations:annotations (which maps to the parent module google.golang.org/genproto) but should instead depend on its submodule org_golang_google_genproto_googleapis_api//annotations:annotations (which maps to google.golang.org/genproto/googleapis/api). There's two different go.mods (parent module, subpackage module) which I found from looking at the pkg.go.dev pages for these packages.

This happens when you both the parent and subpackage external forms of the target gets added (even transitively) as dependencies!

The fetch of the parent package includes the code for the subpackage, so it's easy to depend on the parent's external and not notice. I think this happens just by explicit accidental inclusion of both externals in the deps but also can happen when the parent and subpackage's maintainers split them out after the parent package has been used by folks for a while and you can upgrade into that without noticing for a while.

Tangentially, it might be nice for rules_go to help detect when folks are accidentally depending on a subpackage's code from the parent package's external. (Maybe it does already! I'm currently upgrading from a 6 month old version)

@remiphilippe
Copy link

remiphilippe commented Dec 29, 2023

@jmhodges we're running into the exact same issue, do you happen to have a workaround?

link: package conflict error: google.golang.org/genproto/googleapis/cloud/location: package imports google.golang.org/genproto/googleapis/api/annotations
          was compiled with: @org_golang_google_genproto//googleapis/api/annotations:annotations
        but was linked with: @org_golang_google_genproto_googleapis_api//annotations:annotations
See https://github.com/bazelbuild/rules_go/issues/1877.

Thanks!

edit:
forgot to mention we also seen linker warnings:

DEBUG: /private/var/tmp/_bazel_/6108bdb662b1210897dd1ebdb34d9b4a/external/io_bazel_rules_go/go/private/actions/link.bzl:59:18: Multiple copies of google.golang.org/genproto/googleapis/api passed to the linker. Ignoring bazel-out/darwin-fastbuild/bin/external/org_golang_google_genproto/googleapis/api/api.a in favor of bazel-out/darwin-fastbuild/bin/external/org_golang_google_genproto_googleapis_api/api.a
DEBUG: /private/var/tmp/_bazel_/6108bdb662b1210897dd1ebdb34d9b4a/external/io_bazel_rules_go/go/private/actions/link.bzl:59:18: Multiple copies of google.golang.org/genproto/googleapis/api/annotations passed to the linker. Ignoring bazel-out/darwin-fastbuild/bin/external/org_golang_google_genproto/googleapis/api/annotations/annotations.a in favor of bazel-out/darwin-fastbuild/bin/external/org_golang_google_genproto_googleapis_api/annotations/annotations.a

@jmhodges
Copy link
Contributor

jmhodges commented Dec 30, 2023

@remiphilippe I'd have to see more of the set up, but I believe that happens when the go_repository for the parent module and the go_repository for the submodule are very different versions and both are (transitively) depended on in a target. Something about there being a missing package in the submodule that is in the parent or vice versa. Often this is because some other dependency requires the older of the two or whatever (and doesn't show up in the errors because that's all working correctly)!

Oh, not sure if you know: you also have to account for the rules_go v0.41 change to how googleapis works now, so be sure to grab a version of it that matches your genproto submodule and your targets that need any of the genproto/... deps.

It's a real mess of upgrading golang.org/x/oauth2, cloud.google.com/go/... repos, google.golang.org/genproto/... repos and, of course, the rules_go 0.34 change to googleapis (iirc) while figuring out what externals are registering older versions of those you need to override. (e.g. golang.org/x/oauth2/google depending on cloud.google.com/go/compute/metadata while cloud.google.com/go/ stuff depends on golang.org/x/oauth2/ is surprisingly annoying and takes a bit to figure out!)

@jmhodges
Copy link
Contributor

@remiphilippe Ah, though, the release that came out yesterday might be relevant to you: https://github.com/bazelbuild/rules_go/releases/tag/v0.44.1

@remiphilippe
Copy link

thanks @jmhodges just gave it a try, still the same. Will try to create a bare bone repro tomorrow, I'm 99% sure it's due to the deps that are pulled in by vault sdk (https://github.com/hashicorp/vault/tree/main/sdk) we use that for our tests, and this issue only happens in tests.

@remiphilippe
Copy link

remiphilippe commented Jan 2, 2024

so couldn't repro in an isolated env, but figured out a fix. Seems to be indeed linked to vault/sdk but not only. What I ended up doing is adding this in my deps:

build_directives = [
            "gazelle:resolve go google.golang.org/genproto/googleapis/api/annotations @org_golang_google_genproto//googleapis/api/annotations",  # keep
            "gazelle:resolve go google.golang.org/genproto/googleapis/api @org_golang_google_genproto//googleapis/api",  # keep
        ],

for the following packages (I got a list from go mod graph, not all the packages require it, couldn't find a specific version common to all of these):

name = "com_google_cloud_go_compute",
name = "com_google_cloud_go_iam",
name = "com_google_cloud_go_kms",
name = "com_google_cloud_go_monitoring",
name = "io_etcd_go_etcd_api_v3",
name = "io_etcd_go_etcd_client_pkg_v3",
name = "io_opentelemetry_go_otel_exporters_otlp_otlpmetric_otlpmetricgrpc"
name = "io_opentelemetry_go_otel_exporters_otlp_otlptrace_otlptracegrpc",
name = "org_golang_google_api",
name = "org_golang_google_genproto_googleapis_api",

everything builds fine now, I'll see if I can dig into more later.
Thanks for the help!

@fmeum
Copy link
Collaborator

fmeum commented Jan 2, 2024

@remiphilippe Glad you found a fix.

Anyone interested in submitting a PR against https://github.com/bazelbuild/bazel-gazelle/blob/8fbf08c4da0a015a2489512aa8238d52f8e32ef4/internal/bzlmod/default_gazelle_overrides.bzl#L24 so that gazelle users get this by default?

@miracvbasaran
Copy link

Thanks @jmhodges & @remiphilippe! @remiphilippe's fix (#1877 (comment)) did the trick for me.

However, I also had the add the build_directives to:

name = "com_google_cloud_go_storage"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet