From 249f85a25e23795247825cbf2001e7e4138980bb Mon Sep 17 00:00:00 2001 From: visualfc Date: Mon, 23 Jun 2025 15:12:07 +0800 Subject: [PATCH] build: gen pkg to object --- internal/build/build.go | 112 ++++++++++++++------- internal/crosscompile/cosscompile.go | 12 ++- internal/crosscompile/crosscompile_test.go | 2 +- 3 files changed, 87 insertions(+), 39 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index 1c480b25..307e131f 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -77,6 +77,7 @@ type Config struct { Mode Mode GenExpect bool // only valid for ModeCmpTest Verbose bool + GenLL bool // generate pkg .ll files Tags string GlobalNames map[string][]string // pkg => names GlobalDatas map[string]string // pkg.name => data @@ -252,7 +253,15 @@ func Do(args []string, conf *Config) ([]Package, error) { output := conf.OutFile != "" export, err := crosscompile.Use(conf.Goos, conf.Goarch, IsWasiThreadsEnabled(), IsRpathChangeEnabled()) 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, false} + ctx := &context{env: env, conf: cfg, progSSA: progSSA, prog: prog, dedup: dedup, + patches: patches, built: make(map[string]none), initial: initial, mode: mode, + output: output, + needRt: make(map[*packages.Package]bool), + needPyInit: make(map[*packages.Package]bool), + buildConf: conf, + crossCompile: export, + isCheckEnable: IsCheckEnable(), + } pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -273,7 +282,7 @@ func Do(args []string, conf *Config) ([]Package, error) { addGlobalString(conf, "runtime.defaultGOROOT="+runtime.GOROOT(), nil) addGlobalString(conf, "runtime.buildVersion="+runtime.Version(), nil) - global, err := createGlobals(conf, ctx.prog, pkgs) + global, err := createGlobals(ctx, ctx.prog, pkgs) check(err) for _, pkg := range initial { @@ -341,6 +350,8 @@ type context struct { nLibdir int output bool + isCheckEnable bool + needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool @@ -476,25 +487,28 @@ func addGlobalString(conf *Config, arg string, mainPkgs []string) { } } -func createGlobals(conf *Config, prog llssa.Program, pkgs []*aPackage) (llssa.Package, error) { - if len(conf.GlobalDatas) == 0 { +func createGlobals(ctx *context, prog llssa.Program, pkgs []*aPackage) (llssa.Package, error) { + if len(ctx.buildConf.GlobalDatas) == 0 { return nil, nil } for _, pkg := range pkgs { if pkg.ExportFile == "" { continue } - if names, ok := conf.GlobalNames[pkg.PkgPath]; ok { + if names, ok := ctx.buildConf.GlobalNames[pkg.PkgPath]; ok { err := pkg.LPkg.Undefined(names...) if err != nil { return nil, err } - pkg.ExportFile = pkg.ExportFile + "-global.ll" - os.WriteFile(pkg.ExportFile, []byte(pkg.LPkg.String()), 0644) + pkg.ExportFile += "-global" + pkg.ExportFile, err = exportObject(ctx, pkg.PkgPath+".global", pkg.ExportFile, []byte(pkg.LPkg.String())) + if err != nil { + return nil, err + } } } global := prog.NewPackage("", "global") - for name, value := range conf.GlobalDatas { + for name, value := range ctx.buildConf.GlobalDatas { global.AddGlobalString(name, value) } return global, nil @@ -543,14 +557,14 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l } } }) - entryLLFile, err := genMainModuleFile(conf, llssa.PkgRuntime, pkg.PkgPath, needRuntime, needPyInit) + entryLLFile, err := genMainModuleFile(ctx, llssa.PkgRuntime, pkg, needRuntime, needPyInit) check(err) // defer os.Remove(entryLLFile) llFiles = append(llFiles, entryLLFile) if global != nil { - export := pkg.ExportFile + "-global.ll" - os.WriteFile(export, []byte(global.String()), 0666) + export, err := exportObject(ctx, pkg.PkgPath+".global", pkg.ExportFile+"-global", []byte(global.String())) + check(err) llFiles = append(llFiles, export) } @@ -663,13 +677,14 @@ 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) { +func genMainModuleFile(ctx *context, rtPkgPath string, pkg *packages.Package, needRuntime, needPyInit bool) (path string, err error) { var ( pyInitDecl string pyInit string rtInitDecl string rtInit string ) + mainPkgPath := pkg.PkgPath if needRuntime { rtInit = "call void @\"" + rtPkgPath + ".init\"()" rtInitDecl = "declare void @\"" + rtPkgPath + ".init\"()" @@ -679,7 +694,7 @@ func genMainModuleFile(conf *Config, rtPkgPath, mainPkgPath string, needRuntime, pyInitDecl = "declare void @Py_Initialize()" } declSizeT := "%size_t = type i64" - if is32Bits(conf.Goarch) { + if is32Bits(ctx.buildConf.Goarch) { declSizeT = "%size_t = type i32" } stdioDecl := "" @@ -703,7 +718,7 @@ call i32 @setvbuf(ptr %stderr_ptr, ptr null, i32 2, %size_t 0) ` } mainDefine := "define i32 @main(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr" - if isWasmTarget(conf.Goos) { + if isWasmTarget(ctx.buildConf.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' @@ -742,19 +757,7 @@ _llgo_0: mainDefine, stdioNobuf, pyInit, rtInit, mainPkgPath, mainPkgPath) - f, err := os.CreateTemp("", "main*.ll") - if err != nil { - return "", err - } - _, err = f.Write([]byte(mainCode)) - if err != nil { - return "", err - } - err = f.Close() - if err != nil { - return "", err - } - return f.Name(), nil + return exportObject(ctx, pkg.PkgPath+".main", pkg.ExportFile+"-main", []byte(mainCode)) } func is32Bits(goarch string) bool { @@ -805,20 +808,50 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) error { aPkg.LinkArgs = append(aPkg.LinkArgs, altLdflags...) } if pkg.ExportFile != "" { - pkg.ExportFile += ".ll" - os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644) + pkg.ExportFile, err = exportObject(ctx, pkg.PkgPath, pkg.ExportFile, []byte(ret.String())) + if err != nil { + return fmt.Errorf("export object of %v failed: %v", pkgPath, err) + } if debugBuild || verbose { fmt.Fprintf(os.Stderr, "==> Export %s: %s\n", aPkg.PkgPath, pkg.ExportFile) } - if IsCheckEnable() { - if msg, err := llcCheck(ctx.env, pkg.ExportFile); err != nil { - fmt.Fprintf(os.Stderr, "==> lcc %v: %v\n%v\n", pkg.PkgPath, pkg.ExportFile, msg) - } - } } return nil } +func exportObject(ctx *context, pkgPath string, exportFile string, data []byte) (string, error) { + f, err := os.CreateTemp("", "llgo-*.ll") + if err != nil { + return "", err + } + f.Write(data) + err = f.Close() + if err != nil { + return exportFile, err + } + if ctx.isCheckEnable { + if msg, err := llcCheck(ctx.env, f.Name()); err != nil { + fmt.Fprintf(os.Stderr, "==> lcc %v: %v\n%v\n", pkgPath, f.Name(), msg) + } + } + if ctx.buildConf.GenLL { + exportFile += ".ll" + err = os.Chmod(f.Name(), 0644) + if err != nil { + return exportFile, err + } + return exportFile, os.Rename(f.Name(), exportFile) + } + exportFile += ".o" + args := []string{"-o", exportFile, "-c", f.Name(), "-Wno-override-module"} + args = append(args, ctx.crossCompile.CCFLAGS...) + if ctx.buildConf.Verbose { + fmt.Fprintln(os.Stderr, "clang", args) + } + cmd := ctx.compiler() + return exportFile, cmd.Compile(args...) +} + func llcCheck(env *llvm.Env, exportFile string) (msg string, err error) { bin := filepath.Join(env.BinDir(), "llc") cmd := exec.Command(bin, "-filetype=null", exportFile) @@ -1034,15 +1067,20 @@ 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" + llFile := expFile + filepath.Base(cFile) ext := filepath.Ext(cFile) // default clang++ will use c++ to compile c file,will cause symbol be mangled if ext == ".c" { args = append(args, "-x", "c") } - - args = append(args, "-emit-llvm", "-S", "-o", llFile, "-c", cFile) + if ctx.buildConf.GenLL { + llFile += ".ll" + args = append(args, "-emit-llvm", "-S", "-o", llFile, "-c", cFile) + } else { + llFile += ".o" + args = append(args, "-o", llFile, "-c", cFile) + } args = append(args, ctx.crossCompile.CCFLAGS...) args = append(args, ctx.crossCompile.CFLAGS...) if verbose { diff --git a/internal/crosscompile/cosscompile.go b/internal/crosscompile/cosscompile.go index c532cc79..df6e4aaf 100644 --- a/internal/crosscompile/cosscompile.go +++ b/internal/crosscompile/cosscompile.go @@ -36,7 +36,6 @@ func Use(goos, goarch string, wasiThreads, changeRpath bool) (export Export, err "-Wno-override-module", "-Wl,--error-limit=0", "-fuse-ld=lld", - "-Wno-override-module", } // Add OS-specific flags @@ -56,6 +55,11 @@ func Use(goos, goarch string, wasiThreads, changeRpath bool) (export Export, err case "windows": // lld-link (Windows) // TODO(lijie): Add options for Windows. default: // ld.lld (Unix) + export.CCFLAGS = append( + export.CCFLAGS, + "-fdata-sections", + "-ffunction-sections", + ) export.LDFLAGS = append( export.LDFLAGS, "-fdata-sections", @@ -105,6 +109,8 @@ func Use(goos, goarch string, wasiThreads, changeRpath bool) (export Export, err "-target", targetTriple, "--sysroot=" + sysrootDir, "-resource-dir=" + libclangDir, + "-matomics", + "-mbulk-memory", } export.CFLAGS = []string{ "-I" + includeDir, @@ -138,6 +144,10 @@ func Use(goos, goarch string, wasiThreads, changeRpath bool) (export Export, err } // Add thread support if enabled if wasiThreads { + export.CCFLAGS = append( + export.CCFLAGS, + "-pthread", + ) export.LDFLAGS = append( export.LDFLAGS, "-lwasi-emulated-pthread", diff --git a/internal/crosscompile/crosscompile_test.go b/internal/crosscompile/crosscompile_test.go index d988171a..6c062408 100644 --- a/internal/crosscompile/crosscompile_test.go +++ b/internal/crosscompile/crosscompile_test.go @@ -146,7 +146,7 @@ func TestUseCrossCompileSDK(t *testing.T) { } } } else { - if len(export.CCFLAGS) != 0 || len(export.CFLAGS) != 0 { + if /*len(export.CCFLAGS) != 0 ||*/ len(export.CFLAGS) != 0 { t.Errorf("Expected empty export, got CCFLAGS=%v, CFLAGS=%v, LDFLAGS=%v", export.CCFLAGS, export.CFLAGS, export.LDFLAGS) }