From c8bdb683fc11f699e69eb70d62ebf44cf2bfd775 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 20 Aug 2026 14:56:51 +0800 Subject: [PATCH] build: preserve main package identity for test builds --- dev/test_std_buildmodes.sh | 6 ++++-- dev/test_std_buildmodes/runner.c | 8 ++++---- internal/build/build.go | 16 ++++++++-------- internal/build/build_test.go | 21 +-------------------- internal/packages/load.go | 6 +++--- ssa/abi/abi.go | 3 ++- test/go/linkname/demo_test.go | 25 +++++++++++++++++++++++++ test/go/linkname/main.go | 18 ++++++++++++++++++ test/go/linkname/main_test.go | 31 +++++++++++++++++++++++++++++++ 9 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 test/go/linkname/demo_test.go create mode 100644 test/go/linkname/main.go create mode 100644 test/go/linkname/main_test.go diff --git a/dev/test_std_buildmodes.sh b/dev/test_std_buildmodes.sh index adaee179b9..a813fc5992 100755 --- a/dev/test_std_buildmodes.sh +++ b/dev/test_std_buildmodes.sh @@ -96,10 +96,12 @@ for mode in c-shared c-archive; do fi import_path="${import_paths[$i]}" stem="${stems[$i]}" - test_main_pkg="${import_path}.test" runner_base="${work_dir}/runner-${i}" echo "==> ${test_pkgs[$i]}: run ${mode}" - runner_cflags=("-DGO_TEST_PACKAGE=\"${test_main_pkg}\"") + # Test-main packages keep the Go package identity "main". The + # output library is still named after its import path (for example, + # libtar.test), but its entry points are main.init and main.main. + runner_cflags=("-DGO_TEST_MAIN_PACKAGE=\"main\"") if [[ "${mode}" == c-shared ]]; then runner_cflags+=("-DGO_C_SHARED=1") fi diff --git a/dev/test_std_buildmodes/runner.c b/dev/test_std_buildmodes/runner.c index ada134d2c2..602a8af102 100644 --- a/dev/test_std_buildmodes/runner.c +++ b/dev/test_std_buildmodes/runner.c @@ -1,5 +1,5 @@ -#ifndef GO_TEST_PACKAGE -#error GO_TEST_PACKAGE must name the generated Go test main package +#ifndef GO_TEST_MAIN_PACKAGE +#error GO_TEST_MAIN_PACKAGE must name the generated Go test main package #endif #include @@ -10,8 +10,8 @@ #define GO_SYMBOL(name) __asm__(name) #endif -extern void llgo_test_init(void) GO_SYMBOL(GO_TEST_PACKAGE ".init"); -extern void llgo_test_run(void) GO_SYMBOL(GO_TEST_PACKAGE ".main"); +extern void llgo_test_init(void) GO_SYMBOL(GO_TEST_MAIN_PACKAGE ".init"); +extern void llgo_test_run(void) GO_SYMBOL(GO_TEST_MAIN_PACKAGE ".main"); extern int __llgo_argc; extern char **__llgo_argv; diff --git a/internal/build/build.go b/internal/build/build.go index 6f870695c1..f9cf2a1cf9 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -520,11 +520,14 @@ func Build(inv Invocation) ([]Package, error) { defer syntaxErrMu.Unlock() return syntaxErr } - dedup.SetPreload(func(pkg *types.Package, files []*ast.File) { - if llruntime.SkipToBuild(pkg.Path()) { + dedup.SetPreload(func(pkg *packages.Package) { + if llruntime.SkipToBuild(pkg.PkgPath) { return } - if err := cl.ParsePkgSyntaxWithOptions(prog, cfg.Fset, pkg, files, preloadOptions); err != nil { + if pkg.Name == "main" && pkg.ForTest != "" { + pkg.Types.Scope().Insert(types.NewConst(0, pkg.Types, abi.ForTestMarker, types.Typ[types.UntypedBool], constant.MakeBool(true))) + } + if err := cl.ParsePkgSyntaxWithOptions(prog, cfg.Fset, pkg.Types, pkg.Syntax, preloadOptions); err != nil { recordSyntaxErr(err) } }) @@ -888,9 +891,6 @@ func filterTestPackages(initial []*packages.Package, outFile string) ([]*package if needLink(pkg, ModeTest) { filtered = append(filtered, pkg) } - if pkg.Types != nil && pkg.Types.Name() == "main" { - pkg.Types.SetName("main.test") - } } if len(filtered) > 1 && outFile != "" { return nil, fmt.Errorf("cannot use -o flag with multiple packages") @@ -1784,8 +1784,8 @@ func cSharedExportArgs(ctx *context, pkgs []*aPackage) []string { } } if ctx.mode == ModeTest && pkg.Package != nil && pkg.Name == "main" && strings.HasSuffix(pkg.PkgPath, ".test") { - exports[pkg.PkgPath+".init"] = none{} - exports[pkg.PkgPath+".main"] = none{} + exports["main.init"] = none{} + exports["main.main"] = none{} } } names := make([]string, 0, len(exports)) diff --git a/internal/build/build_test.go b/internal/build/build_test.go index 57cca90998..53c9d53d71 100644 --- a/internal/build/build_test.go +++ b/internal/build/build_test.go @@ -811,25 +811,6 @@ func TestFilterTestPackages(t *testing.T) { } }) - t.Run("rename main package", func(t *testing.T) { - mainPkg := pkg("example.com/cmd") - mainPkg.Types = types.NewPackage(mainPkg.ID, "main") - initial := []*packages.Package{ - mainPkg, - pkg("example.com/cmd.test"), - } - filtered, err := filterTestPackages(initial, "") - if err != nil { - t.Fatalf("filterTestPackages returned unexpected error: %v", err) - } - if len(filtered) != 1 || filtered[0].ID != "example.com/cmd.test" { - t.Fatalf("filtered = %#v, want only example.com/cmd.test", filtered) - } - if got := mainPkg.Types.Name(); got != "main.test" { - t.Fatalf("main package name = %q, want %q", got, "main.test") - } - }) - t.Run("multiple test packages with output file", func(t *testing.T) { initial := []*packages.Package{ pkg("a.test"), @@ -1378,7 +1359,7 @@ func TestCSharedExportArgsKeepsTestMain(t *testing.T) { mode: ModeTest, buildConf: &Config{BuildMode: BuildModeCShared, Goos: "linux"}, } - if got, want := strings.Join(cSharedExportArgs(ctx, pkgs), " "), "-Wl,--undefined=example.com/p.test.init -Wl,--undefined=example.com/p.test.main"; got != want { + if got, want := strings.Join(cSharedExportArgs(ctx, pkgs), " "), "-Wl,--undefined=main.init -Wl,--undefined=main.main"; got != want { t.Fatalf("test main cSharedExportArgs = %q, want %q", got, want) } } diff --git a/internal/packages/load.go b/internal/packages/load.go index 97c46838dd..23f5fb8941 100644 --- a/internal/packages/load.go +++ b/internal/packages/load.go @@ -90,7 +90,7 @@ type aDeduper struct { cache sync.Map checked sync.Map setpath func(path string, name string) string - preload func(pkg *types.Package, syntax []*ast.File) + preload func(pkg *packages.Package) llgoFiles map[string][]string } @@ -100,7 +100,7 @@ func NewDeduper() Deduper { return &aDeduper{} } -func (p Deduper) SetPreload(fn func(pkg *types.Package, syntax []*ast.File)) { +func (p Deduper) SetPreload(fn func(pkg *packages.Package)) { p.preload = fn } @@ -458,7 +458,7 @@ func (tc *typecheckContext) typecheckPackage(pkg *Package) { }) if tc.dedup != nil && tc.dedup.preload != nil { - tc.dedup.preload(pkg.Types, pkg.Syntax) + tc.dedup.preload(pkg) } typeConf := &types.Config{ diff --git a/ssa/abi/abi.go b/ssa/abi/abi.go index fbda4356b9..d1d36c4fad 100644 --- a/ssa/abi/abi.go +++ b/ssa/abi/abi.go @@ -286,6 +286,7 @@ func typeArgString(t types.Type) string { const ( PatchPathPrefix = env.LLGoRuntimePkg + "/internal/lib/" + ForTestMarker = "@ForTest" ) // PathOf returns the package path of the specified package. @@ -293,7 +294,7 @@ func PathOf(pkg *types.Package) string { if pkg == nil { return "" } - if pkg.Name() == "main" { + if pkg.Name() == "main" && pkg.Scope().Lookup(ForTestMarker) == nil { return "main" } return strings.TrimPrefix(pkg.Path(), PatchPathPrefix) diff --git a/test/go/linkname/demo_test.go b/test/go/linkname/demo_test.go new file mode 100644 index 0000000000..f13a461d10 --- /dev/null +++ b/test/go/linkname/demo_test.go @@ -0,0 +1,25 @@ +package main_test + +import ( + "testing" + _ "unsafe" +) + +//go:linkname demo github.com/xgo-dev/llgo/test/go/linkname.demo +func demo() int + +func xdemo1() int { + return 44 +} + +//go:linkname xdemo2 github.com/xgo-dev/llgo/test/go/linkname_test.xdemo1 +func xdemo2() int + +func TestLinknameFromExternalTestPackage(t *testing.T) { + if got := demo(); got != 42 { + t.Fatalf("external-test-to-main linkname = %d, want 42", got) + } + if got := xdemo2(); got != 44 { + t.Fatalf("external-test self linkname = %d, want 44", got) + } +} diff --git a/test/go/linkname/main.go b/test/go/linkname/main.go new file mode 100644 index 0000000000..b7348453c3 --- /dev/null +++ b/test/go/linkname/main.go @@ -0,0 +1,18 @@ +package main + +import _ "unsafe" + +func main() { + main_demo() +} + +func demo() int { + return 42 +} + +func demo2() int { + return 43 +} + +//go:linkname main_demo main.demo +func main_demo() int diff --git a/test/go/linkname/main_test.go b/test/go/linkname/main_test.go new file mode 100644 index 0000000000..6670e8d5e0 --- /dev/null +++ b/test/go/linkname/main_test.go @@ -0,0 +1,31 @@ +package main + +import ( + "testing" + _ "unsafe" +) + +func TestLinknameFromSameTestPackage(t *testing.T) { + if got := demo(); got != 42 { + t.Fatalf("same-package linkname = %d, want 42", got) + } +} + +func demo3() int { + return 42 +} + +//go:linkname demo4 github.com/xgo-dev/llgo/test/go/linkname.demo2 +func demo4() int + +//go:linkname demo5 github.com/xgo-dev/llgo/test/go/linkname.demo3 +func demo5() int + +func TestLinknameToMainPackage(t *testing.T) { + if got := demo4(); got != 43 { + t.Fatalf("test-to-main linkname = %d, want 43", got) + } + if got := demo5(); got != 42 { + t.Fatalf("test-to-main linkname = %d, want 42", got) + } +}