From fe5de95008ffea4acb0f15998fccfcbbba6b76ba Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 8 Aug 2024 14:14:20 +0800 Subject: [PATCH 1/2] llcppsymg:improve parsing process --- chore/_xtool/llcppsymg/llcppsymg.go | 118 +++++-------------------- chore/_xtool/llcppsymg/parse/parse.go | 120 ++++++++++++++------------ 2 files changed, 90 insertions(+), 148 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 93c2194d..43009159 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -22,7 +22,6 @@ import ( "io" "os" "path/filepath" - "strconv" "strings" "unsafe" @@ -61,11 +60,11 @@ func main() { check(err) - filepaths := generateHeaderFilePath(conf.CFlags, conf.Include) - astInfos, err := parse.ParseHeaderFile(filepaths) + filepaths := genHeaderFilePath(conf.CFlags, conf.Include) + headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes) check(err) - symbolInfo := getCommonSymbols(symbols, astInfos, conf.TrimPrefixes) + symbolInfo := getCommonSymbols(symbols, headerInfos, conf.TrimPrefixes) err = genSymbolTableFile(symbolInfo) check(err) @@ -77,8 +76,8 @@ func check(err error) { } } -func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { - dylibPath, err := generateDylibPath(lib) +func parseDylibSymbols(lib string) ([]*nm.Symbol, error) { + dylibPath, err := genDylibPath(lib) if err != nil { return nil, errors.New("failed to generate dylib path") } @@ -88,22 +87,15 @@ func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { return nil, errors.New("failed to list symbols in dylib") } - var symbols []types.CPPSymbol - + var symbols []*nm.Symbol for _, file := range files { - for _, sym := range file.Symbols { - demangleName := decodeSymbolName(sym.Name) - symbols = append(symbols, types.CPPSymbol{ - Symbol: sym, - DemangleName: demangleName, - }) - } + symbols = append(symbols, file.Symbols...) } return symbols, nil } -func generateDylibPath(lib string) (string, error) { +func genDylibPath(lib string) (string, error) { output := lib libPath := "" libName := "" @@ -123,31 +115,20 @@ func generateDylibPath(lib string) (string, error) { return dylibPath, nil } -func decodeSymbolName(symbolName string) string { +func decodeSymbol(symbolName string) string { if symbolName == "" { return "" } - demangled := llvm.ItaniumDemangle(symbolName, true) if demangled == nil { return symbolName } defer c.Free(unsafe.Pointer(demangled)) - demangleName := c.GoString(demangled) - if demangleName == "" { - return symbolName - } - - decodedName := strings.TrimSpace(demangleName) - decodedName = strings.ReplaceAll(decodedName, - "std::__1::basic_string, std::__1::allocator > const", - "std::string") - - return decodedName + return strings.TrimSpace(demangleName) } -func generateHeaderFilePath(cflags string, files []string) []string { +func genHeaderFilePath(cflags string, files []string) []string { prefixPath := cflags prefixPath = strings.TrimPrefix(prefixPath, "-I") var includePaths []string @@ -157,77 +138,23 @@ func generateHeaderFilePath(cflags string, files []string) []string { return includePaths } -func getCommonSymbols(dylibSymbols []types.CPPSymbol, astInfoList []types.ASTInformation, prefix []string) []types.SymbolInfo { - var commonSymbols []types.SymbolInfo - functionNameMap := make(map[string]int) - - for _, astInfo := range astInfoList { - for _, dylibSym := range dylibSymbols { - if strings.TrimPrefix(dylibSym.Name, "_") == astInfo.Symbol { - cppName := generateCPPName(astInfo) - functionNameMap[cppName]++ - symbolInfo := types.SymbolInfo{ - Mangle: strings.TrimPrefix(dylibSym.Name, "_"), - CPP: cppName, - Go: generateMangle(astInfo, functionNameMap[cppName], prefix), - } - commonSymbols = append(commonSymbols, symbolInfo) - break +func getCommonSymbols(dylibSymbols []*nm.Symbol, symbolMap map[string]string, prefix []string) []*types.SymbolInfo { + var commonSymbols []*types.SymbolInfo + for _, dylibSym := range dylibSymbols { + symName := strings.TrimPrefix(dylibSym.Name, "_") + if goName, ok := symbolMap[symName]; ok { + symbolInfo := &types.SymbolInfo{ + Mangle: symName, + CPP: decodeSymbol(dylibSym.Name), + Go: goName, } + commonSymbols = append(commonSymbols, symbolInfo) } } - return commonSymbols } -func generateCPPName(astInfo types.ASTInformation) string { - cppName := astInfo.Name - if astInfo.Class != "" { - cppName = astInfo.Class + "::" + astInfo.Name - } - return cppName -} - -func generateMangle(astInfo types.ASTInformation, count int, prefixes []string) string { - astInfo.Class = removePrefix(astInfo.Class, prefixes) - astInfo.Name = removePrefix(astInfo.Name, prefixes) - res := "" - if astInfo.Class != "" { - if astInfo.Class == astInfo.Name { - res = "(*" + astInfo.Class + ")." + "Init" - if count > 1 { - res += "__" + strconv.Itoa(count-1) - } - } else if astInfo.Name == "~"+astInfo.Class { - res = "(*" + astInfo.Class + ")." + "Dispose" - if count > 1 { - res += "__" + strconv.Itoa(count-1) - } - } else { - res = "(*" + astInfo.Class + ")." + astInfo.Name - if count > 1 { - res += "__" + strconv.Itoa(count-1) - } - } - } else { - res = astInfo.Name - if count > 1 { - res += "__" + strconv.Itoa(count-1) - } - } - return res -} - -func removePrefix(str string, prefixes []string) string { - for _, prefix := range prefixes { - if strings.HasPrefix(str, prefix) { - return strings.TrimPrefix(str, prefix) - } - } - return str -} - -func genSymbolTableFile(symbolInfos []types.SymbolInfo) error { +func genSymbolTableFile(symbolInfos []*types.SymbolInfo) error { // keep open follow code block can run successfully for i := range symbolInfos { println("symbol", symbolInfos[i].Go) @@ -269,6 +196,7 @@ func genSymbolTableFile(symbolInfos []types.SymbolInfo) error { } return nil } + func readExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, error) { existingSymbols := make(map[string]types.SymbolInfo) diff --git a/chore/_xtool/llcppsymg/parse/parse.go b/chore/_xtool/llcppsymg/parse/parse.go index 5a15d26a..f3e852eb 100644 --- a/chore/_xtool/llcppsymg/parse/parse.go +++ b/chore/_xtool/llcppsymg/parse/parse.go @@ -3,23 +3,27 @@ package parse import ( "errors" "strconv" + "strings" "unsafe" "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/clang" - "github.com/goplus/llgo/chore/llcppg/types" ) type Context struct { namespaceName string className string - astInfo []types.ASTInformation + prefixes []string + symbolMap map[string]string currentFile string + nameCounts map[string]int } -func newContext() *Context { +func newContext(prefixes []string) *Context { return &Context{ - astInfo: make([]types.ASTInformation, 0), + prefixes: prefixes, + symbolMap: make(map[string]string), + nameCounts: make(map[string]int), } } @@ -35,70 +39,83 @@ func (c *Context) setCurrentFile(filename string) { c.currentFile = filename } -var context = newContext() +func (c *Context) removePrefix(str string) string { + for _, prefix := range c.prefixes { + if strings.HasPrefix(str, prefix) { + return strings.TrimPrefix(str, prefix) + } + } + return str +} -func collectFuncInfo(cursor clang.Cursor) types.ASTInformation { +func (c *Context) genGoName(name string) string { + class := c.removePrefix(c.className) + name = c.removePrefix(name) - info := types.ASTInformation{ - Namespace: context.namespaceName, - Class: context.className, + var baseName string + if class == "" { + baseName = name + } else { + baseName = c.genMethodName(class, name) } + return c.addSuffix(baseName) +} + +func (c *Context) genMethodName(class, name string) string { + prefix := "(*" + class + ")." + if class == name { + return prefix + "Init" + } + if name == "~"+class { + return prefix + "Dispose" + } + return prefix + name +} + +func (c *Context) addSuffix(name string) string { + c.nameCounts[name]++ + count := c.nameCounts[name] + if count > 1 { + return name + "__" + strconv.Itoa(count-1) + } + return name +} + +var context = newContext([]string{}) + +func collectFuncInfo(cursor clang.Cursor) { cursorStr := cursor.String() symbol := cursor.Mangling() - info.Name = c.GoString(cursorStr.CStr()) - - info.Symbol = c.GoString(symbol.CStr()) - if len(info.Symbol) >= 1 { - if info.Symbol[0] == '_' { - info.Symbol = info.Symbol[1:] - } + name := c.GoString(cursorStr.CStr()) + symbolName := c.GoString(symbol.CStr()) + if len(symbolName) >= 1 && symbolName[0] == '_' { + symbolName = symbolName[1:] } - defer symbol.Dispose() defer cursorStr.Dispose() - if context.namespaceName != "" { - info.Namespace = context.namespaceName - } - if context.className != "" { - info.Class = context.className - } - - typeStr := cursor.ResultType().String() - defer typeStr.Dispose() - info.ReturnType = c.GoString(typeStr.CStr()) - - info.Parameters = make([]types.Parameter, cursor.NumArguments()) - for i := 0; i < int(cursor.NumArguments()); i++ { - argCurSor := cursor.Argument(c.Uint(i)) - argType := argCurSor.Type().String() - argName := argCurSor.String() - info.Parameters[i] = types.Parameter{ - Name: c.GoString(argName.CStr()), - Type: c.GoString(argType.CStr()), - } - - argType.Dispose() - argName.Dispose() - } - - return info + goName := context.genGoName(name) + context.symbolMap[symbolName] = goName } func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult { - if cursor.Kind == clang.Namespace { + if cursor.Kind == clang.CursorNamespace { nameStr := cursor.String() + defer nameStr.Dispose() + context.setNamespaceName(c.GoString(nameStr.CStr())) clang.VisitChildren(cursor, visit, nil) context.setNamespaceName("") - } else if cursor.Kind == clang.ClassDecl { + } else if cursor.Kind == clang.CursorClassDecl { nameStr := cursor.String() + defer nameStr.Dispose() + context.setClassName(c.GoString(nameStr.CStr())) clang.VisitChildren(cursor, visit, nil) context.setClassName("") - } else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl || cursor.Kind == clang.Constructor || cursor.Kind == clang.Destructor { + } else if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor { loc := cursor.Location() var file clang.File var line, column c.Uint @@ -107,9 +124,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe filename := file.FileName() if c.Strcmp(filename.CStr(), c.AllocaCStr(context.currentFile)) == 0 { - info := collectFuncInfo(cursor) - info.Location = c.GoString(filename.CStr()) + ":" + strconv.Itoa(int(line)) + ":" + strconv.Itoa(int(column)) - context.astInfo = append(context.astInfo, info) + collectFuncInfo(cursor) } defer filename.Dispose() @@ -118,14 +133,13 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe return clang.ChildVisit_Continue } -func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, error) { - +func ParseHeaderFile(filepaths []string, prefixes []string) (map[string]string, error) { index := clang.CreateIndex(0, 0) args := make([]*c.Char, 3) args[0] = c.Str("-x") args[1] = c.Str("c++") args[2] = c.Str("-std=c++11") - context = newContext() + context = newContext(prefixes) for _, filename := range filepaths { unit := index.ParseTranslationUnit( @@ -149,5 +163,5 @@ func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, error) { index.Dispose() - return context.astInfo, nil + return context.symbolMap, nil } From 4c2099d33e0cb0bb89935b7be773e46085ade890 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 8 Aug 2024 15:09:24 +0800 Subject: [PATCH 2/2] llcppg:remove unuse types --- chore/llcppg/types/types.go | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index 9d700881..6852ed1f 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -16,10 +16,6 @@ package types -import ( - "github.com/goplus/llgo/xtool/nm" -) - // Config represents a configuration for the llcppg tool. type Config struct { Name string `json:"name"` @@ -29,27 +25,6 @@ type Config struct { TrimPrefixes []string `json:"trimPrefixes"` } -type CPPSymbol struct { - DemangleName string - *nm.Symbol -} - -type ASTInformation struct { - Namespace string `json:"namespace"` - Class string `json:"class"` - Name string `json:"name"` - BaseClasses []string `json:"baseClasses"` - ReturnType string `json:"returnType"` - Location string `json:"location"` - Parameters []Parameter `json:"parameters"` - Symbol string `json:"symbol"` -} - -type Parameter struct { - Name string `json:"name"` - Type string `json:"type"` -} - type SymbolInfo struct { Mangle string `json:"mangle"` // C++ Symbol CPP string `json:"c++"` // C++ function name