diff --git a/_demo/go/gobuild/demo.go b/_demo/go/gobuild/demo.go new file mode 100644 index 00000000..b2177544 --- /dev/null +++ b/_demo/go/gobuild/demo.go @@ -0,0 +1,147 @@ +package main + +import ( + "fmt" + "go/build" + "runtime" + "strings" +) + +func main() { + fmt.Printf("runtime.Compiler = %q\n", runtime.Compiler) + + // Test 1: Check build.Default context + ctx := build.Default + fmt.Printf("build.Default.Compiler = %q\n", ctx.Compiler) + if ctx.Compiler != "gc" { + panic(fmt.Sprintf("expected build.Default.Compiler to be \"gc\", got %q", ctx.Compiler)) + } + + if len(ctx.ToolTags) == 0 { + panic("expected build.Default.ToolTags to be non-empty") + } + fmt.Printf("build.Default.ToolTags = %v\n", ctx.ToolTags) + + if len(ctx.ReleaseTags) == 0 { + panic("expected build.Default.ReleaseTags to be non-empty") + } + fmt.Printf("build.Default.ReleaseTags count = %d\n", len(ctx.ReleaseTags)) + + // Validate GOOS and GOARCH are set + if ctx.GOOS == "" { + panic("expected build.Default.GOOS to be non-empty") + } + if ctx.GOARCH == "" { + panic("expected build.Default.GOARCH to be non-empty") + } + fmt.Printf("build.Default.GOOS = %q, GOARCH = %q\n", ctx.GOOS, ctx.GOARCH) + + // Test 2: Import standard library package with FindOnly + pkg, err := build.Import("fmt", "", build.FindOnly) + if err != nil { + panic(fmt.Sprintf("build.Import(\"fmt\") failed: %v", err)) + } + if pkg.ImportPath != "fmt" { + panic(fmt.Sprintf("expected ImportPath \"fmt\", got %q", pkg.ImportPath)) + } + if !pkg.Goroot { + panic("expected fmt package to be in GOROOT") + } + fmt.Printf("build.Import(\"fmt\"): ImportPath=%s, Goroot=%v\n", pkg.ImportPath, pkg.Goroot) + + // Test 3: Import nested standard library package + osPkg, err := build.Import("os/exec", "", build.FindOnly) + if err != nil { + panic(fmt.Sprintf("build.Import(\"os/exec\") failed: %v", err)) + } + if osPkg.ImportPath != "os/exec" { + panic(fmt.Sprintf("expected ImportPath \"os/exec\", got %q", osPkg.ImportPath)) + } + if !osPkg.Goroot { + panic("expected os/exec package to be in GOROOT") + } + fmt.Printf("build.Import(\"os/exec\"): ImportPath=%s, Goroot=%v\n", osPkg.ImportPath, osPkg.Goroot) + + // Test 4: Import internal package (should succeed with FindOnly) + internalPkg, err := build.Import("internal/cpu", "", build.FindOnly) + if err != nil { + panic(fmt.Sprintf("build.Import(\"internal/cpu\") failed: %v", err)) + } + if internalPkg.ImportPath != "internal/cpu" { + panic(fmt.Sprintf("expected ImportPath \"internal/cpu\", got %q", internalPkg.ImportPath)) + } + fmt.Printf("build.Import(\"internal/cpu\"): ImportPath=%s\n", internalPkg.ImportPath) + + // Test 5: Import with srcDir parameter + runtimePkg, err := build.Import("runtime", "", build.FindOnly) + if err != nil { + panic(fmt.Sprintf("build.Import(\"runtime\") failed: %v", err)) + } + if runtimePkg.ImportPath != "runtime" { + panic(fmt.Sprintf("expected ImportPath \"runtime\", got %q", runtimePkg.ImportPath)) + } + if runtimePkg.Dir == "" { + panic("expected runtime package Dir to be non-empty") + } + fmt.Printf("build.Import(\"runtime\"): ImportPath=%s, Dir exists=%v\n", runtimePkg.ImportPath, runtimePkg.Dir != "") + + // Test 6: ImportDir with current directory + dirPkg, err := build.ImportDir(".", build.FindOnly) + if err != nil { + panic(fmt.Sprintf("build.ImportDir(\".\") failed: %v", err)) + } + // Note: Name might be empty with FindOnly mode as it doesn't read source files + fmt.Printf("build.ImportDir(\".\"): Dir=%s, ImportPath=%s\n", dirPkg.Dir, dirPkg.ImportPath) + + // Test 7: IsLocalImport with various paths + testCases := []struct { + path string + expected bool + }{ + {"./foo", true}, + {"../bar", true}, + {"./", true}, + {"fmt", false}, + {"github.com/user/repo", false}, + {"", false}, + } + for _, tc := range testCases { + result := build.IsLocalImport(tc.path) + if result != tc.expected { + panic(fmt.Sprintf("build.IsLocalImport(%q): expected %v, got %v", tc.path, tc.expected, result)) + } + } + fmt.Printf("build.IsLocalImport: all test cases passed\n") + + // Test 8: Verify Context has expected fields + if ctx.GOPATH == "" && ctx.GOROOT == "" { + panic("expected either GOPATH or GOROOT to be set") + } + fmt.Printf("build.Default.GOROOT exists = %v\n", ctx.GOROOT != "") + + // Test 9: Import with AllowBinary flag + binaryPkg, err := build.Import("fmt", "", build.FindOnly|build.AllowBinary) + if err != nil { + panic(fmt.Sprintf("build.Import with AllowBinary failed: %v", err)) + } + if binaryPkg.ImportPath != "fmt" { + panic(fmt.Sprintf("expected ImportPath \"fmt\", got %q", binaryPkg.ImportPath)) + } + fmt.Printf("build.Import(\"fmt\") with AllowBinary: success\n") + + // Test 10: Verify compiler tag in build context + hasCompilerTag := false + for _, tag := range ctx.ReleaseTags { + if strings.HasPrefix(tag, "go1.") { + hasCompilerTag = true + break + } + } + if !hasCompilerTag { + panic("expected at least one go1.x release tag") + } + fmt.Printf("build.Default.ReleaseTags: contains go1.x tags = %v\n", hasCompilerTag) + + fmt.Printf("\nSuccess! All go/build public functions work correctly with llgo\n") + fmt.Printf("Total tests passed: 10\n") +} diff --git a/runtime/build.go b/runtime/build.go index 32bee643..ce5b8915 100644 --- a/runtime/build.go +++ b/runtime/build.go @@ -22,6 +22,7 @@ var hasAltPkg = map[string]none{ "crypto/sha256": {}, "crypto/sha512": {}, "crypto/subtle": {}, + "go/build": {}, "go/parser": {}, "hash/crc32": {}, "hash/maphash": {}, diff --git a/runtime/internal/lib/go/build/build.go b/runtime/internal/lib/go/build/build.go new file mode 100644 index 00000000..576fa0a7 --- /dev/null +++ b/runtime/internal/lib/go/build/build.go @@ -0,0 +1,19 @@ +// Copyright 2024 The GoPlus Authors (goplus.org). All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package build provides alternative implementations for go/build. +// We override build.Default.Compiler in an init function. + +package build + +import ( + "go/build" +) + +func init() { + // LLGO PATCH: Override build.Default.Compiler to be "gc" instead of "llgo" + // This prevents "unknown compiler" errors when user code uses go/build package + // Even though runtime.Compiler = "llgo", we set build.Default.Compiler = "gc" + build.Default.Compiler = "gc" +} diff --git a/runtime/internal/lib/runtime/symtab.go b/runtime/internal/lib/runtime/symtab.go index 04d236eb..a583611f 100644 --- a/runtime/internal/lib/runtime/symtab.go +++ b/runtime/internal/lib/runtime/symtab.go @@ -140,6 +140,10 @@ type Func struct { opaque struct{} // unexported field to disallow conversions } +func (f *Func) Name() string { + panic("todo") +} + // moduledata records information about the layout of the executable // image. It is written by the linker. Any changes here must be // matched changes to the code in cmd/link/internal/ld/symtab.go:symtab.