build: gen pkg to object

This commit is contained in:
visualfc
2025-06-23 15:12:07 +08:00
parent 9c59ac297d
commit 249f85a25e
3 changed files with 87 additions and 39 deletions

View File

@@ -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 {