From ca47e341cd95df5991e7efc04556175e4e2f19ef Mon Sep 17 00:00:00 2001 From: xhd2015 Date: Sun, 21 Apr 2024 17:59:11 +0800 Subject: [PATCH] workaround cgo filenames, see https://github.com/xhd2015/xgo/issues/80 --- cmd/xgo/runtime_gen/core/version.go | 6 +- cmd/xgo/trace.go | 103 ++++++++++++++++++++-------- cmd/xgo/version.go | 6 +- patch/syntax/syntax.go | 21 +++++- runtime/core/version.go | 6 +- 5 files changed, 101 insertions(+), 41 deletions(-) diff --git a/cmd/xgo/runtime_gen/core/version.go b/cmd/xgo/runtime_gen/core/version.go index 4e05587a..536606f2 100755 --- a/cmd/xgo/runtime_gen/core/version.go +++ b/cmd/xgo/runtime_gen/core/version.go @@ -6,9 +6,9 @@ import ( "os" ) -const VERSION = "1.0.26" -const REVISION = "d19c85ac922d26f26038dc99ae3049de0d91d2f6+1" -const NUMBER = 199 +const VERSION = "1.0.27" +const REVISION = "4f58227acb703c893cc78dd39c09f0fe5d15565c+1" +const NUMBER = 200 // these fields will be filled by compiler const XGO_VERSION = "" diff --git a/cmd/xgo/trace.go b/cmd/xgo/trace.go index 916c21b7..01f440c4 100644 --- a/cmd/xgo/trace.go +++ b/cmd/xgo/trace.go @@ -362,6 +362,11 @@ func addBlankImports(goroot string, goBinary string, projectDir string, pkgArgs // list files, add init // NOTE: go build tag applies, // ignored files will be placed to IgnoredGoFiles + + // meanings: + // TestGoFiles []string // _test.go files in package + // XTestGoFiles []string // _test.go files outside package + // XTestGoFiles are files with another package name, such as api_test for api listArgs := []string{"list", "-json"} listArgs = append(listArgs, pkgArgs...) output, err := cmd.Dir(projectDir).Env([]string{ @@ -384,53 +389,82 @@ func addBlankImports(goroot string, goBinary string, projectDir string, pkgArgs replace = make(map[string]string) for _, pkg := range pkgs { if pkg.Standard { + // skip standarding packages continue } - // already has trace? - var hasDep bool - for _, dep := range pkg.Deps { - if dep == RUNTIME_TRACE_PKG { - hasDep = true - break - } + type pkgInfo struct { + imports []string + files []string + addForAllFiles bool } - if hasDep { - continue + var pkgInfos []pkgInfo + + // no matter test or not,adding to the + // original package is always fine. + // it is a catch-all workaround + // when there is no source files, then we add to all tests + // the fact is: go allows duplicate blank imports + if len(pkg.GoFiles) > 0 { + pkgInfos = append(pkgInfos, pkgInfo{pkg.Imports, pkg.GoFiles, false}) + } else { + pkgInfos = append(pkgInfos, pkgInfo{nil, pkg.TestGoFiles, true}) + pkgInfos = append(pkgInfos, pkgInfo{nil, pkg.XTestGoFiles, true}) } - var file string - if test && len(pkg.TestGoFiles) > 0 { - file = pkg.TestGoFiles[0] - } else if len(pkg.GoFiles) > 0 { - file = pkg.GoFiles[0] + for _, p := range pkgInfos { + mapping, err := addBlankImportForPackage(pkg.Dir, tmpProjectDir, p.imports, p.files, p.addForAllFiles) + if err != nil { + return nil, err + } + for srcFile, dstFile := range mapping { + replace[srcFile] = dstFile + } } - if file == "" { - // no files - continue + } + return replace, nil +} + +func addBlankImportForPackage(srcDir string, dstDir string, imports []string, files []string, allFile bool) (map[string]string, error) { + if len(files) == 0 { + // no files + return nil, nil + } + if !allFile { + // check if already has trace + for _, imp := range imports { + if imp == RUNTIME_TRACE_PKG { + return nil, nil + } } - srcFile := filepath.Join(pkg.Dir, file) - dstFile := filepath.Join(tmpProjectDir, srcFile) + // take the first one + files = files[0:1] + } + + mapping := make(map[string]string, len(files)) + for _, file := range files { + srcFile := filepath.Join(srcDir, file) + dstFile := filepath.Join(dstDir, srcFile) err := filecopy.CopyFileAll(srcFile, dstFile) if err != nil { return nil, err } // add blank import + // NOTE: go allows duplicate blank imports content, err := os.ReadFile(dstFile) if err != nil { return nil, err } newContent, ok := addBlankImport(string(content)) if !ok { - continue + return nil, nil } err = os.WriteFile(dstFile, []byte(newContent), 0755) if err != nil { return nil, err } - replace[srcFile] = dstFile + mapping[srcFile] = dstFile } - return replace, nil + return mapping, nil } - func exists(path string) bool { _, err := os.Stat(path) return err == nil @@ -444,14 +478,23 @@ func isDir(path string) bool { return stat.IsDir() } +// see go-release/go1.22.2/src/cmd/go/internal/list/list.go type GoListPkg struct { - Dir string // real dir - ImportPath string - Root string // project root - Standard bool - GoFiles []string - TestGoFiles []string - Deps []string // all dependents + Dir string // real dir + ImportPath string + Root string // project root + Standard bool + + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + TestGoFiles []string + XTestGoFiles []string // _test.go files outside package + + // Dependency information + Deps []string // all (recursively) imported dependencies + Imports []string // import paths used by this package + TestImports []string // imports from TestGoFiles + XTestImports []string // imports from XTestGoFiles + } func addBlankImport(content string) (string, bool) { diff --git a/cmd/xgo/version.go b/cmd/xgo/version.go index c2ce9abd..7434032c 100644 --- a/cmd/xgo/version.go +++ b/cmd/xgo/version.go @@ -2,9 +2,9 @@ package main import "fmt" -const VERSION = "1.0.26" -const REVISION = "d19c85ac922d26f26038dc99ae3049de0d91d2f6+1" -const NUMBER = 199 +const VERSION = "1.0.27" +const REVISION = "4f58227acb703c893cc78dd39c09f0fe5d15565c+1" +const NUMBER = 200 func getRevision() string { revSuffix := "" diff --git a/patch/syntax/syntax.go b/patch/syntax/syntax.go index 53f21e5c..b0867632 100644 --- a/patch/syntax/syntax.go +++ b/patch/syntax/syntax.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "path/filepath" "strconv" "strings" @@ -284,6 +285,12 @@ func registerFuncs(fileList []*syntax.File, addFile func(name string, r io.Reade // special when there are multiple files fileNameBase += fmt.Sprintf("_%d", i) } + if false { + // debug + dir := filepath.Join("/tmp/xgo_debug_gen", pkgPath) + os.MkdirAll(dir, 0755) + os.WriteFile(filepath.Join(dir, fileNameBase+".go"), []byte(fileCode), 0755) + } addFile(fileNameBase+".go", strings.NewReader(fileCode)) if false && pkgPath == "main" { // debug @@ -490,17 +497,25 @@ func getFuncDecls(files []*syntax.File, varTrap bool) []*DeclInfo { var declFuncs []*DeclInfo for i, f := range files { var file string + var trimmed bool if base.Flag.Std && false { file = f.Pos().RelFilename() } else if TrimFilename != nil { // >= go1.18 file = TrimFilename(f.Pos().Base()) + trimmed = true } else if AbsFilename != nil { file = AbsFilename(f.Pos().Base().Filename()) + trimmed = true } else { // fallback to default file = f.Pos().RelFilename() } + + // see https://github.com/xhd2015/xgo/issues/80 + if trimmed && strings.HasPrefix(file, "_cgo") { + file = f.Pos().RelFilename() + } for _, decl := range f.DeclList { fnDecls := extractFuncDecls(i, f, file, decl, varTrap) declFuncs = append(declFuncs, fnDecls...) @@ -625,7 +640,9 @@ func extractFuncDecls(fileIndex int, f *syntax.File, file string, decl syntax.De func getFuncDeclInfo(fileIndex int, f *syntax.File, file string, fn *syntax.FuncDecl) *DeclInfo { line := fn.Pos().Line() - if fn.Name.Value == "init" { + fnName := fn.Name.Value + if fnName == "init" || strings.HasPrefix(fnName, "_cgo") || strings.HasPrefix(fnName, "_Cgo") { + // skip cgo also,see https://github.com/xhd2015/xgo/issues/80#issuecomment-2067976575 return nil } var genericFunc bool @@ -676,7 +693,7 @@ func getFuncDeclInfo(fileIndex int, f *syntax.File, file string, fn *syntax.Func return &DeclInfo{ FuncDecl: fn, - Name: fn.Name.Value, + Name: fnName, RecvTypeName: recvTypeName, RecvPtr: recvPtr, Generic: genericFunc || genericRecv, diff --git a/runtime/core/version.go b/runtime/core/version.go index 4e05587a..536606f2 100644 --- a/runtime/core/version.go +++ b/runtime/core/version.go @@ -6,9 +6,9 @@ import ( "os" ) -const VERSION = "1.0.26" -const REVISION = "d19c85ac922d26f26038dc99ae3049de0d91d2f6+1" -const NUMBER = 199 +const VERSION = "1.0.27" +const REVISION = "4f58227acb703c893cc78dd39c09f0fe5d15565c+1" +const NUMBER = 200 // these fields will be filled by compiler const XGO_VERSION = ""