diff --git a/.bazelrc b/.bazelrc index a6bde4f8a..57755f37a 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,6 +1,9 @@ # This file contains options passed to Bazel when running tests. # They are used by Travis CI and by non-Bazel test scripts. +# TODO: Make all tests work with Bzlmod. +common --noenable_bzlmod + build:ci --verbose_failures build:ci --sandbox_debug build:ci --spawn_strategy=standalone diff --git a/.bazelversion b/.bazelversion index 21c8c7b46..b26a34e47 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.1.1 +7.2.1 diff --git a/cmd/gazelle/integration_test.go b/cmd/gazelle/integration_test.go index c5002b0c3..cab375b50 100644 --- a/cmd/gazelle/integration_test.go +++ b/cmd/gazelle/integration_test.go @@ -4751,3 +4751,97 @@ require ( t.Fatalf("got %s ; want %s; diff %s", string(got), want, cmp.Diff(string(got), want)) } } + +func TestCgoFlagsHaveExternalPrefix(t *testing.T) { + files := []testtools.FileSpec{ + { + Path: "external/com_example_foo_v2/go.mod", + Content: "module example.com/foo/v2", + }, { + Path: "external/com_example_foo_v2/cgo_static.go", + Content: ` +package duckdb + +/* +#cgo LDFLAGS: -lstdc++ -lm -ldl -L${SRCDIR}/deps +*/ +import "C" +`, + }, + } + dir, cleanup := testtools.CreateFiles(t, files) + defer cleanup() + + repoRoot := filepath.Join(dir, "external", "com_example_foo_v2") + + args := []string{"update", "-repo_root", repoRoot, "-go_prefix", "example.com/foo/v2", "-go_repository_mode", "-go_repository_module_mode"} + if err := runGazelle(repoRoot, args); err != nil { + t.Fatal(err) + } + + testtools.CheckFiles(t, repoRoot, []testtools.FileSpec{ + { + Path: "BUILD.bazel", + Content: ` +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "foo", + srcs = ["cgo_static.go"], + cgo = True, + clinkopts = ["-lstdc++ -lm -ldl -Lexternal/com_example_foo_v2/deps"], + importpath = "example.com/foo/v2", + importpath_aliases = ["example.com/foo"], + visibility = ["//visibility:public"], +) +`, + }, + }) +} + +func TestCgoFlagsHaveDotDotPrefixWithSiblingRepositoryLayout(t *testing.T) { + files := []testtools.FileSpec{ + { + Path: "execroot/com_example_foo_v2/go.mod", + Content: "module example.com/foo/v2", + }, { + Path: "execroot/com_example_foo_v2/cgo_static.go", + Content: ` +package duckdb + +/* +#cgo LDFLAGS: -lstdc++ -lm -ldl -L${SRCDIR}/deps +*/ +import "C" +`, + }, + } + dir, cleanup := testtools.CreateFiles(t, files) + defer cleanup() + + repoRoot := filepath.Join(dir, "execroot", "com_example_foo_v2") + + args := []string{"update", "-repo_root", repoRoot, "-go_prefix", "example.com/foo/v2", "-go_repository_mode", "-go_repository_module_mode"} + if err := runGazelle(repoRoot, args); err != nil { + t.Fatal(err) + } + + testtools.CheckFiles(t, repoRoot, []testtools.FileSpec{ + { + Path: "BUILD.bazel", + Content: ` +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "foo", + srcs = ["cgo_static.go"], + cgo = True, + clinkopts = ["-lstdc++ -lm -ldl -L../com_example_foo_v2/deps"], + importpath = "example.com/foo/v2", + importpath_aliases = ["example.com/foo"], + visibility = ["//visibility:public"], +) +`, + }, + }) +} diff --git a/language/go/fileinfo.go b/language/go/fileinfo.go index eabbefbf2..38a95665b 100644 --- a/language/go/fileinfo.go +++ b/language/go/fileinfo.go @@ -211,7 +211,7 @@ func otherFileInfo(path string) fileInfo { // will be returned. // This function is intended to match go/build.Context.Import. // TODD(#53): extract canonical import path -func goFileInfo(path, rel string) fileInfo { +func goFileInfo(path, srcdir string) fileInfo { info := fileNameInfo(path) fset := token.NewFileSet() pf, err := parser.ParseFile(fset, info.path, nil, parser.ImportsOnly|parser.ParseComments) @@ -254,7 +254,7 @@ func goFileInfo(path, rel string) fileInfo { cg = d.Doc } if cg != nil { - if err := saveCgo(&info, rel, cg); err != nil { + if err := saveCgo(&info, srcdir, cg); err != nil { log.Printf("%s: error reading go file: %v", info.path, err) } } @@ -317,7 +317,7 @@ func goFileInfo(path, rel string) fileInfo { // saveCgo extracts CFLAGS, CPPFLAGS, CXXFLAGS, and LDFLAGS directives // from a comment above a "C" import. This is intended to match logic in // go/build.Context.saveCgo. -func saveCgo(info *fileInfo, rel string, cg *ast.CommentGroup) error { +func saveCgo(info *fileInfo, srcdir string, cg *ast.CommentGroup) error { text := cg.Text() for _, line := range strings.Split(text, "\n") { orig := line @@ -355,7 +355,7 @@ func saveCgo(info *fileInfo, rel string, cg *ast.CommentGroup) error { } for i, opt := range opts { - if opt, ok = expandSrcDir(opt, rel); !ok { + if opt, ok = expandSrcDir(opt, srcdir); !ok { return fmt.Errorf("%s: malformed #cgo argument: %s", info.path, orig) } opts[i] = opt @@ -478,8 +478,10 @@ func expandSrcDir(str string, srcdir string) (string, bool) { // See golang.org/issue/6038. // The @ is for OS X. See golang.org/issue/13720. // The % is for Jenkins. See golang.org/issue/16959. +// The ~ is for Bzlmod as it is used as a separator in repository names. It is special in shells (which we don't pass +// it to) and on Windows (where it can still be part of legitimate short paths). const ( - safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%" + safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%~" safeSpaces = " " ) diff --git a/language/go/generate.go b/language/go/generate.go index 9e3ed9aaa..e0cc1c286 100644 --- a/language/go/generate.go +++ b/language/go/generate.go @@ -36,6 +36,7 @@ func (gl *goLang) GenerateRules(args language.GenerateArgs) language.GenerateRes // Extract information about proto files. We need this to exclude .pb.go // files and generate go_proto_library rules. c := args.Config + gc := getGoConfig(c) pcMode := getProtoMode(c) // This is a collection of proto_library rule names that have a corresponding @@ -117,11 +118,27 @@ func (gl *goLang) GenerateRules(args language.GenerateArgs) language.GenerateRes } // Build a set of packages from files in this directory. + srcdir := args.Rel + if gc.goRepositoryMode { + // cgo opts such as '-L${SRCDIR}/libs' should become + // '-Lexternal/my_repo~/libs' in an external repo. + // We obtain the path from the repo root to support both cases of + // --experimental_sibling_repository_layout. + slashPath := filepath.ToSlash(c.RepoRoot) + segments := strings.Split(slashPath, "/") + repoName := segments[len(segments)-1] + previousSegment := segments[len(segments)-2] + if previousSegment == "external" { + srcdir = path.Join("external", repoName, srcdir) + } else { + srcdir = path.Join("..", repoName, srcdir) + } + } goFileInfos := make([]fileInfo, len(goFiles)) var er *embedResolver for i, name := range goFiles { path := filepath.Join(args.Dir, name) - goFileInfos[i] = goFileInfo(path, args.Rel) + goFileInfos[i] = goFileInfo(path, srcdir) if len(goFileInfos[i].embeds) > 0 && er == nil { er = newEmbedResolver(args.Dir, args.Rel, c.ValidBuildFileNames, gl.goPkgRels, args.Subdirs, args.RegularFiles, args.GenFiles) } diff --git a/tests/bcr/go_mod/.bazelversion b/tests/bcr/go_mod/.bazelversion index 21c8c7b46..b26a34e47 100644 --- a/tests/bcr/go_mod/.bazelversion +++ b/tests/bcr/go_mod/.bazelversion @@ -1 +1 @@ -7.1.1 +7.2.1 diff --git a/tests/bcr/go_work/.bazelversion b/tests/bcr/go_work/.bazelversion index a8907c025..b26a34e47 100644 --- a/tests/bcr/go_work/.bazelversion +++ b/tests/bcr/go_work/.bazelversion @@ -1 +1 @@ -7.0.2 +7.2.1