From b17632a3524335c35c59e0b2fa594d77bb553611 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 09:25:49 +0800 Subject: [PATCH 1/8] xtool: clang.Cmd supports Env/Verbose/Stdio, add CCFLAGS support --- xtool/clang/clang.go | 91 ++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/xtool/clang/clang.go b/xtool/clang/clang.go index 657883df..d9dfd8cc 100644 --- a/xtool/clang/clang.go +++ b/xtool/clang/clang.go @@ -17,9 +17,11 @@ package clang import ( + "fmt" "io" "os" "os/exec" + "runtime" "strings" ) @@ -27,10 +29,12 @@ import ( // Cmd represents a clang command. type Cmd struct { - app string - - Stdout io.Writer - Stderr io.Writer + app string + Env []string + Verbose bool + Stdin io.Reader + Stdout io.Writer + Stderr io.Writer } // New creates a new clang command. @@ -38,33 +42,56 @@ func New(app string) *Cmd { if app == "" { app = "clang" } - return &Cmd{app, os.Stdout, os.Stderr} + return &Cmd{app, nil, false, nil, os.Stdout, os.Stderr} } func (p *Cmd) Compile(args ...string) error { - // Parse CFLAGS environment variable into separate arguments - cflags := strings.Fields(os.Getenv("CFLAGS")) - if len(cflags) > 0 { - // Create a new slice with capacity for all arguments - newArgs := make([]string, 0, len(cflags)+len(args)) - newArgs = append(newArgs, cflags...) - newArgs = append(newArgs, args...) - args = newArgs - } - return p.Exec(args...) + return p.execWithFlags([]string{"CFLAGS", "CCFLAGS"}, args...) } func (p *Cmd) Link(args ...string) error { - // Parse LDFLAGS environment variable into separate arguments - ldflags := strings.Fields(os.Getenv("LDFLAGS")) - if len(ldflags) > 0 { - // Create a new slice with capacity for all arguments - newArgs := make([]string, 0, len(ldflags)+len(args)) - newArgs = append(newArgs, ldflags...) - newArgs = append(newArgs, args...) - args = newArgs + return p.execWithFlags([]string{"LDFLAGS", "CCFLAGS"}, args...) +} + +// execWithFlags executes a clang command with flags from environment variables. +func (p *Cmd) execWithFlags(flags []string, args ...string) error { + var allFlags []string + if p.Env != nil { + for _, env := range p.Env { + parts := strings.SplitN(env, "=", 2) + if len(parts) != 2 { + continue + } + key, value := parts[0], parts[1] + for _, flagName := range flags { + if key == flagName { + allFlags = append(allFlags, strings.Fields(value)...) + break + } + } + } + } else { + for _, flagName := range flags { + envValue := os.Getenv(flagName) + if envValue != "" { + allFlags = append(allFlags, strings.Fields(envValue)...) + } + } } - return p.Exec(args...) + cmdArgs := make([]string, 0, len(allFlags)+len(args)) + cmdArgs = append(cmdArgs, allFlags...) + cmdArgs = append(cmdArgs, args...) + cmd := exec.Command(p.app, cmdArgs...) + if p.Verbose { + fmt.Fprintf(os.Stderr, "%v\n", cmd) + } + cmd.Stdin = p.Stdin + cmd.Stdout = p.Stdout + cmd.Stderr = p.Stderr + if p.Env != nil { + cmd.Env = p.Env + } + return cmd.Run() } // Exec executes a clang command. @@ -72,7 +99,23 @@ func (p *Cmd) Exec(args ...string) error { cmd := exec.Command(p.app, args...) cmd.Stdout = p.Stdout cmd.Stderr = p.Stderr + if p.Env != nil { + cmd.Env = p.Env + } return cmd.Run() } +func (p *Cmd) CheckLinkArgs(cmdArgs []string) error { + nul := "/dev/null" + if runtime.GOOS == "windows" { + nul = "NUL" + } + args := append([]string{}, cmdArgs...) + args = append(args, []string{"-x", "c", "-o", nul, "-"}...) + src := "int main() {return 0;}" + srcIn := strings.NewReader(src) + p.Stdin = srcIn + return p.execWithFlags([]string{"LDFLAGS", "CCFLAGS"}, args...) +} + // ----------------------------------------------------------------------------- From a85d9374827fa6eea0fe1fa59e5ea47396c67f66 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 09:35:03 +0800 Subject: [PATCH 2/8] enable command tests --- cmd/llgo/llgo_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/llgo/llgo_test.go b/cmd/llgo/llgo_test.go index 87aa6f94..5c1d25b2 100644 --- a/cmd/llgo/llgo_test.go +++ b/cmd/llgo/llgo_test.go @@ -301,7 +301,7 @@ func main() { } } -func _TestCommandHandling(t *testing.T) { +func TestCommandHandling(t *testing.T) { tests := []struct { name string args []string From e6c7627ee8a0197ad211ff56093e95979313ed66 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 09:26:27 +0800 Subject: [PATCH 3/8] cross compilation --- cmd/internal/build/build.go | 5 +- internal/build/build.go | 261 +++++++++++++++++++++++------- internal/llgen/llgenf.go | 3 +- internal/xtool/llvm/llvm.go | 55 +++++++ internal/xtool/llvm/llvm_test.go | 150 +++++++++++++++++ llgo_wasm | 11 ++ ssa/cl_test.go | 10 +- ssa/datastruct.go | 2 +- ssa/package.go | 24 ++- ssa/ssa_test.go | 7 + ssa/target.go | 67 ++++---- xtool/safesplit/safesplit_test.go | 3 + 12 files changed, 496 insertions(+), 102 deletions(-) create mode 100644 internal/xtool/llvm/llvm.go create mode 100644 internal/xtool/llvm/llvm_test.go create mode 100755 llgo_wasm diff --git a/cmd/internal/build/build.go b/cmd/internal/build/build.go index a093b609..3bbde7c7 100644 --- a/cmd/internal/build/build.go +++ b/cmd/internal/build/build.go @@ -37,10 +37,7 @@ func init() { } func runCmd(cmd *base.Command, args []string) { - conf := &build.Config{ - Mode: build.ModeBuild, - AppExt: build.DefaultAppExt(), - } + conf := build.NewDefaultConf(build.ModeBuild) if len(args) >= 2 && args[0] == "-o" { conf.OutFile = args[1] args = args[2:] diff --git a/internal/build/build.go b/internal/build/build.go index c36786d5..b2bf418a 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -21,7 +21,6 @@ import ( "debug/macho" "fmt" "go/ast" - "go/build" "go/constant" "go/token" "go/types" @@ -31,6 +30,7 @@ import ( "path" "path/filepath" "runtime" + "slices" "strings" "unsafe" @@ -41,13 +41,13 @@ import ( "github.com/goplus/llgo/internal/mockable" "github.com/goplus/llgo/internal/packages" "github.com/goplus/llgo/internal/typepatch" + llvmTarget "github.com/goplus/llgo/internal/xtool/llvm" "github.com/goplus/llgo/ssa/abi" xenv "github.com/goplus/llgo/xtool/env" "github.com/goplus/llgo/xtool/env/llvm" llruntime "github.com/goplus/llgo/runtime" llssa "github.com/goplus/llgo/ssa" - clangCheck "github.com/goplus/llgo/xtool/clang/check" ) type Mode int @@ -66,6 +66,8 @@ const ( ) type Config struct { + Goos string + Goarch string BinPath string AppExt string // ".exe" on Windows, empty on Unix OutFile string // only valid for ModeBuild when len(pkgs) == 1 @@ -86,10 +88,19 @@ func NewDefaultConf(mode Mode) *Config { if err := os.MkdirAll(bin, 0755); err != nil { panic(fmt.Errorf("cannot create bin directory: %v", err)) } + goos, goarch := os.Getenv("GOOS"), os.Getenv("GOARCH") + if goos == "" { + goos = runtime.GOOS + } + if goarch == "" { + goarch = runtime.GOARCH + } conf := &Config{ + Goos: goos, + Goarch: goarch, BinPath: bin, Mode: mode, - AppExt: DefaultAppExt(), + AppExt: DefaultAppExt(goos), } return conf } @@ -105,9 +116,12 @@ func envGOPATH() (string, error) { return filepath.Join(home, "go"), nil } -func DefaultAppExt() string { - if runtime.GOOS == "windows" { +func DefaultAppExt(goos string) string { + switch goos { + case "windows": return ".exe" + case "wasi", "wasip1", "js": + return ".wasm" } return "" } @@ -121,9 +135,65 @@ const ( loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo ) +func mergeFlags(flags, extraFlags []string) (newFlags []string, tags []string) { + // Combine all flags + allFlags := append([]string{}, flags...) + allFlags = append(allFlags, extraFlags...) + + // Find all -tags flags and extract their values + tagValues := []string{} + + for i := 0; i < len(allFlags); i++ { + flag := allFlags[i] + // Handle -tags=value format + if strings.HasPrefix(flag, "-tags=") { + value := strings.TrimPrefix(flag, "-tags=") + if value != "" { + tagValues = append(tagValues, strings.Split(value, ",")...) + } + continue + } + // Handle -tags value format + if flag == "-tags" && i+1 < len(allFlags) { + i++ + value := allFlags[i] + if value != "" { + tagValues = append(tagValues, strings.Split(value, ",")...) + } + continue + } + // Keep other flags + newFlags = append(newFlags, flag) + } + // Add combined -tags flag if we found any tag values + if len(tagValues) > 0 { + // Remove duplicates + uniqueTags := make([]string, 0, len(tagValues)) + seen := make(map[string]bool) + for _, tag := range tagValues { + tag = strings.TrimSpace(tag) + if tag != "" && !seen[tag] { + seen[tag] = true + uniqueTags = append(uniqueTags, tag) + } + } + if len(uniqueTags) > 0 { + newFlags = append(newFlags, "-tags", strings.Join(uniqueTags, ",")) + tags = []string{"-tags", strings.Join(uniqueTags, ",")} + } + } + return newFlags, tags +} + func Do(args []string, conf *Config) ([]Package, error) { + if conf.Goos == "" { + conf.Goos = runtime.GOOS + } + if conf.Goarch == "" { + conf.Goarch = runtime.GOARCH + } flags, patterns, verbose := ParseArgs(args, buildFlags) - flags = append(flags, "-tags", "llgo") + flags, _ = mergeFlags(flags, []string{"-tags", "llgo"}) cfg := &packages.Config{ Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile, BuildFlags: flags, @@ -148,8 +218,8 @@ func Do(args []string, conf *Config) ([]Package, error) { llssa.Initialize(llssa.InitAll) target := &llssa.Target{ - GOOS: build.Default.GOOS, - GOARCH: build.Default.GOARCH, + GOOS: conf.Goos, + GOARCH: conf.Goarch, } prog := llssa.NewProgram(target) @@ -221,7 +291,7 @@ func Do(args []string, conf *Config) ([]Package, error) { os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows output := conf.OutFile != "" - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool)} + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), conf} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -286,6 +356,8 @@ type context struct { needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool + + buildConf *Config } func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage, err error) { @@ -364,7 +436,7 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs ctx.nLibdir++ } } - if err := clangCheck.CheckLinkArgs(pkgLinkArgs); err != nil { + if err := ctx.env.Clang().CheckLinkArgs(pkgLinkArgs); err != nil { panic(fmt.Sprintf("test link args '%s' failed\n\texpanded to: %v\n\tresolved to: %v\n\terror: %v", param, expdArgs, pkgLinkArgs, err)) } aPkg.LinkArgs = append(aPkg.LinkArgs, pkgLinkArgs...) @@ -401,39 +473,18 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs } else { app = filepath.Join(conf.BinPath, name+conf.AppExt) } + } else if !strings.HasSuffix(app, conf.AppExt) { + app += conf.AppExt } + + // Start with output file argument args := make([]string, 0, len(pkg.Imports)+len(linkArgs)+16) - args = append( - args, - "-o", app, - "-Wl,--error-limit=0", - "-fuse-ld=lld", - "-Wno-override-module", - // "-O2", // FIXME: This will cause TestFinalizer in _test/bdwgc.go to fail on macOS. - ) - switch runtime.GOOS { - case "darwin": // ld64.lld (macOS) - args = append( - args, - "-rpath", "@loader_path", - "-rpath", "@loader_path/../lib", - "-Xlinker", "-dead_strip", - ) - case "windows": // lld-link (Windows) - // TODO: Add options for Windows. - default: // ld.lld (Unix), wasm-ld (WebAssembly) - args = append( - args, - "-rpath", "$ORIGIN", - "-rpath", "$ORIGIN/../lib", - "-fdata-sections", - "-ffunction-sections", - "-Xlinker", "--gc-sections", - "-lm", - "-latomic", - "-lpthread", // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions. - ) - } + args = append(args, "-o", app) + + // Add common linker arguments based on target OS and architecture + targetTriple := llvmTarget.GetTargetTriple(conf.Goos, conf.Goarch) + args = append(args, buildLdflags(conf.Goos, conf.Goarch, targetTriple)...) + needRuntime := false needPyInit := false pkgsMap := make(map[*packages.Package]*aPackage, len(pkgs)) @@ -453,7 +504,7 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs } } }) - entryLLFile, err := genMainModuleFile(llssa.PkgRuntime, pkg.PkgPath, needRuntime, needPyInit) + entryLLFile, err := genMainModuleFile(conf, llssa.PkgRuntime, pkg.PkgPath, needRuntime, needPyInit) if err != nil { panic(err) } @@ -478,11 +529,13 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs // add rpath and find libs exargs := make([]string, 0, ctx.nLibdir<<1) libs := make([]string, 0, ctx.nLibdir*3) - for _, arg := range args { - if strings.HasPrefix(arg, "-L") { - exargs = append(exargs, "-rpath", arg[2:]) - } else if strings.HasPrefix(arg, "-l") { - libs = append(libs, arg[2:]) + if IsRpathChangeEnabled() { + for _, arg := range args { + if strings.HasPrefix(arg, "-L") { + exargs = append(exargs, "-rpath", arg[2:]) + } else if strings.HasPrefix(arg, "-l") { + libs = append(libs, arg[2:]) + } } } args = append(args, exargs...) @@ -490,14 +543,12 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs args = append(args, "-gdwarf-4") } - // TODO(xsw): show work - if verbose { - fmt.Fprintln(os.Stderr, "clang", args) - } - err = ctx.env.Clang().Link(args...) + cmd := ctx.env.Clang() + cmd.Verbose = verbose + err = cmd.Link(args...) check(err) - if IsRpathChangeEnabled() && runtime.GOOS == "darwin" { + if IsRpathChangeEnabled() && conf.Goos == "darwin" { dylibDeps := make([]string, 0, len(libs)) for _, lib := range libs { dylibDep := findDylibDep(app, lib) @@ -519,7 +570,16 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs fmt.Fprintf(os.Stderr, "%s: exit code %d\n", app, s.ExitCode()) } case ModeRun: - cmd := exec.Command(app, conf.RunArgs...) + args := make([]string, 0, len(conf.RunArgs)+1) + copy(args, conf.RunArgs) + if isWasmTarget(conf.Goos) { + args = append(args, app, "--wasm", "multi-memory=true") + args = append(args, conf.RunArgs...) + app = "wasmtime" + } else { + args = conf.RunArgs + } + cmd := exec.Command(app, args...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -532,7 +592,84 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs } } -func genMainModuleFile(rtPkgPath, mainPkgPath string, needRuntime, needPyInit bool) (path string, err error) { +func buildCflags(goos, goarch, targetTriple string) []string { + args := []string{} + if goarch == "wasm" { + args = append(args, "-target", targetTriple) + } + return args +} + +// buildLdflags builds the common linker arguments based on target OS and architecture +func buildLdflags(goos, goarch, targetTriple string) []string { + args := []string{ + "-target", targetTriple, + "-Wno-override-module", + } + if goos == runtime.GOOS { + // Non-cross-compile + args = append(args, + "-Wl,--error-limit=0", + "-fuse-ld=lld", + "-Wno-override-module", + ) + } + + switch goos { + case "darwin": // ld64.lld (macOS) + if IsRpathChangeEnabled() { + args = append( + args, + "-rpath", "@loader_path", + "-rpath", "@loader_path/../lib", + ) + } + args = append( + args, + "-Xlinker", "-dead_strip", + ) + case "windows": // lld-link (Windows) + // TODO(xsw): Add options for Windows. + case "wasi", "wasip1", "js": // wasm-ld (WebAssembly) + args = append( + args, + "-fdata-sections", + "-ffunction-sections", + // "-nostdlib", + // "-Wl,--no-entry", + "-Wl,--export-all", + "-Wl,--allow-undefined", + // "-Wl,--import-memory,", + "-Wl,--export-memory", + "-Wl,--initial-memory=16777216", // 16MB + // "-pthread", + // "-matomics", + // "-mbulk-memory", + // "-mmultimemory", + ) + default: // ld.lld (Unix) + args = append( + args, + // "-rpath", "$ORIGIN", + // "-rpath", "$ORIGIN/../lib", + "-fdata-sections", + "-ffunction-sections", + "-Xlinker", + "--gc-sections", + "-lm", + "-latomic", + "-lpthread", // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions. + ) + } + + return args +} + +func isWasmTarget(goos string) bool { + return slices.Contains([]string{"wasi", "js", "wasip1"}, goos) +} + +func genMainModuleFile(conf *Config, rtPkgPath, mainPkgPath string, needRuntime, needPyInit bool) (path string, err error) { var ( pyInitDecl string pyInit string @@ -547,6 +684,10 @@ func genMainModuleFile(rtPkgPath, mainPkgPath string, needRuntime, needPyInit bo pyInit = "call void @Py_Initialize()" pyInitDecl = "declare void @Py_Initialize()" } + mainDefine := "define i32 @main(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr" + if isWasmTarget(conf.Goos) { + mainDefine = "define hidden noundef i32 @__main_argc_argv(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr" + } mainCode := fmt.Sprintf(`; ModuleID = 'main' source_filename = "main" @@ -566,7 +707,7 @@ define weak void @"syscall.init"() { ret void } -define i32 @main(i32 %%0, ptr %%1) { +%s { _llgo_0: %s store i32 %%0, ptr @__llgo_argc, align 4 @@ -577,7 +718,7 @@ _llgo_0: call void @"%s.main"() ret i32 0 } -`, pyInitDecl, rtInitDecl, mainPkgPath, mainPkgPath, +`, pyInitDecl, rtInitDecl, mainPkgPath, mainPkgPath, mainDefine, pyInit, rtInit, mainPkgPath, mainPkgPath) f, err := os.CreateTemp("", "main*.ll") @@ -877,11 +1018,15 @@ func clFiles(ctx *context, files string, pkg *packages.Package, procFile func(li func clFile(ctx *context, args []string, cFile, expFile string, procFile func(linkFile string), verbose bool) { llFile := expFile + filepath.Base(cFile) + ".ll" + targetTriple := llvmTarget.GetTargetTriple(ctx.buildConf.Goos, ctx.buildConf.Goarch) + cflags := buildCflags(ctx.buildConf.Goos, ctx.buildConf.Goarch, targetTriple) + args = append(cflags, args...) args = append(args, "-emit-llvm", "-S", "-o", llFile, "-c", cFile) if verbose { fmt.Fprintln(os.Stderr, "clang", args) } - err := ctx.env.Clang().Compile(args...) + cmd := ctx.env.Clang() + err := cmd.Compile(args...) check(err) procFile(llFile) } diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 2e33ee67..55e5d5af 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -20,6 +20,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" "github.com/goplus/llgo/internal/build" @@ -46,7 +47,7 @@ func genFrom(pkgPath string) (build.Package, error) { conf := &build.Config{ Mode: build.ModeGen, - AppExt: build.DefaultAppExt(), + AppExt: build.DefaultAppExt(runtime.GOOS), } pkgs, err := build.Do([]string{pkgPath}, conf) if err != nil { diff --git a/internal/xtool/llvm/llvm.go b/internal/xtool/llvm/llvm.go new file mode 100644 index 00000000..05fe805b --- /dev/null +++ b/internal/xtool/llvm/llvm.go @@ -0,0 +1,55 @@ +package llvm + +import "runtime" + +func GetTargetTriple(goos, goarch string) string { + var llvmarch string + if goarch == "" { + goarch = runtime.GOARCH + } + if goos == "" { + goos = runtime.GOOS + } + switch goarch { + case "386": + llvmarch = "i386" + case "amd64": + llvmarch = "x86_64" + case "arm64": + llvmarch = "aarch64" + case "arm": + switch goarch { + case "5": + llvmarch = "armv5" + case "6": + llvmarch = "armv6" + default: + llvmarch = "armv7" + } + case "wasm": + llvmarch = "wasm32" + default: + llvmarch = goarch + } + llvmvendor := "unknown" + llvmos := goos + switch goos { + case "darwin": + // Use macosx* instead of darwin, otherwise darwin/arm64 will refer + // to iOS! + llvmos = "macosx" + if llvmarch == "aarch64" { + // Looks like Apple prefers to call this architecture ARM64 + // instead of AArch64. + llvmarch = "arm64" + llvmos = "macosx" + } + llvmvendor = "apple" + case "wasip1": + llvmos = "wasip1" + } + // Target triples (which actually have four components, but are called + // triples for historical reasons) have the form: + // arch-vendor-os-environment + return llvmarch + "-" + llvmvendor + "-" + llvmos +} diff --git a/internal/xtool/llvm/llvm_test.go b/internal/xtool/llvm/llvm_test.go new file mode 100644 index 00000000..f56f2f65 --- /dev/null +++ b/internal/xtool/llvm/llvm_test.go @@ -0,0 +1,150 @@ +//go:build !llgo +// +build !llgo + +package llvm + +import ( + "os/exec" + "strings" + "testing" +) + +func TestGetTargetTriple(t *testing.T) { + // Get the list of supported architectures from clang + cmd := exec.Command("clang", "--print-targets") + output, err := cmd.Output() + if err != nil { + t.Fatalf("Failed to run clang --print-targets: %v", err) + } + + // Parse the output to get the list of supported architectures + supportedArchs := make(map[string]bool) + lines := strings.Split(string(output), "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if line != "" && !strings.HasPrefix(line, "Registered Targets:") { + // Extract the architecture from the line + parts := strings.SplitN(line, " - ", 2) + if len(parts) > 0 { + arch := strings.TrimSpace(parts[0]) + supportedArchs[arch] = true + } + } + } + + if len(supportedArchs) == 0 { + t.Fatal("No supported architectures found from clang --print-targets") + } + + t.Logf("Found %d supported architectures from clang", len(supportedArchs)) + + // Map our architecture names to clang's architecture names + clangArchMap := map[string][]string{ + "x86_64": {"x86-64", "x86_64"}, + "i386": {"x86", "i386"}, + "aarch64": {"aarch64", "arm64"}, + "arm64": {"arm64", "aarch64"}, + "armv7": {"arm", "thumb"}, + "wasm32": {"wasm32"}, + } + + // Define a function to check if the architecture is supported by clang + isArchSupported := func(archPart string) (bool, string) { + if mappedArchs, ok := clangArchMap[archPart]; ok { + for _, mappedArch := range mappedArchs { + if supportedArchs[mappedArch] { + return true, mappedArch + } + } + } else if supportedArchs[archPart] { + // Direct match + return true, archPart + } + return false, "" + } + + // Define a function to verify OS name + isOSValid := func(os, goos string) bool { + validOSMap := map[string][]string{ + "linux": {"linux", "linux-gnu"}, + "darwin": {"macosx", "darwin"}, + "windows": {"windows", "win32"}, + "wasip1": {"wasip1", "wasi"}, + "js": {"js", "javascript"}, + } + + if validVariants, ok := validOSMap[goos]; ok { + for _, validVariant := range validVariants { + if strings.HasPrefix(os, validVariant) { + return true + } + } + } + return false + } + + // Define a function to check if vendor is valid + isVendorValid := func(vendor string) bool { + validVendors := map[string]bool{ + "unknown": true, + "apple": true, + "pc": true, + "ibm": true, + } + return validVendors[vendor] + } + + // Define the test function + checkTriple := func(t *testing.T, testName, goos, goarch, expected string) { + t.Helper() + got := GetTargetTriple(goos, goarch) + + // Check if the generated triple matches the expected value + if got != expected { + t.Errorf("getTargetTriple(%q, %q) = %q, want %q", + goos, goarch, got, expected) + } + + // Extract the architecture part from the triple (first component) + parts := strings.Split(got, "-") + if len(parts) < 3 { + t.Errorf("Invalid target triple format: %s, should have at least 3 components", got) + return + } + + archPart := parts[0] + vendor := parts[1] + os := parts[2] + + // Check if the architecture is supported by clang + supported, mappedArch := isArchSupported(archPart) + if supported { + t.Logf("Architecture %s (mapped to %s) is supported by clang", archPart, mappedArch) + } else { + t.Logf("WARNING: Architecture %s from triple %q for %s/%s not found in clang's supported architectures", + archPart, got, goos, goarch) + } + + // Verify vendor + if !isVendorValid(vendor) { + t.Errorf("Invalid vendor in triple: %s", vendor) + } + + // Verify OS + if !isOSValid(os, goos) { + t.Errorf("OS in triple %q doesn't match expected OS %q", os, goos) + } + } + + // Run tests for different OS/arch combinations + checkTriple(t, "wasip1/wasm", "wasip1", "wasm", "wasm32-unknown-wasip1") + checkTriple(t, "linux/amd64", "linux", "amd64", "x86_64-unknown-linux") + checkTriple(t, "linux/386", "linux", "386", "i386-unknown-linux") + checkTriple(t, "linux/arm64", "linux", "arm64", "aarch64-unknown-linux") + checkTriple(t, "linux/arm", "linux", "arm", "armv7-unknown-linux") + checkTriple(t, "darwin/amd64", "darwin", "amd64", "x86_64-apple-macosx") + checkTriple(t, "darwin/arm64", "darwin", "arm64", "arm64-apple-macosx") + checkTriple(t, "windows/amd64", "windows", "amd64", "x86_64-unknown-windows") + checkTriple(t, "windows/386", "windows", "386", "i386-unknown-windows") + checkTriple(t, "js/wasm", "js", "wasm", "wasm32-unknown-js") +} diff --git a/llgo_wasm b/llgo_wasm new file mode 100755 index 00000000..5232313f --- /dev/null +++ b/llgo_wasm @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +WORKDIR='' +WORKDIR=$(pwd) +LLGO_ROOT='' +LLGO_ROOT=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd ) +export LLGO_ROOT +cd $LLGO_ROOT +go install ./cmd/llgo +cd $WORKDIR +GOOS=wasip1 GOARCH=wasm llgo "$@" diff --git a/ssa/cl_test.go b/ssa/cl_test.go index 7294cc34..c49aad3e 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -24,6 +24,8 @@ import ( "go/types" "io" "log" + "os" + "runtime" "testing" "github.com/goplus/llgo/cl/cltest" @@ -65,7 +67,13 @@ func TestFromTestdata(t *testing.T) { } func TestMakeInterface(t *testing.T) { - prog := ssatest.NewProgram(t, &ssa.Target{GOARCH: "x86"}) + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + os.Chdir("../runtime") + defer os.Chdir(wd) + prog := ssatest.NewProgram(t, &ssa.Target{GOARCH: runtime.GOARCH}) pkg := prog.NewPackage("foo", "foo") fn := pkg.NewFunc("main", types.NewSignatureType(nil, nil, nil, nil, nil, false), ssa.InC) b := fn.MakeBody(1) diff --git a/ssa/datastruct.go b/ssa/datastruct.go index dedc081c..32cbaa6f 100644 --- a/ssa/datastruct.go +++ b/ssa/datastruct.go @@ -245,7 +245,7 @@ func (b Builder) checkIndex(idx Expr, max Expr) Expr { } else { typ = prog.Uint() } - if prog.SizeOf(idx.Type) < prog.SizeOf(typ) { + if prog.SizeOf(idx.Type) != prog.SizeOf(typ) { idx.Type = typ idx.impl = castUintptr(b, idx.impl, typ) } diff --git a/ssa/package.go b/ssa/package.go index 8c23515e..cee0bbd3 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -210,6 +210,22 @@ type aProgram struct { // A Program presents a program. type Program = *aProgram +var arch32 = map[string]bool{ + "386": true, + "arm": true, + "mips": true, + "mipsle": true, + "s390x": true, + "wasm": true, +} + +func is32Bits(arch string) bool { + if v, ok := arch32[arch]; ok { + return v + } + return false +} + // NewProgram creates a new program. func NewProgram(target *Target) Program { if target == nil { @@ -231,7 +247,7 @@ func NewProgram(target *Target) Program { // TODO(xsw): Finalize may cause panic, so comment it. ctx.Finalize() */ - is32Bits := (td.PointerSize() == 4 || target.GOARCH == "x86") // TODO(xsw): remove temp code + is32Bits := (td.PointerSize() == 4 || is32Bits(target.GOARCH)) return &aProgram{ ctx: ctx, gocvt: newGoTypes(), fnsCompiled: fnsCompiled, target: target, td: td, is32Bits: is32Bits, @@ -379,6 +395,12 @@ func (p Program) tyComplex128() llvm.Type { // NewPackage creates a new package. func (p Program) NewPackage(name, pkgPath string) Package { mod := p.ctx.NewModule(pkgPath) + // TODO(lijie): enable target output will check module override, but can't + // pass the snapshot test, so disable it for now + // if p.target.GOARCH != runtime.GOARCH && p.target.GOOS != runtime.GOOS { + // mod.SetTarget(p.target.Spec().Triple) + // } + // TODO(xsw): Finalize may cause panic, so comment it. // mod.Finalize() gbls := make(map[string]Global) diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 2f88a7fa..b61fb624 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -23,6 +23,7 @@ import ( "go/constant" "go/token" "go/types" + "os" "testing" "unsafe" @@ -40,6 +41,12 @@ func TestEndDefer(t *testing.T) { } func TestUnsafeString(t *testing.T) { + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + os.Chdir("../../runtime") + defer os.Chdir(wd) prog := NewProgram(nil) prog.SetRuntime(func() *types.Package { fset := token.NewFileSet() diff --git a/ssa/target.go b/ssa/target.go index 77e27b9b..9b998024 100644 --- a/ssa/target.go +++ b/ssa/target.go @@ -17,6 +17,8 @@ package ssa import ( + "runtime" + "github.com/goplus/llvm" ) @@ -29,15 +31,15 @@ type Target struct { } func (p *Target) targetData() llvm.TargetData { - spec := p.toSpec() - if spec.triple == "" { - spec.triple = llvm.DefaultTargetTriple() + spec := p.Spec() + if spec.Triple == "" { + spec.Triple = llvm.DefaultTargetTriple() } - t, err := llvm.GetTargetFromTriple(spec.triple) + t, err := llvm.GetTargetFromTriple(spec.Triple) if err != nil { panic(err) } - machine := t.CreateTargetMachine(spec.triple, spec.cpu, spec.features, llvm.CodeGenLevelDefault, llvm.RelocDefault, llvm.CodeModelDefault) + machine := t.CreateTargetMachine(spec.Triple, spec.CPU, spec.Features, llvm.CodeGenLevelDefault, llvm.RelocDefault, llvm.CodeModelDefault) return machine.CreateTargetData() } @@ -62,19 +64,13 @@ func (p *Program) targetMachine() llvm.TargetMachine { } */ -type targetSpec struct { - triple string - cpu string - features string +type TargetSpec struct { + Triple string + CPU string + Features string } -// TODO config -func (p *Target) toSpec() (spec targetSpec) { - return -} - -/* -func (p *Target) toSpec() (spec targetSpec) { +func (p *Target) Spec() (spec TargetSpec) { // Configure based on GOOS/GOARCH environment variables (falling back to // runtime.GOOS/runtime.GOARCH), and generate a LLVM target based on it. var llvmarch string @@ -113,56 +109,55 @@ func (p *Target) toSpec() (spec targetSpec) { case "darwin": // Use macosx* instead of darwin, otherwise darwin/arm64 will refer // to iOS! - llvmos = "macosx10.12.0" + llvmos = "macosx" if llvmarch == "aarch64" { // Looks like Apple prefers to call this architecture ARM64 // instead of AArch64. llvmarch = "arm64" - llvmos = "macosx11.0.0" + llvmos = "macosx" } llvmvendor = "apple" case "wasip1": - llvmos = "wasi" + llvmos = "wasip1" } // Target triples (which actually have four components, but are called // triples for historical reasons) have the form: // arch-vendor-os-environment - spec.triple = llvmarch + "-" + llvmvendor + "-" + llvmos + spec.Triple = llvmarch + "-" + llvmvendor + "-" + llvmos if llvmos == "windows" { - spec.triple += "-gnu" + spec.Triple += "-gnu" } else if goarch == "arm" { - spec.triple += "-gnueabihf" + spec.Triple += "-gnueabihf" } switch goarch { case "386": - spec.cpu = "pentium4" - spec.features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87" + spec.CPU = "pentium4" + spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87" case "amd64": - spec.cpu = "x86-64" - spec.features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87" + spec.CPU = "x86-64" + spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87" case "arm": - spec.cpu = "generic" + spec.CPU = "generic" switch llvmarch { case "armv5": - spec.features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" + spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" case "armv6": - spec.features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" + spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" case "armv7": - spec.features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" + spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" } case "arm64": - spec.cpu = "generic" + spec.CPU = "generic" if goos == "darwin" { - spec.features = "+neon" + spec.Features = "+neon" } else { // windows, linux - spec.features = "+neon,-fmv" + spec.Features = "+neon,-fmv" } case "wasm": - spec.cpu = "generic" - spec.features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" + spec.CPU = "generic" + spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } return } -*/ // ----------------------------------------------------------------------------- diff --git a/xtool/safesplit/safesplit_test.go b/xtool/safesplit/safesplit_test.go index 93eb953d..cbb8c9cc 100644 --- a/xtool/safesplit/safesplit_test.go +++ b/xtool/safesplit/safesplit_test.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + /* * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. * From f35063ee6ed43edab911d4e0e86f8b84ff18ad73 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 10:18:50 +0800 Subject: [PATCH 4/8] build: download and compile with wasi-sdk --- internal/build/build.go | 13 +- internal/crosscompile/cosscompile.go | 62 ++++++++ internal/crosscompile/crosscompile_test.go | 156 +++++++++++++++++++++ internal/crosscompile/fetch.go | 109 ++++++++++++++ internal/env/env.go | 8 ++ 5 files changed, 346 insertions(+), 2 deletions(-) create mode 100644 internal/crosscompile/cosscompile.go create mode 100644 internal/crosscompile/crosscompile_test.go create mode 100644 internal/crosscompile/fetch.go diff --git a/internal/build/build.go b/internal/build/build.go index b2bf418a..d29b130d 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -37,6 +37,7 @@ import ( "golang.org/x/tools/go/ssa" "github.com/goplus/llgo/cl" + "github.com/goplus/llgo/internal/crosscompile" "github.com/goplus/llgo/internal/env" "github.com/goplus/llgo/internal/mockable" "github.com/goplus/llgo/internal/packages" @@ -291,7 +292,9 @@ func Do(args []string, conf *Config) ([]Package, error) { os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows output := conf.OutFile != "" - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), conf} + export, err := crosscompile.UseCrossCompileSDK(conf.Goos, conf.Goarch) + check(err) + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), conf, export} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -357,7 +360,8 @@ type context struct { needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool - buildConf *Config + buildConf *Config + crossCompile crosscompile.Export } func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage, err error) { @@ -543,6 +547,9 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs args = append(args, "-gdwarf-4") } + args = append(args, ctx.crossCompile.CCFLAGS...) + args = append(args, ctx.crossCompile.LDFLAGS...) + cmd := ctx.env.Clang() cmd.Verbose = verbose err = cmd.Link(args...) @@ -1022,6 +1029,8 @@ func clFile(ctx *context, args []string, cFile, expFile string, procFile func(li cflags := buildCflags(ctx.buildConf.Goos, ctx.buildConf.Goarch, targetTriple) args = append(cflags, args...) args = append(args, "-emit-llvm", "-S", "-o", llFile, "-c", cFile) + args = append(args, ctx.crossCompile.CCFLAGS...) + args = append(args, ctx.crossCompile.CFLAGS...) if verbose { fmt.Fprintln(os.Stderr, "clang", args) } diff --git a/internal/crosscompile/cosscompile.go b/internal/crosscompile/cosscompile.go new file mode 100644 index 00000000..f71a96a9 --- /dev/null +++ b/internal/crosscompile/cosscompile.go @@ -0,0 +1,62 @@ +package crosscompile + +import ( + "errors" + "io/fs" + "os" + "path/filepath" + "runtime" + + "github.com/goplus/llgo/internal/env" + "github.com/goplus/llgo/internal/xtool/llvm" +) + +type Export struct { + CCFLAGS []string + CFLAGS []string + LDFLAGS []string +} + +const wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz" + +func cacheDir() string { + return filepath.Join(env.LLGoCacheDir(), "crosscompile") +} + +func UseCrossCompileSDK(goos, goarch string) (export Export, err error) { + if runtime.GOOS == goos && runtime.GOARCH == goarch { + // not cross compile + return + } + if goarch == "wasm" { + sdkDir := filepath.Join(cacheDir(), llvm.GetTargetTriple(goos, goarch)) + if _, err = os.Stat(sdkDir); err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return + } + if err = downloadAndExtract(wasiSdkUrl, sdkDir); err != nil { + return + } + } + // Set up flags for the SDK + wasiSdkRoot := filepath.Join(sdkDir, "wasi-sdk-25.0-x86_64-macos") + sysrootDir := filepath.Join(wasiSdkRoot, "share", "wasi-sysroot") + libclangDir := filepath.Join(wasiSdkRoot, "lib", "clang", "19") + includeDir := filepath.Join(sysrootDir, "include", "wasm32-wasip1") + libDir := filepath.Join(sysrootDir, "lib", "wasm32-wasip1") + + export.CCFLAGS = []string{ + "--sysroot=" + sysrootDir, + "-resource-dir=" + libclangDir, + } + export.CFLAGS = []string{ + "-I" + includeDir, + } + export.LDFLAGS = []string{ + "-L" + libDir, + } + return + } + // TODO(lijie): supports other platforms + return +} diff --git a/internal/crosscompile/crosscompile_test.go b/internal/crosscompile/crosscompile_test.go new file mode 100644 index 00000000..35ffa192 --- /dev/null +++ b/internal/crosscompile/crosscompile_test.go @@ -0,0 +1,156 @@ +//go:build !llgo +// +build !llgo + +package crosscompile + +import ( + "os" + "runtime" + "testing" +) + +const ( + sysrootPrefix = "--sysroot=" + resourceDirPrefix = "-resource-dir=" + includePrefix = "-I" + libPrefix = "-L" +) + +func TestUseCrossCompileSDK(t *testing.T) { + // Skip long-running tests unless explicitly enabled + if testing.Short() { + t.Skip("Skipping test in short mode") + } + + // Test cases + testCases := []struct { + name string + goos string + goarch string + expectSDK bool + expectCCFlags bool + expectCFlags bool + expectLDFlags bool + }{ + { + name: "Same Platform", + goos: runtime.GOOS, + goarch: runtime.GOARCH, + expectSDK: false, + expectCCFlags: false, + expectCFlags: false, + expectLDFlags: false, + }, + { + name: "WASM Target", + goos: "wasip1", + goarch: "wasm", + expectSDK: true, + expectCCFlags: true, + expectCFlags: true, + expectLDFlags: true, + }, + { + name: "Unsupported Target", + goos: "windows", + goarch: "amd64", + expectSDK: false, + expectCCFlags: false, + expectCFlags: false, + expectLDFlags: false, + }, + } + + // Create a temporary directory for the cache + tempDir, err := os.MkdirTemp("", "crosscompile_test") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + defer os.RemoveAll(tempDir) + + // Set environment variable for cache directory + oldEnv := os.Getenv("LLGO_CACHE_DIR") + os.Setenv("LLGO_CACHE_DIR", tempDir) + defer os.Setenv("LLGO_CACHE_DIR", oldEnv) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + export, err := UseCrossCompileSDK(tc.goos, tc.goarch) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + t.Logf("export: %+v", export) + + if tc.expectSDK { + // Check if flags are set correctly + if tc.expectCCFlags && len(export.CCFLAGS) == 0 { + t.Error("Expected CCFLAGS to be set, but they are empty") + } + + if tc.expectCFlags && len(export.CFLAGS) == 0 { + t.Error("Expected CFLAGS to be set, but they are empty") + } + + if tc.expectLDFlags && len(export.LDFLAGS) == 0 { + t.Error("Expected LDFLAGS to be set, but they are empty") + } + + // Check for specific flags + if tc.expectCCFlags { + hasSysroot := false + hasResourceDir := false + + for _, flag := range export.CCFLAGS { + if len(flag) >= len(sysrootPrefix) && flag[:len(sysrootPrefix)] == sysrootPrefix { + hasSysroot = true + } + if len(flag) >= len(resourceDirPrefix) && flag[:len(resourceDirPrefix)] == resourceDirPrefix { + hasResourceDir = true + } + } + + if !hasSysroot { + t.Error("Missing --sysroot flag in CCFLAGS") + } + if !hasResourceDir { + t.Error("Missing -resource-dir flag in CCFLAGS") + } + } + + if tc.expectCFlags { + hasInclude := false + + for _, flag := range export.CFLAGS { + if len(flag) >= len(includePrefix) && flag[:len(includePrefix)] == includePrefix { + hasInclude = true + } + } + + if !hasInclude { + t.Error("Missing -I flag in CFLAGS") + } + } + + if tc.expectLDFlags { + hasLib := false + + for _, flag := range export.LDFLAGS { + if len(flag) >= len(libPrefix) && flag[:len(libPrefix)] == libPrefix { + hasLib = true + } + } + + if !hasLib { + t.Error("Missing -L flag in LDFLAGS") + } + } + } else { + if len(export.CCFLAGS) != 0 || len(export.CFLAGS) != 0 || len(export.LDFLAGS) != 0 { + t.Errorf("Expected empty export, got CCFLAGS=%v, CFLAGS=%v, LDFLAGS=%v", + export.CCFLAGS, export.CFLAGS, export.LDFLAGS) + } + } + }) + } +} diff --git a/internal/crosscompile/fetch.go b/internal/crosscompile/fetch.go new file mode 100644 index 00000000..edd556a7 --- /dev/null +++ b/internal/crosscompile/fetch.go @@ -0,0 +1,109 @@ +package crosscompile + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strings" +) + +func downloadAndExtract(url, dir string) (err error) { + if _, err = os.Stat(dir); err == nil { + os.RemoveAll(dir) + } + tempDir := dir + ".temp" + os.RemoveAll(tempDir) + if err = os.MkdirAll(tempDir, 0755); err != nil { + return fmt.Errorf("failed to create temporary directory: %w", err) + } + + urlPath := strings.Split(url, "/") + filename := urlPath[len(urlPath)-1] + localFile := filepath.Join(tempDir, filename) + if err = downloadFile(url, localFile); err != nil { + return fmt.Errorf("failed to download file: %w", err) + } + defer os.Remove(localFile) + + if strings.HasSuffix(filename, ".tar.gz") || strings.HasSuffix(filename, ".tgz") { + err = extractTarGz(localFile, tempDir) + } else { + return fmt.Errorf("unsupported archive format: %s", filename) + } + if err != nil { + return fmt.Errorf("failed to extract archive: %w", err) + } + if err = os.Rename(tempDir, dir); err != nil { + return fmt.Errorf("failed to rename directory: %w", err) + } + return nil +} + +func downloadFile(url, filepath string) error { + out, err := os.Create(filepath) + if err != nil { + return err + } + defer out.Close() + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("bad status: %s", resp.Status) + } + _, err = io.Copy(out, resp.Body) + return err +} + +func extractTarGz(tarGzFile, dest string) error { + file, err := os.Open(tarGzFile) + if err != nil { + return err + } + defer file.Close() + gzr, err := gzip.NewReader(file) + if err != nil { + return err + } + defer gzr.Close() + tr := tar.NewReader(gzr) + for { + header, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + target := filepath.Join(dest, header.Name) + if !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) { + return fmt.Errorf("%s: illegal file path", target) + } + switch header.Typeflag { + case tar.TypeDir: + if err := os.MkdirAll(target, 0755); err != nil { + return err + } + case tar.TypeReg: + if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { + return err + } + f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) + if err != nil { + return err + } + if _, err := io.Copy(f, tr); err != nil { + f.Close() + return err + } + f.Close() + } + } + return nil +} diff --git a/internal/env/env.go b/internal/env/env.go index f28fd8ae..5d602e90 100644 --- a/internal/env/env.go +++ b/internal/env/env.go @@ -32,6 +32,14 @@ func GOROOT() string { panic("cannot get GOROOT: " + err.Error()) } +func LLGoCacheDir() string { + userCacheDir, err := os.UserCacheDir() + if err != nil { + panic(err) + } + return filepath.Join(userCacheDir, "llgo") +} + func LLGoRuntimeDir() string { root := LLGoROOT() if root != "" { From f0ade21155bf27281ee9764b9ed00b827f0dd429 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 09:36:48 +0800 Subject: [PATCH 5/8] update docs and CI --- .github/actions/setup-deps/action.yml | 4 +- .github/workflows/doc.yml | 13 ++++--- .github/workflows/fmt.yml | 6 +-- .github/workflows/go.yml | 2 +- .github/workflows/llgo.yml | 55 ++++++++++++++++++++++++--- README.md | 2 +- _demo/helloc/helloc.go | 15 ++++++++ doc/_readme/scripts/install_macos.sh | 2 +- 8 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 _demo/helloc/helloc.go diff --git a/.github/actions/setup-deps/action.yml b/.github/actions/setup-deps/action.yml index a410db3f..5ab296b2 100644 --- a/.github/actions/setup-deps/action.yml +++ b/.github/actions/setup-deps/action.yml @@ -15,7 +15,7 @@ runs: run: | brew update brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} bdw-gc openssl libffi libuv - brew link --overwrite lld@${{inputs.llvm-version}} libffi + brew link --overwrite llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} libffi echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH # Install optional deps for demos. @@ -35,7 +35,7 @@ runs: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update sudo apt-get install -y llvm-${{inputs.llvm-version}}-dev clang-${{inputs.llvm-version}} libclang-${{inputs.llvm-version}}-dev lld-${{inputs.llvm-version}} pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libunwind-dev libuv1-dev - echo "/usr/lib/llvm-${{inputs.llvm-version}}/bin" >> $GITHUB_PATH + echo "PATH=/usr/lib/llvm-${{inputs.llvm-version}}/bin:$PATH" >> $GITHUB_ENV # Install optional deps for demos. # diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 7ac6f345..c65daa1f 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -2,9 +2,9 @@ name: Docs on: push: - branches: [ "**" ] + branches: ["**"] pull_request: - branches: [ "**" ] + branches: ["**"] jobs: doc_verify: @@ -15,7 +15,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: "20" - name: Install embedme run: npm install -g embedme @@ -43,7 +43,7 @@ jobs: - name: Set up Go uses: ./.github/actions/setup-go with: - go-version: '1.23.6' + go-version: "1.24.2" - name: Install dependencies on macOS if: startsWith(matrix.os, 'macos') @@ -79,7 +79,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.23' + go-version: "1.23" - name: Install dependencies on macOS if: startsWith(matrix.os, 'macos') @@ -130,7 +130,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.23' + go-version: "1.23" - name: Install dependencies on macOS if: startsWith(matrix.os, 'macos') @@ -145,6 +145,7 @@ jobs: set -e set -x source doc/_readme/scripts/install_ubuntu.sh + echo "PATH=/usr/lib/llvm-19/bin:$PATH" >> $GITHUB_ENV - name: Install llgo with tools run: | diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml index 74b37271..c38293f6 100644 --- a/.github/workflows/fmt.yml +++ b/.github/workflows/fmt.yml @@ -2,9 +2,9 @@ name: Format Check on: push: - branches: [ "**" ] + branches: ["**"] pull_request: - branches: [ "**" ] + branches: ["**"] jobs: fmt: @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: ./.github/actions/setup-go with: - go-version: '1.24.0' + go-version: "1.24.2" - name: Check formatting run: | diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 8806c3e5..2cb18175 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -35,7 +35,7 @@ jobs: - name: Set up Go uses: ./.github/actions/setup-go with: - go-version: "1.24.0" + go-version: "1.24.2" - name: Build run: go build -v ./... diff --git a/.github/workflows/llgo.yml b/.github/workflows/llgo.yml index ad4b0def..de57fe9b 100644 --- a/.github/workflows/llgo.yml +++ b/.github/workflows/llgo.yml @@ -34,7 +34,7 @@ jobs: - macos-latest - ubuntu-24.04 llvm: [19] - go: ['1.21.13', '1.22.12', '1.23.6', '1.24.0'] + go: ["1.21.13", "1.22.12", "1.23.6", "1.24.2"] runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 @@ -58,7 +58,7 @@ jobs: - name: Set up Go for build uses: ./.github/actions/setup-go with: - go-version: "1.24.0" + go-version: "1.24.2" - name: Install run: | @@ -105,7 +105,7 @@ jobs: - macos-latest - ubuntu-24.04 llvm: [19] - go: ["1.24.0"] + go: ["1.24.2"] runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 @@ -124,7 +124,7 @@ jobs: - name: Set up Go for build uses: ./.github/actions/setup-go with: - go-version: "1.24.0" + go-version: "1.24.2" - name: Install run: | @@ -146,7 +146,7 @@ jobs: matrix: os: [ubuntu-24.04, macos-latest] llvm: [19] - go: ['1.21.13', '1.22.12', '1.23.6', '1.24.0'] + go: ["1.21.13", "1.22.12", "1.23.6", "1.24.2"] runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 @@ -158,7 +158,7 @@ jobs: - name: Set up Go 1.23 for building llgo uses: ./.github/actions/setup-go with: - go-version: "1.24.0" + go-version: "1.24.2" - name: Install llgo run: | @@ -197,3 +197,46 @@ jobs: with: go-version: ${{matrix.go}} mod-version: "1.24" + + cross-compile: + continue-on-error: true + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + uses: ./.github/actions/setup-deps + with: + llvm-version: 19 + + - name: Set up Go for building llgo + uses: ./.github/actions/setup-go + with: + go-version: "1.24.2" + + - name: Install wasmtime and wasi-libc + run: | + brew install wasmtime + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/libclang_rt.builtins-wasm32-wasi-25.0.tar.gz + tar -xvf libclang_rt.builtins-wasm32-wasi-25.0.tar.gz + mkdir -p `llvm-config --libdir`/clang/19/lib/wasi/ + mv libclang_rt.builtins-wasm32-wasi-25.0/libclang_rt.builtins-wasm32.a `llvm-config --libdir`/clang/19/lib/wasi/ + + - name: Install llgo + run: | + go install ./... + echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV + + - name: Test Cross Compilation (wasm) + shell: bash + working-directory: _demo + run: | + echo "Testing cross-compilation wasm with Go 1.24.2" + + # Compile for wasm architecture + GOOS=wasip1 GOARCH=wasm llgo build -o hello -v ./helloc + + # Check file type + file hello.wasm + + # Run the wasm binary using llgo_wasm + wasmtime hello.wasm diff --git a/README.md b/README.md index 7219f216..d1910c00 100644 --- a/README.md +++ b/README.md @@ -361,7 +361,7 @@ Follow these steps to generate the `llgo` command (its usage is the same as the brew update brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config brew install python@3.12 # optional -brew link --overwrite lld@19 libffi +brew link --overwrite llvm@19 lld@19 libffi # curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash ./install.sh ``` diff --git a/_demo/helloc/helloc.go b/_demo/helloc/helloc.go new file mode 100644 index 00000000..158a99ba --- /dev/null +++ b/_demo/helloc/helloc.go @@ -0,0 +1,15 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/lib/c" +) + +func main() { + c.Printf(c.Str("Hello world by c.Printf\n")) + c.Printf(c.Str("%ld\n"), unsafe.Sizeof(int(0))) + c.Printf(c.Str("%ld\n"), unsafe.Sizeof(uintptr(0))) + // var v any = int(0) + // c.Printf(c.Str("%ld\n"), unsafe.Sizeof(v)) +} diff --git a/doc/_readme/scripts/install_macos.sh b/doc/_readme/scripts/install_macos.sh index b6bebd35..546a8eba 100644 --- a/doc/_readme/scripts/install_macos.sh +++ b/doc/_readme/scripts/install_macos.sh @@ -2,6 +2,6 @@ brew update brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config brew install python@3.12 # optional -brew link --overwrite lld@19 libffi +brew link --overwrite llvm@19 lld@19 libffi # curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash ./install.sh \ No newline at end of file From 5f4b09bede93a426a92c7ae48501984d10baf056 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 11:00:40 +0800 Subject: [PATCH 6/8] regenerate snapshot tests --- cl/_testdata/vargs/out.ll | 4 ++-- cl/_testrt/any/out.ll | 8 ++++---- cl/_testrt/tpabi/out.ll | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cl/_testdata/vargs/out.ll b/cl/_testdata/vargs/out.ll index 2d4a4d62..df2ff24a 100644 --- a/cl/_testdata/vargs/out.ll +++ b/cl/_testdata/vargs/out.ll @@ -8,7 +8,7 @@ source_filename = "github.com/goplus/llgo/cl/_testdata/vargs" @"github.com/goplus/llgo/cl/_testdata/vargs.init$guard" = global i1 false, align 1 @_llgo_int = linkonce global ptr null, align 8 @0 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 -@1 = private unnamed_addr constant [40 x i8] c"type assertion interface{} -> int failed", align 1 +@1 = private unnamed_addr constant [32 x i8] c"type assertion any -> int failed", align 1 @_llgo_string = linkonce global ptr null, align 8 define void @"github.com/goplus/llgo/cl/_testdata/vargs.init"() { @@ -87,7 +87,7 @@ _llgo_4: ; preds = %_llgo_2 _llgo_5: ; preds = %_llgo_2 %18 = load ptr, ptr @_llgo_string, align 8 %19 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 40 }, ptr %19, align 8 + store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 32 }, ptr %19, align 8 %20 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %18, 0 %21 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %20, ptr %19, 1 call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %21) diff --git a/cl/_testrt/any/out.ll b/cl/_testrt/any/out.ll index ebc5fb54..d990852e 100644 --- a/cl/_testrt/any/out.ll +++ b/cl/_testrt/any/out.ll @@ -7,10 +7,10 @@ source_filename = "github.com/goplus/llgo/cl/_testrt/any" @"github.com/goplus/llgo/cl/_testrt/any.init$guard" = global i1 false, align 1 @_llgo_int8 = linkonce global ptr null, align 8 @"*_llgo_int8" = linkonce global ptr null, align 8 -@0 = private unnamed_addr constant [42 x i8] c"type assertion interface{} -> *int8 failed", align 1 +@0 = private unnamed_addr constant [34 x i8] c"type assertion any -> *int8 failed", align 1 @_llgo_string = linkonce global ptr null, align 8 @_llgo_int = linkonce global ptr null, align 8 -@1 = private unnamed_addr constant [40 x i8] c"type assertion interface{} -> int failed", align 1 +@1 = private unnamed_addr constant [32 x i8] c"type assertion any -> int failed", align 1 @2 = private unnamed_addr constant [7 x i8] c"%s %d\0A\00", align 1 @3 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1 @@ -29,7 +29,7 @@ _llgo_1: ; preds = %_llgo_0 _llgo_2: ; preds = %_llgo_0 %6 = load ptr, ptr @_llgo_string, align 8 %7 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 42 }, ptr %7, align 8 + store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 34 }, ptr %7, align 8 %8 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %6, 0 %9 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %8, ptr %7, 1 call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %9) @@ -52,7 +52,7 @@ _llgo_1: ; preds = %_llgo_0 _llgo_2: ; preds = %_llgo_0 %7 = load ptr, ptr @_llgo_string, align 8 %8 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 40 }, ptr %8, align 8 + store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 32 }, ptr %8, align 8 %9 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %7, 0 %10 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %9, ptr %8, 1 call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %10) diff --git a/cl/_testrt/tpabi/out.ll b/cl/_testrt/tpabi/out.ll index 4975be4a..bdbe27d3 100644 --- a/cl/_testrt/tpabi/out.ll +++ b/cl/_testrt/tpabi/out.ll @@ -23,7 +23,7 @@ source_filename = "github.com/goplus/llgo/cl/_testrt/tpabi" @5 = private unnamed_addr constant [4 x i8] c"Demo", align 1 @"_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac" = linkonce global ptr null, align 8 @6 = private unnamed_addr constant [4 x i8] c"Info", align 1 -@7 = private unnamed_addr constant [91 x i8] c"type assertion interface{} -> github.com/goplus/llgo/cl/_testrt/tpabi.T[string, int] failed", align 1 +@7 = private unnamed_addr constant [83 x i8] c"type assertion any -> github.com/goplus/llgo/cl/_testrt/tpabi.T[string, int] failed", align 1 @8 = private unnamed_addr constant [5 x i8] c"hello", align 1 @"*_llgo_github.com/goplus/llgo/cl/_testrt/tpabi.T[string,int]" = linkonce global ptr null, align 8 @"_llgo_iface$BP0p_lUsEd-IbbtJVukGmgrdQkqzcoYzSiwgUvgFvUs" = linkonce global ptr null, align 8 @@ -107,7 +107,7 @@ _llgo_1: ; preds = %_llgo_0 _llgo_2: ; preds = %_llgo_0 %38 = load ptr, ptr @_llgo_string, align 8 %39 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16) - store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @7, i64 91 }, ptr %39, align 8 + store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @7, i64 83 }, ptr %39, align 8 %40 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %38, 0 %41 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %40, ptr %39, 1 call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %41) From 4bbc58d62db37e64a7f2d4b8149285f75a47eaa6 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 11:36:46 +0800 Subject: [PATCH 7/8] test cross compile on macos --- .github/workflows/llgo.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/llgo.yml b/.github/workflows/llgo.yml index de57fe9b..c49ea13d 100644 --- a/.github/workflows/llgo.yml +++ b/.github/workflows/llgo.yml @@ -200,13 +200,17 @@ jobs: cross-compile: continue-on-error: true - runs-on: macos-latest + strategy: + matrix: + os: [macos-latest] + llvm: [19] + runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - name: Install dependencies uses: ./.github/actions/setup-deps with: - llvm-version: 19 + llvm-version: ${{matrix.llvm}} - name: Set up Go for building llgo uses: ./.github/actions/setup-go From 3a883b882159c7c144fe32f22384d8380a332b92 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 8 Apr 2025 19:32:26 +0800 Subject: [PATCH 8/8] upgrade to github.com/goplus/lib v0.2.0 --- _demo/go.mod | 2 +- _demo/go.sum | 4 ++-- _pydemo/go.mod | 2 +- _pydemo/go.sum | 4 ++-- _xtool/go.mod | 2 +- _xtool/go.sum | 4 ++-- doc/_readme/go.mod | 2 +- doc/_readme/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/_demo/go.mod b/_demo/go.mod index e6fd6415..b5dd0630 100644 --- a/_demo/go.mod +++ b/_demo/go.mod @@ -2,4 +2,4 @@ module github.com/goplus/llgo/_demo go 1.20 -require github.com/goplus/lib v0.1.0 +require github.com/goplus/lib v0.2.0 diff --git a/_demo/go.sum b/_demo/go.sum index 415531cd..512980a5 100644 --- a/_demo/go.sum +++ b/_demo/go.sum @@ -1,2 +1,2 @@ -github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ= -github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= +github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g= +github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= diff --git a/_pydemo/go.mod b/_pydemo/go.mod index afce0e02..c117f8d9 100644 --- a/_pydemo/go.mod +++ b/_pydemo/go.mod @@ -2,4 +2,4 @@ module github.com/goplus/llgo/_pydemo go 1.20 -require github.com/goplus/lib v0.1.0 +require github.com/goplus/lib v0.2.0 diff --git a/_pydemo/go.sum b/_pydemo/go.sum index 415531cd..512980a5 100644 --- a/_pydemo/go.sum +++ b/_pydemo/go.sum @@ -1,2 +1,2 @@ -github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ= -github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= +github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g= +github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= diff --git a/_xtool/go.mod b/_xtool/go.mod index 6f97bf6d..03c80912 100644 --- a/_xtool/go.mod +++ b/_xtool/go.mod @@ -2,4 +2,4 @@ module github.com/goplus/llgo/_xtool go 1.20 -require github.com/goplus/lib v0.1.0 +require github.com/goplus/lib v0.2.0 diff --git a/_xtool/go.sum b/_xtool/go.sum index 415531cd..512980a5 100644 --- a/_xtool/go.sum +++ b/_xtool/go.sum @@ -1,2 +1,2 @@ -github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ= -github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= +github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g= +github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= diff --git a/doc/_readme/go.mod b/doc/_readme/go.mod index 059f0f4f..5d2e87fd 100644 --- a/doc/_readme/go.mod +++ b/doc/_readme/go.mod @@ -2,4 +2,4 @@ module github.com/goplus/llgo/doc/_readme go 1.20 -require github.com/goplus/lib v0.1.0 +require github.com/goplus/lib v0.2.0 diff --git a/doc/_readme/go.sum b/doc/_readme/go.sum index 415531cd..512980a5 100644 --- a/doc/_readme/go.sum +++ b/doc/_readme/go.sum @@ -1,2 +1,2 @@ -github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ= -github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= +github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g= +github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= diff --git a/go.mod b/go.mod index 77521392..12e45a19 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.24.1 require ( github.com/goplus/gogen v1.16.9 - github.com/goplus/lib v0.1.0 + github.com/goplus/lib v0.2.0 github.com/goplus/llgo/runtime v0.0.0-20250403035532-0a8a4eb6a653 github.com/goplus/llvm v0.8.3 github.com/goplus/mod v0.13.17 diff --git a/go.sum b/go.sum index 17f6f53c..1f6c2514 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/goplus/gogen v1.16.9 h1:BRNAsRzdyMcLBOLUe6+suVMmOe+D2HLfF7mAkS4/QW4= github.com/goplus/gogen v1.16.9/go.mod h1:6TQYbabXDF9LCdDkOOzHmfg1R4ENfXQ3XpHa9RhTSD8= -github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ= -github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= +github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g= +github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= github.com/goplus/llvm v0.8.3 h1:is1zOwhiQZWtLnOmSMVPO+1sPa2uK/XJ/FjTSfIjGBU= github.com/goplus/llvm v0.8.3/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4= github.com/goplus/mod v0.13.17 h1:aWp14xosENrh7t0/0qcIejDmQEiTgI3ou2+KoLDlSlE=