From a96d6a814825b20863b25bacf480e4f4d1d963af Mon Sep 17 00:00:00 2001 From: morpingsss Date: Fri, 26 Jul 2024 10:31:20 +0800 Subject: [PATCH 01/24] feat(llgo/xtools): add llcppsymg.go --- chore/_xtool/llcppsymg/common/common.go | 29 +++ chore/_xtool/llcppsymg/llcppg.cfg | 10 + chore/_xtool/llcppsymg/llcppsymg.go | 249 +++++++++++++++++++++++- 3 files changed, 278 insertions(+), 10 deletions(-) create mode 100644 chore/_xtool/llcppsymg/common/common.go create mode 100644 chore/_xtool/llcppsymg/llcppg.cfg diff --git a/chore/_xtool/llcppsymg/common/common.go b/chore/_xtool/llcppsymg/common/common.go new file mode 100644 index 00000000..35fed532 --- /dev/null +++ b/chore/_xtool/llcppsymg/common/common.go @@ -0,0 +1,29 @@ +package common + +type CPPSymbol struct { + Symbol string `json:"symbol"` + Type string `json:"type"` + Name string `json:"name"` +} + +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 + Go string `json:"go"` // Go function name +} diff --git a/chore/_xtool/llcppsymg/llcppg.cfg b/chore/_xtool/llcppsymg/llcppg.cfg new file mode 100644 index 00000000..b5335e2c --- /dev/null +++ b/chore/_xtool/llcppsymg/llcppg.cfg @@ -0,0 +1,10 @@ +{ + "name": "inih", + "cflags": "$(pkg-config --cflags INIReader)", + "include": [ + "INIReader.h", + "AnotherHeaderFile.h" + ], + "libs": "$(pkg-config --libs INIReader)", + "trimPrefixes": ["Ini", "INI"] +} \ No newline at end of file diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index ea60dffe..db4bc1e4 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -17,12 +17,20 @@ package main import ( + "bufio" + "bytes" + "encoding/json" + "errors" "fmt" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" + "github.com/goplus/llgo/chore/llcppg/types" "io" "os" - - "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/cjson" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" ) func main() { @@ -40,14 +48,26 @@ func main() { } check(err) - conf := cjson.ParseBytes(data) - if conf == nil { - fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) - os.Exit(1) - } - defer conf.Delete() + var config types.Config + err = json.Unmarshal(data, &config) + check(err) + + symbols, err := parseDylibSymbols(config.Libs) + check(err) + + files, err := parseHeaderFile(config) + check(err) + + symbolInfo := getCommonSymbols(symbols, files) + + jsonData, err := json.MarshalIndent(symbolInfo, "", " ") + check(err) + + // 写入文件 + fileName := "llcppg.symb.json" + err = os.WriteFile(fileName, jsonData, 0644) // 使用 0644 权限 + check(err) - c.Printf(c.Str("%s"), conf.Print()) } func check(err error) { @@ -55,3 +75,212 @@ func check(err error) { panic(err) } } + +func parseDylibSymbols(lib string) ([]common.CPPSymbol, error) { + dylibPath, _ := generateDylibPath(lib) + nmCmd := exec.Command("nm", "-gU", dylibPath) + nmOutput, err := nmCmd.Output() + if err != nil { + return nil, errors.New("failed to execute nm command") + } + + symbols := parseNmOutput(nmOutput) + + for i, sym := range symbols { + decodedName, err := decodeSymbolName(sym.Name) + if err != nil { + return nil, err + } + symbols[i].Name = decodedName + } + + return symbols, nil +} + +func generateDylibPath(lib string) (string, error) { + // 执行pkg-config命令 + output := expandEnv(lib) + // 解析输出 + libPath := "" + libName := "" + for _, part := range strings.Fields(string(output)) { + if strings.HasPrefix(part, "-L") { + libPath = part[2:] // 去掉-L前缀 + } else if strings.HasPrefix(part, "-l") { + libName = part[2:] // 去掉-l前缀 + } + } + + if libPath == "" || libName == "" { + return "", fmt.Errorf("failed to parse pkg-config output: %s", output) + } + + // 构造dylib路径 + dylibPath := filepath.Join(libPath, "lib"+libName+".dylib") + return dylibPath, nil +} + +func parseNmOutput(output []byte) []common.CPPSymbol { + scanner := bufio.NewScanner(bytes.NewReader(output)) + var symbols []common.CPPSymbol + + for scanner.Scan() { + line := scanner.Text() + fields := strings.Fields(line) + if len(fields) < 3 { + continue + } + symbolName := fields[2] + // Check if the symbol name starts with an underscore and remove it if present + if strings.HasPrefix(symbolName, "_") { + symbolName = symbolName[1:] + } + symbols = append(symbols, common.CPPSymbol{ + Symbol: symbolName, + Type: fields[1], + Name: fields[2], + }) + } + + return symbols +} + +func decodeSymbolName(symbolName string) (string, error) { + cppfiltCmd := exec.Command("c++filt", symbolName) + cppfiltOutput, err := cppfiltCmd.Output() + if err != nil { + return "", errors.New("failed to execute c++filt command") + } + + decodedName := strings.TrimSpace(string(cppfiltOutput)) + // 将特定的模板类型转换为 std::string + decodedName = strings.ReplaceAll(decodedName, "std::__1::basic_string, std::__1::allocator > const", "std::string") + return decodedName, nil +} + +// parseHeaderFile +func parseHeaderFile(config types.Config) ([]common.ASTInformation, error) { + files := generateHeaderFilePath(config.CFlags, config.Include) + headerFileCmd := exec.Command("llcppinfofetch", files...) + headerFileOutput, err := headerFileCmd.Output() + if err != nil { + return nil, errors.New("failed to execute header file command") + } + t := make([]common.ASTInformation, 0) + err = json.Unmarshal(headerFileOutput, &t) + if err != nil { + return nil, err + } + return t, nil +} + +func generateHeaderFilePath(cflags string, files []string) []string { + // 执行pkg-config命令 + prefixPath := expandEnv(cflags) + if strings.HasPrefix(prefixPath, "-I") { + prefixPath = prefixPath[2:] + } + // 去掉首尾空白字符(包括换行符) + prefixPath = strings.TrimSpace(prefixPath) + var includePaths []string + for _, file := range files { + includePaths = append(includePaths, filepath.Join(prefixPath, "/"+file)) + } + return includePaths +} + +func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTInformation) []common.SymbolInfo { + var commonSymbols []common.SymbolInfo + functionNameMap := make(map[string]int) + + for _, astInfo := range astInfoList { + for _, dylibSym := range dylibSymbols { + if dylibSym.Symbol == astInfo.Symbol { + cppName := generateCPPName(astInfo) + functionNameMap[cppName]++ + symbolInfo := common.SymbolInfo{ + Mangle: dylibSym.Symbol, + CPP: cppName, + Go: generateMangle(astInfo, functionNameMap[cppName]), + } + commonSymbols = append(commonSymbols, symbolInfo) + break + } + } + } + + return commonSymbols +} + +func generateCPPName(astInfo common.ASTInformation) string { + cppName := astInfo.Name + if astInfo.Class != "" { + cppName = astInfo.Class + "::" + astInfo.Name + } + return cppName +} + +func generateMangle(astInfo common.ASTInformation, count int) string { + 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 + "__" + string(rune(count)) + } + } else { + res = astInfo.Name + if count > 0 { + res += "__" + strconv.Itoa(count-1) + } + } + return res +} + +var ( + reSubcmd = regexp.MustCompile(`\$\([^)]+\)`) + reFlag = regexp.MustCompile(`[^ \t\n]+`) +) + +func expandEnv(s string) string { + return expandEnvWithCmd(s) +} + +func expandEnvWithCmd(s string) string { + expanded := reSubcmd.ReplaceAllStringFunc(s, func(m string) string { + subcmd := strings.TrimSpace(s[2 : len(s)-1]) + + args := parseSubcmd(subcmd) + + cmd := args[0] + + if cmd != "pkg-config" && cmd != "llvm-config" { + fmt.Fprintf(os.Stderr, "expand cmd only support pkg-config and llvm-config: '%s'\n", subcmd) + return "" + } + + var out []byte + var err error + out, err = exec.Command(cmd, args[1:]...).Output() + + if err != nil { + // TODO(kindy): log in verbose mode + return "" + } + + return string(out) + }) + return os.Expand(expanded, os.Getenv) +} + +func parseSubcmd(s string) []string { + return reFlag.FindAllString(s, -1) +} From f391ccb8e8872f8761fe61b5a9d3b24e675bc96a Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 26 Jul 2024 13:45:08 +0800 Subject: [PATCH 02/24] c/clang/symg/header:get func info --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 chore/_xtool/llcppinfofetch/llcppinfofetch.go diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go new file mode 100644 index 00000000..333dd7dd --- /dev/null +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -0,0 +1,220 @@ +package main + +import ( + "fmt" + "os" + "strconv" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/c/clang" +) + +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 Context struct { + namespaceName string + className string + astInfo []ASTInformation +} + +func newContext() *Context { + return &Context{ + astInfo: make([]ASTInformation, 0), + } +} + +func (c *Context) setNamespaceName(name string) { + c.namespaceName = name +} + +func (c *Context) setClassName(name string) { + c.className = name +} + +var context = newContext() + +func collectFuncInfo(cursor clang.Cursor) ASTInformation { + info := ASTInformation{ + Namespace: context.namespaceName, + Class: context.className, + } + + loc := cursor.Location() + var file clang.File + var line, column c.Uint + + loc.SpellingLocation(&file, &line, &column, nil) + filename := file.FileName() + + info.Location = c.GoString(filename.CStr()) + ":" + strconv.Itoa(int(line)) + ":" + strconv.Itoa(int(column)) + + // c.Printf(c.Str("%s:%d:%d\n"), filename.CStr(), line, column) + + cursorStr := cursor.String() + symbol := cursor.Mangling() + + info.Name = c.GoString(cursorStr.CStr()) + info.Symbol = c.GoString(symbol.CStr()) + + defer symbol.Dispose() + defer cursorStr.Dispose() + defer filename.Dispose() + + if context.namespaceName != "" { + info.Namespace = context.namespaceName + } + if context.className != "" { + info.Class = context.className + } + + if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { + // c.Printf(c.Str("symbol:%s\n"), symbol.CStr()) + + typeStr := cursor.ResultType().String() + defer typeStr.Dispose() + info.ReturnType = c.GoString(typeStr.CStr()) + // c.Printf(c.Str("Parameters(%d): ( "), cursor.NumArguments()) + + info.Parameters = make([]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] = Parameter{ + Name: c.GoString(argName.CStr()), + Type: c.GoString(argType.CStr()), + } + + argType.Dispose() + argName.Dispose() + } + + // fmt.Println("location", info.Location) + // fmt.Println("symbol:", info.Symbol) + // fmt.Println("name:", info.Name) + // if info.Namespace != "" { + // fmt.Println("namespace:", info.Namespace) + // } + // if info.Class != "" { + // fmt.Println("class:", info.Class) + // } + // fmt.Println("return type:", info.ReturnType) + + // if len(info.Parameters) != 0 { + // fmt.Println("Parameters:(") + // for _, param := range info.Parameters { + // fmt.Println(" ", param.Name, ":", param.Type) + // } + // fmt.Println(")") + // } + // println("--------------------------------") + } + + return info +} + +func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult { + if cursor.Kind == clang.Namespace { + nameStr := cursor.String() + context.setNamespaceName(c.GoString(nameStr.CStr())) + clang.VisitChildren(cursor, visit, nil) + context.setNamespaceName("") + } else if cursor.Kind == clang.ClassDecl { + nameStr := cursor.String() + context.setClassName(c.GoString(nameStr.CStr())) + clang.VisitChildren(cursor, visit, nil) + context.setClassName("") + } else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { + info := collectFuncInfo(cursor) + context.astInfo = append(context.astInfo, info) + } + + return clang.ChildVisit_Continue +} + +func parse(filename *c.Char) []ASTInformation { + 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") + unit := index.ParseTranslationUnit( + filename, + unsafe.SliceData(args), 3, + nil, 0, + clang.TranslationUnit_None, + ) + + if unit == nil { + println("Unable to parse translation unit. Quitting.") + c.Exit(1) + } + + cursor := unit.Cursor() + + clang.VisitChildren(cursor, visit, nil) + + unit.Dispose() + index.Dispose() + + return context.astInfo +} +func printJson(infos []ASTInformation) { + root := cjson.Array() + + for _, info := range infos { + item := cjson.Object() + item.SetItem(c.Str("namespace"), cjson.String(c.AllocaCStr(info.Namespace))) + item.SetItem(c.Str("class"), cjson.String(c.AllocaCStr(info.Class))) + item.SetItem(c.Str("name"), cjson.String(c.AllocaCStr(info.Name))) + item.SetItem(c.Str("returnType"), cjson.String(c.AllocaCStr(info.ReturnType))) + item.SetItem(c.Str("location"), cjson.String(c.AllocaCStr(info.Location))) + item.SetItem(c.Str("symbol"), cjson.String(c.AllocaCStr(info.Symbol))) + + params := cjson.Array() + for _, param := range info.Parameters { + paramObj := cjson.Object() + paramObj.SetItem(c.Str("name"), cjson.String(c.AllocaCStr(param.Name))) + paramObj.SetItem(c.Str("type"), cjson.String(c.AllocaCStr(param.Type))) + params.AddItem(paramObj) + } + item.SetItem(c.Str("parameters"), params) + + root.AddItem(item) + } + c.Printf(c.Str("%s\n"), root.Print()) +} + +func main() { + // for i := c.Int(0); i < c.Argc; i++ { + // c.Printf(c.Str("%s\n"), c.Index(c.Argv, i)) + // } + // c.Printf(c.Str("c.Index %s\n"), c.Index(c.Argv, 1)) + // c.Printf(c.Str("c.Index %s\n"), *c.Advance(c.Argv, 1)) + + if c.Argc != 2 { + fmt.Fprintln(os.Stderr, "Usage: \n") + return + } else { + // sourceFile := *c.Advance(c.Argv, 1) + printJson(parse(c.Index(c.Argv, 1))) + // fmt.Println("Json end") + } + +} From c53484f92ed98c3d526404d526820c3abdae106e Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 26 Jul 2024 14:37:26 +0800 Subject: [PATCH 03/24] c/clang/symg:normal gen json --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 7 +++++++ chore/_xtool/llcppsymg/llcppg.cfg | 3 +-- chore/_xtool/llcppsymg/llcppsymg.go | 17 +++++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go index 333dd7dd..a7b2c9c4 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -70,7 +70,13 @@ func collectFuncInfo(cursor clang.Cursor) ASTInformation { 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:] + } + } defer symbol.Dispose() defer cursorStr.Dispose() @@ -212,6 +218,7 @@ func main() { fmt.Fprintln(os.Stderr, "Usage: \n") return } else { + // sourceFile := *c.Advance(c.Argv, 1) printJson(parse(c.Index(c.Argv, 1))) // fmt.Println("Json end") diff --git a/chore/_xtool/llcppsymg/llcppg.cfg b/chore/_xtool/llcppsymg/llcppg.cfg index b5335e2c..163284b3 100644 --- a/chore/_xtool/llcppsymg/llcppg.cfg +++ b/chore/_xtool/llcppsymg/llcppg.cfg @@ -2,8 +2,7 @@ "name": "inih", "cflags": "$(pkg-config --cflags INIReader)", "include": [ - "INIReader.h", - "AnotherHeaderFile.h" + "INIReader.h" ], "libs": "$(pkg-config --libs INIReader)", "trimPrefixes": ["Ini", "INI"] diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index db4bc1e4..dafd21d8 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -22,8 +22,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" - "github.com/goplus/llgo/chore/llcppg/types" "io" "os" "os/exec" @@ -31,6 +29,9 @@ import ( "regexp" "strconv" "strings" + + "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" + "github.com/goplus/llgo/chore/llcppg/types" ) func main() { @@ -161,11 +162,16 @@ func decodeSymbolName(symbolName string) (string, error) { // parseHeaderFile func parseHeaderFile(config types.Config) ([]common.ASTInformation, error) { files := generateHeaderFilePath(config.CFlags, config.Include) + fmt.Println(files) headerFileCmd := exec.Command("llcppinfofetch", files...) + + fmt.Println("Executing command:", headerFileCmd.String()) + headerFileOutput, err := headerFileCmd.Output() if err != nil { return nil, errors.New("failed to execute header file command") } + fmt.Println("headerFileOutput:", string(headerFileOutput), len(headerFileOutput)) t := make([]common.ASTInformation, 0) err = json.Unmarshal(headerFileOutput, &t) if err != nil { @@ -234,11 +240,14 @@ func generateMangle(astInfo common.ASTInformation, count int) string { res += "__" + strconv.Itoa(count-1) } } else { - res = "(*" + astInfo.Class + ")." + astInfo.Name + "__" + string(rune(count)) + res = "(*" + astInfo.Class + ")." + astInfo.Name + if count > 1 { + res += "__" + strconv.Itoa(count-1) + } } } else { res = astInfo.Name - if count > 0 { + if count > 1 { res += "__" + strconv.Itoa(count-1) } } From ce36a25ba39ef29c7c6ede27612c0394322ed17e Mon Sep 17 00:00:00 2001 From: morpingsss Date: Fri, 26 Jul 2024 15:00:06 +0800 Subject: [PATCH 04/24] feat(llgo/xtools): add TrimPrefix --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 33 +++++-------------- chore/_xtool/llcppsymg/llcppsymg.go | 28 +++++++++++----- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go index a7b2c9c4..177d2400 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" "os" "strconv" "unsafe" @@ -11,31 +12,15 @@ import ( "github.com/goplus/llgo/c/clang" ) -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 Context struct { namespaceName string className string - astInfo []ASTInformation + astInfo []common.ASTInformation } func newContext() *Context { return &Context{ - astInfo: make([]ASTInformation, 0), + astInfo: make([]common.ASTInformation, 0), } } @@ -49,8 +34,8 @@ func (c *Context) setClassName(name string) { var context = newContext() -func collectFuncInfo(cursor clang.Cursor) ASTInformation { - info := ASTInformation{ +func collectFuncInfo(cursor clang.Cursor) common.ASTInformation { + info := common.ASTInformation{ Namespace: context.namespaceName, Class: context.className, } @@ -97,12 +82,12 @@ func collectFuncInfo(cursor clang.Cursor) ASTInformation { info.ReturnType = c.GoString(typeStr.CStr()) // c.Printf(c.Str("Parameters(%d): ( "), cursor.NumArguments()) - info.Parameters = make([]Parameter, cursor.NumArguments()) + info.Parameters = make([]common.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] = Parameter{ + info.Parameters[i] = common.Parameter{ Name: c.GoString(argName.CStr()), Type: c.GoString(argType.CStr()), } @@ -154,7 +139,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe return clang.ChildVisit_Continue } -func parse(filename *c.Char) []ASTInformation { +func parse(filename *c.Char) []common.ASTInformation { index := clang.CreateIndex(0, 0) args := make([]*c.Char, 3) args[0] = c.Str("-x") @@ -181,7 +166,7 @@ func parse(filename *c.Char) []ASTInformation { return context.astInfo } -func printJson(infos []ASTInformation) { +func printJson(infos []common.ASTInformation) { root := cjson.Array() for _, info := range infos { diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index dafd21d8..54e6b445 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -35,10 +35,10 @@ import ( ) func main() { - cfgFile := "llcppg.cfg" - if len(os.Args) > 1 { - cfgFile = os.Args[1] - } + cfgFile := "/Users/lixianyu/go/src/llgo/chore/_xtool/llcppsymg/llcppg.cfg" + //if len(os.Args) > 1 { + // cfgFile = os.Args[1] + //} var data []byte var err error @@ -59,7 +59,7 @@ func main() { files, err := parseHeaderFile(config) check(err) - symbolInfo := getCommonSymbols(symbols, files) + symbolInfo := getCommonSymbols(symbols, files, config.TrimPrefixes) jsonData, err := json.MarshalIndent(symbolInfo, "", " ") check(err) @@ -195,7 +195,7 @@ func generateHeaderFilePath(cflags string, files []string) []string { return includePaths } -func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTInformation) []common.SymbolInfo { +func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTInformation, prefix []string) []common.SymbolInfo { var commonSymbols []common.SymbolInfo functionNameMap := make(map[string]int) @@ -207,7 +207,7 @@ func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTI symbolInfo := common.SymbolInfo{ Mangle: dylibSym.Symbol, CPP: cppName, - Go: generateMangle(astInfo, functionNameMap[cppName]), + Go: generateMangle(astInfo, functionNameMap[cppName], prefix), } commonSymbols = append(commonSymbols, symbolInfo) break @@ -226,7 +226,10 @@ func generateCPPName(astInfo common.ASTInformation) string { return cppName } -func generateMangle(astInfo common.ASTInformation, count int) string { +func generateMangle(astInfo common.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 { @@ -254,6 +257,15 @@ func generateMangle(astInfo common.ASTInformation, count int) string { 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 +} + var ( reSubcmd = regexp.MustCompile(`\$\([^)]+\)`) reFlag = regexp.MustCompile(`[^ \t\n]+`) From 2c7f0e85833c1eb79f3df0606bfed3927477a35d Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 26 Jul 2024 15:14:19 +0800 Subject: [PATCH 05/24] c/clang/symg:get constructor & destructor --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 69 +++++-------------- chore/_xtool/llcppsymg/llcppsymg.go | 2 +- 2 files changed, 19 insertions(+), 52 deletions(-) diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go index 177d2400..c8e918b1 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -2,11 +2,12 @@ package main import ( "fmt" - "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" "os" "strconv" "unsafe" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" + "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" "github.com/goplus/llgo/c/clang" @@ -74,47 +75,22 @@ func collectFuncInfo(cursor clang.Cursor) common.ASTInformation { info.Class = context.className } - if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { - // c.Printf(c.Str("symbol:%s\n"), symbol.CStr()) + typeStr := cursor.ResultType().String() + defer typeStr.Dispose() + info.ReturnType = c.GoString(typeStr.CStr()) - typeStr := cursor.ResultType().String() - defer typeStr.Dispose() - info.ReturnType = c.GoString(typeStr.CStr()) - // c.Printf(c.Str("Parameters(%d): ( "), cursor.NumArguments()) - - info.Parameters = make([]common.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] = common.Parameter{ - Name: c.GoString(argName.CStr()), - Type: c.GoString(argType.CStr()), - } - - argType.Dispose() - argName.Dispose() + info.Parameters = make([]common.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] = common.Parameter{ + Name: c.GoString(argName.CStr()), + Type: c.GoString(argType.CStr()), } - // fmt.Println("location", info.Location) - // fmt.Println("symbol:", info.Symbol) - // fmt.Println("name:", info.Name) - // if info.Namespace != "" { - // fmt.Println("namespace:", info.Namespace) - // } - // if info.Class != "" { - // fmt.Println("class:", info.Class) - // } - // fmt.Println("return type:", info.ReturnType) - - // if len(info.Parameters) != 0 { - // fmt.Println("Parameters:(") - // for _, param := range info.Parameters { - // fmt.Println(" ", param.Name, ":", param.Type) - // } - // fmt.Println(")") - // } - // println("--------------------------------") + argType.Dispose() + argName.Dispose() } return info @@ -131,7 +107,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe context.setClassName(c.GoString(nameStr.CStr())) clang.VisitChildren(cursor, visit, nil) context.setClassName("") - } else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { + } else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl || cursor.Kind == clang.Constructor || cursor.Kind == clang.Destructor { info := collectFuncInfo(cursor) context.astInfo = append(context.astInfo, info) } @@ -193,20 +169,11 @@ func printJson(infos []common.ASTInformation) { } func main() { - // for i := c.Int(0); i < c.Argc; i++ { - // c.Printf(c.Str("%s\n"), c.Index(c.Argv, i)) - // } - // c.Printf(c.Str("c.Index %s\n"), c.Index(c.Argv, 1)) - // c.Printf(c.Str("c.Index %s\n"), *c.Advance(c.Argv, 1)) - - if c.Argc != 2 { + if c.Argc < 2 { fmt.Fprintln(os.Stderr, "Usage: \n") return } else { - - // sourceFile := *c.Advance(c.Argv, 1) + // todo(zzy): receive files printJson(parse(c.Index(c.Argv, 1))) - // fmt.Println("Json end") } - } diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 54e6b445..6547ebf6 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -35,7 +35,7 @@ import ( ) func main() { - cfgFile := "/Users/lixianyu/go/src/llgo/chore/_xtool/llcppsymg/llcppg.cfg" + cfgFile := "llcppg.cfg" //if len(os.Args) > 1 { // cfgFile = os.Args[1] //} From 3bd609ee41ffe95464c3b95f73a852e8ac6f2dfb Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 26 Jul 2024 15:56:47 +0800 Subject: [PATCH 06/24] c/clang/symg:filter unuse file --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go index c8e918b1..d2f57ae3 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -17,6 +17,7 @@ type Context struct { namespaceName string className string astInfo []common.ASTInformation + filename *c.Char } func newContext() *Context { @@ -33,25 +34,19 @@ func (c *Context) setClassName(name string) { c.className = name } +func (c *Context) setFilename(filename *c.Char) { + c.filename = filename +} + var context = newContext() func collectFuncInfo(cursor clang.Cursor) common.ASTInformation { + info := common.ASTInformation{ Namespace: context.namespaceName, Class: context.className, } - loc := cursor.Location() - var file clang.File - var line, column c.Uint - - loc.SpellingLocation(&file, &line, &column, nil) - filename := file.FileName() - - info.Location = c.GoString(filename.CStr()) + ":" + strconv.Itoa(int(line)) + ":" + strconv.Itoa(int(column)) - - // c.Printf(c.Str("%s:%d:%d\n"), filename.CStr(), line, column) - cursorStr := cursor.String() symbol := cursor.Mangling() @@ -66,7 +61,6 @@ func collectFuncInfo(cursor clang.Cursor) common.ASTInformation { defer symbol.Dispose() defer cursorStr.Dispose() - defer filename.Dispose() if context.namespaceName != "" { info.Namespace = context.namespaceName @@ -108,8 +102,21 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe 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 { - info := collectFuncInfo(cursor) - context.astInfo = append(context.astInfo, info) + loc := cursor.Location() + var file clang.File + var line, column c.Uint + + loc.SpellingLocation(&file, &line, &column, nil) + filename := file.FileName() + + if c.Strcmp(filename.CStr(), context.filename) == 0 { + info := collectFuncInfo(cursor) + info.Location = c.GoString(filename.CStr()) + ":" + strconv.Itoa(int(line)) + ":" + strconv.Itoa(int(column)) + context.astInfo = append(context.astInfo, info) + } + + defer filename.Dispose() + } return clang.ChildVisit_Continue @@ -120,6 +127,7 @@ func parse(filename *c.Char) []common.ASTInformation { args := make([]*c.Char, 3) args[0] = c.Str("-x") args[1] = c.Str("c++") + args[1] = c.Str("c++") args[2] = c.Str("-std=c++11") unit := index.ParseTranslationUnit( filename, @@ -134,6 +142,7 @@ func parse(filename *c.Char) []common.ASTInformation { } cursor := unit.Cursor() + context.setFilename(filename) clang.VisitChildren(cursor, visit, nil) From 9a46301d46651832d0acdde0f8748d5f14b3041d Mon Sep 17 00:00:00 2001 From: morpingsss Date: Fri, 26 Jul 2024 16:13:20 +0800 Subject: [PATCH 07/24] feat(llgo/xtools): delete chinese --- chore/_xtool/llcppsymg/llcppsymg.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 6547ebf6..0597e6a6 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -36,9 +36,9 @@ import ( func main() { cfgFile := "llcppg.cfg" - //if len(os.Args) > 1 { - // cfgFile = os.Args[1] - //} + if len(os.Args) > 1 { + cfgFile = os.Args[1] + } var data []byte var err error @@ -66,7 +66,7 @@ func main() { // 写入文件 fileName := "llcppg.symb.json" - err = os.WriteFile(fileName, jsonData, 0644) // 使用 0644 权限 + err = os.WriteFile(fileName, jsonData, 0644) check(err) } @@ -99,16 +99,14 @@ func parseDylibSymbols(lib string) ([]common.CPPSymbol, error) { } func generateDylibPath(lib string) (string, error) { - // 执行pkg-config命令 output := expandEnv(lib) - // 解析输出 libPath := "" libName := "" for _, part := range strings.Fields(string(output)) { if strings.HasPrefix(part, "-L") { - libPath = part[2:] // 去掉-L前缀 + libPath = part[2:] } else if strings.HasPrefix(part, "-l") { - libName = part[2:] // 去掉-l前缀 + libName = part[2:] } } @@ -154,7 +152,6 @@ func decodeSymbolName(symbolName string) (string, error) { } decodedName := strings.TrimSpace(string(cppfiltOutput)) - // 将特定的模板类型转换为 std::string decodedName = strings.ReplaceAll(decodedName, "std::__1::basic_string, std::__1::allocator > const", "std::string") return decodedName, nil } @@ -181,12 +178,11 @@ func parseHeaderFile(config types.Config) ([]common.ASTInformation, error) { } func generateHeaderFilePath(cflags string, files []string) []string { - // 执行pkg-config命令 prefixPath := expandEnv(cflags) if strings.HasPrefix(prefixPath, "-I") { prefixPath = prefixPath[2:] } - // 去掉首尾空白字符(包括换行符) + prefixPath = strings.TrimSpace(prefixPath) var includePaths []string for _, file := range files { From f0d17b13f288c4c1e0f601bfa4932455ecde8411 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 26 Jul 2024 17:09:26 +0800 Subject: [PATCH 08/24] c/clang/symg:multiple header file --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go index d2f57ae3..7dd09777 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -17,7 +17,7 @@ type Context struct { namespaceName string className string astInfo []common.ASTInformation - filename *c.Char + currentFile *c.Char } func newContext() *Context { @@ -34,8 +34,8 @@ func (c *Context) setClassName(name string) { c.className = name } -func (c *Context) setFilename(filename *c.Char) { - c.filename = filename +func (c *Context) setCurrentFile(filename *c.Char) { + c.currentFile = filename } var context = newContext() @@ -109,7 +109,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe loc.SpellingLocation(&file, &line, &column, nil) filename := file.FileName() - if c.Strcmp(filename.CStr(), context.filename) == 0 { + if c.Strcmp(filename.CStr(), 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) @@ -122,31 +122,34 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe return clang.ChildVisit_Continue } -func parse(filename *c.Char) []common.ASTInformation { +func parse(filenames []*c.Char) []common.ASTInformation { index := clang.CreateIndex(0, 0) args := make([]*c.Char, 3) args[0] = c.Str("-x") args[1] = c.Str("c++") - args[1] = c.Str("c++") args[2] = c.Str("-std=c++11") - unit := index.ParseTranslationUnit( - filename, - unsafe.SliceData(args), 3, - nil, 0, - clang.TranslationUnit_None, - ) - if unit == nil { - println("Unable to parse translation unit. Quitting.") - c.Exit(1) + for _, filename := range filenames { + unit := index.ParseTranslationUnit( + filename, + unsafe.SliceData(args), 3, + nil, 0, + clang.TranslationUnit_None, + ) + + if unit == nil { + fmt.Printf("Unable to parse translation unit for file: %s. Skipping.\n", c.GoString(filename)) + continue + } + + cursor := unit.Cursor() + context.setCurrentFile(filename) + + clang.VisitChildren(cursor, visit, nil) + + unit.Dispose() } - cursor := unit.Cursor() - context.setFilename(filename) - - clang.VisitChildren(cursor, visit, nil) - - unit.Dispose() index.Dispose() return context.astInfo @@ -176,13 +179,15 @@ func printJson(infos []common.ASTInformation) { } c.Printf(c.Str("%s\n"), root.Print()) } - func main() { if c.Argc < 2 { - fmt.Fprintln(os.Stderr, "Usage: \n") + fmt.Fprintln(os.Stderr, "Usage: [ ...]\n") return } else { - // todo(zzy): receive files - printJson(parse(c.Index(c.Argv, 1))) + filenames := make([]*c.Char, c.Argc-1) + for i := 1; i < int(c.Argc); i++ { + filenames[i-1] = c.Index(c.Argv, c.Int(i)) + } + printJson(parse(filenames)) } } From 0d3180271bbf6164755edd8ed9994337cb20c5f8 Mon Sep 17 00:00:00 2001 From: morpingsss Date: Mon, 29 Jul 2024 10:52:10 +0800 Subject: [PATCH 09/24] feat(llgo/chore/llcppg): add JSONPath --- chore/_xtool/llcppsymg/llcppsymg.go | 10 +++++++++- chore/llcppg/types/types.go | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 0597e6a6..03614a9b 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -64,11 +64,19 @@ func main() { jsonData, err := json.MarshalIndent(symbolInfo, "", " ") check(err) - // 写入文件 fileName := "llcppg.symb.json" err = os.WriteFile(fileName, jsonData, 0644) check(err) + absJSONPath, err := filepath.Abs(fileName) + check(err) + + config.JSONPath = absJSONPath + updatedCfgData, err := json.MarshalIndent(config, "", " ") + check(err) + + err = os.WriteFile(cfgFile, updatedCfgData, 0644) + check(err) } func check(err error) { diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index 2e39bbdd..91ac3a5b 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -23,4 +23,5 @@ type Config struct { Libs string `json:"libs"` Include []string `json:"include"` TrimPrefixes []string `json:"trimPrefixes"` + JSONPath string `json:"jsonPath"` } From 1e3aef5b94cbb520ae480f68a97fd3affe283c70 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 10:57:04 +0800 Subject: [PATCH 10/24] c/clang/symg:remove chinese --- chore/_xtool/llcppsymg/llcppsymg.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 03614a9b..f0907a50 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -122,7 +122,6 @@ func generateDylibPath(lib string) (string, error) { return "", fmt.Errorf("failed to parse pkg-config output: %s", output) } - // 构造dylib路径 dylibPath := filepath.Join(libPath, "lib"+libName+".dylib") return dylibPath, nil } @@ -231,7 +230,6 @@ func generateCPPName(astInfo common.ASTInformation) string { } func generateMangle(astInfo common.ASTInformation, count int, prefixes []string) string { - // 去除前缀 astInfo.Class = removePrefix(astInfo.Class, prefixes) astInfo.Name = removePrefix(astInfo.Name, prefixes) res := "" From c8532a548ccbd564534ed33cfac82fd82fb860d0 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 11:21:36 +0800 Subject: [PATCH 11/24] c/clang/symg:abstract common type --- chore/_xtool/llcppinfofetch/llcppinfofetch.go | 18 +++++----- chore/_xtool/llcppsymg/common/common.go | 29 ---------------- chore/_xtool/llcppsymg/llcppsymg.go | 33 ++++++++----------- chore/llcppg/types/types.go | 28 ++++++++++++++++ 4 files changed, 50 insertions(+), 58 deletions(-) delete mode 100644 chore/_xtool/llcppsymg/common/common.go diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppinfofetch/llcppinfofetch.go index 7dd09777..374aa252 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppinfofetch/llcppinfofetch.go @@ -6,7 +6,7 @@ import ( "strconv" "unsafe" - "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" + "github.com/goplus/llgo/chore/llcppg/types" "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" @@ -16,13 +16,13 @@ import ( type Context struct { namespaceName string className string - astInfo []common.ASTInformation + astInfo []types.ASTInformation currentFile *c.Char } func newContext() *Context { return &Context{ - astInfo: make([]common.ASTInformation, 0), + astInfo: make([]types.ASTInformation, 0), } } @@ -40,9 +40,9 @@ func (c *Context) setCurrentFile(filename *c.Char) { var context = newContext() -func collectFuncInfo(cursor clang.Cursor) common.ASTInformation { +func collectFuncInfo(cursor clang.Cursor) types.ASTInformation { - info := common.ASTInformation{ + info := types.ASTInformation{ Namespace: context.namespaceName, Class: context.className, } @@ -73,12 +73,12 @@ func collectFuncInfo(cursor clang.Cursor) common.ASTInformation { defer typeStr.Dispose() info.ReturnType = c.GoString(typeStr.CStr()) - info.Parameters = make([]common.Parameter, cursor.NumArguments()) + 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] = common.Parameter{ + info.Parameters[i] = types.Parameter{ Name: c.GoString(argName.CStr()), Type: c.GoString(argType.CStr()), } @@ -122,7 +122,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe return clang.ChildVisit_Continue } -func parse(filenames []*c.Char) []common.ASTInformation { +func parse(filenames []*c.Char) []types.ASTInformation { index := clang.CreateIndex(0, 0) args := make([]*c.Char, 3) args[0] = c.Str("-x") @@ -154,7 +154,7 @@ func parse(filenames []*c.Char) []common.ASTInformation { return context.astInfo } -func printJson(infos []common.ASTInformation) { +func printJson(infos []types.ASTInformation) { root := cjson.Array() for _, info := range infos { diff --git a/chore/_xtool/llcppsymg/common/common.go b/chore/_xtool/llcppsymg/common/common.go deleted file mode 100644 index 35fed532..00000000 --- a/chore/_xtool/llcppsymg/common/common.go +++ /dev/null @@ -1,29 +0,0 @@ -package common - -type CPPSymbol struct { - Symbol string `json:"symbol"` - Type string `json:"type"` - Name string `json:"name"` -} - -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 - Go string `json:"go"` // Go function name -} diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index f0907a50..da1be9bc 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -30,7 +30,6 @@ import ( "strconv" "strings" - "github.com/goplus/llgo/chore/_xtool/llcppsymg/common" "github.com/goplus/llgo/chore/llcppg/types" ) @@ -85,7 +84,7 @@ func check(err error) { } } -func parseDylibSymbols(lib string) ([]common.CPPSymbol, error) { +func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { dylibPath, _ := generateDylibPath(lib) nmCmd := exec.Command("nm", "-gU", dylibPath) nmOutput, err := nmCmd.Output() @@ -126,9 +125,9 @@ func generateDylibPath(lib string) (string, error) { return dylibPath, nil } -func parseNmOutput(output []byte) []common.CPPSymbol { +func parseNmOutput(output []byte) []types.CPPSymbol { scanner := bufio.NewScanner(bytes.NewReader(output)) - var symbols []common.CPPSymbol + var symbols []types.CPPSymbol for scanner.Scan() { line := scanner.Text() @@ -138,10 +137,8 @@ func parseNmOutput(output []byte) []common.CPPSymbol { } symbolName := fields[2] // Check if the symbol name starts with an underscore and remove it if present - if strings.HasPrefix(symbolName, "_") { - symbolName = symbolName[1:] - } - symbols = append(symbols, common.CPPSymbol{ + symbolName = strings.TrimPrefix(symbolName, "_") + symbols = append(symbols, types.CPPSymbol{ Symbol: symbolName, Type: fields[1], Name: fields[2], @@ -164,7 +161,7 @@ func decodeSymbolName(symbolName string) (string, error) { } // parseHeaderFile -func parseHeaderFile(config types.Config) ([]common.ASTInformation, error) { +func parseHeaderFile(config types.Config) ([]types.ASTInformation, error) { files := generateHeaderFilePath(config.CFlags, config.Include) fmt.Println(files) headerFileCmd := exec.Command("llcppinfofetch", files...) @@ -176,7 +173,7 @@ func parseHeaderFile(config types.Config) ([]common.ASTInformation, error) { return nil, errors.New("failed to execute header file command") } fmt.Println("headerFileOutput:", string(headerFileOutput), len(headerFileOutput)) - t := make([]common.ASTInformation, 0) + t := make([]types.ASTInformation, 0) err = json.Unmarshal(headerFileOutput, &t) if err != nil { return nil, err @@ -186,11 +183,7 @@ func parseHeaderFile(config types.Config) ([]common.ASTInformation, error) { func generateHeaderFilePath(cflags string, files []string) []string { prefixPath := expandEnv(cflags) - if strings.HasPrefix(prefixPath, "-I") { - prefixPath = prefixPath[2:] - } - - prefixPath = strings.TrimSpace(prefixPath) + prefixPath = strings.TrimPrefix(prefixPath, "-I") var includePaths []string for _, file := range files { includePaths = append(includePaths, filepath.Join(prefixPath, "/"+file)) @@ -198,8 +191,8 @@ func generateHeaderFilePath(cflags string, files []string) []string { return includePaths } -func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTInformation, prefix []string) []common.SymbolInfo { - var commonSymbols []common.SymbolInfo +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 { @@ -207,7 +200,7 @@ func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTI if dylibSym.Symbol == astInfo.Symbol { cppName := generateCPPName(astInfo) functionNameMap[cppName]++ - symbolInfo := common.SymbolInfo{ + symbolInfo := types.SymbolInfo{ Mangle: dylibSym.Symbol, CPP: cppName, Go: generateMangle(astInfo, functionNameMap[cppName], prefix), @@ -221,7 +214,7 @@ func getCommonSymbols(dylibSymbols []common.CPPSymbol, astInfoList []common.ASTI return commonSymbols } -func generateCPPName(astInfo common.ASTInformation) string { +func generateCPPName(astInfo types.ASTInformation) string { cppName := astInfo.Name if astInfo.Class != "" { cppName = astInfo.Class + "::" + astInfo.Name @@ -229,7 +222,7 @@ func generateCPPName(astInfo common.ASTInformation) string { return cppName } -func generateMangle(astInfo common.ASTInformation, count int, prefixes []string) string { +func generateMangle(astInfo types.ASTInformation, count int, prefixes []string) string { astInfo.Class = removePrefix(astInfo.Class, prefixes) astInfo.Name = removePrefix(astInfo.Name, prefixes) res := "" diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index 91ac3a5b..e71885ef 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -25,3 +25,31 @@ type Config struct { TrimPrefixes []string `json:"trimPrefixes"` JSONPath string `json:"jsonPath"` } + +type CPPSymbol struct { + Symbol string `json:"symbol"` + Type string `json:"type"` + Name string `json:"name"` +} + +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 + Go string `json:"go"` // Go function name +} From f427c0532d463ea491bc722d57aabdfb27bf8782 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 15:09:54 +0800 Subject: [PATCH 12/24] c/clang/symg:use cjson get conf --- c/cjson/cjson.go | 14 ++++++ chore/_xtool/llcppsymg/llcppsymg.go | 75 +++++++++++------------------ 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/c/cjson/cjson.go b/c/cjson/cjson.go index 21c0d1b0..51edb48e 100644 --- a/c/cjson/cjson.go +++ b/c/cjson/cjson.go @@ -134,6 +134,20 @@ func (o *JSON) PrintUnformatted() *c.Char { return nil } // llgo:link (*JSON).PrintBuffered C.cJSON_PrintBuffered func (o *JSON) PrintBuffered(prebuffer c.Int, fmt c.Int) *c.Char { return nil } +// llgo:link (*JSON).GetObjectItemCaseSensitive C.cJSON_GetObjectItemCaseSensitive +func (o *JSON) GetObjectItemCaseSensitive(key *c.Char) *JSON { return nil } + +func (o *JSON) GetItem(key string) *JSON { return o.GetObjectItemCaseSensitive(c.AllocaCStr(key)) } + +// llgo:link (*JSON).GetArraySize C.cJSON_GetArraySize +func (o *JSON) GetArraySize() c.Int { return 0 } + +// llgo:link (*JSON).GetArrayItem C.cJSON_GetArrayItem +func (o *JSON) GetArrayItem(index c.Int) *JSON { return nil } + +// llgo:link (*JSON).GetStringValue C.cJSON_GetStringValue +func (o *JSON) GetStringValue() *c.Char { return nil } + //go:linkname Free C.cJSON_free func Free(ptr unsafe.Pointer) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index da1be9bc..cfc05998 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -26,10 +26,11 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "strconv" "strings" + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" "github.com/goplus/llgo/chore/llcppg/types" ) @@ -48,9 +49,10 @@ func main() { } check(err) - var config types.Config - err = json.Unmarshal(data, &config) - check(err) + config, err := getConf(data) + if err != nil { + fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) + } symbols, err := parseDylibSymbols(config.Libs) check(err) @@ -84,6 +86,26 @@ func check(err error) { } } +func getConf(data []byte) (config types.Config, err error) { + conf := cjson.ParseBytes(data) + defer conf.Delete() + if conf == nil { + return config, errors.New("failed to execute nm command") + } + config.Name = c.GoString(conf.GetItem("name").GetStringValue()) + config.CFlags = c.GoString(conf.GetItem("cflags").GetStringValue()) + config.Libs = c.GoString(conf.GetItem("libs").GetStringValue()) + config.Include = make([]string, conf.GetItem("include").GetArraySize()) + for i := range config.Include { + config.Include[i] = c.GoString(conf.GetItem("include").GetArrayItem(c.Int(i)).GetStringValue()) + } + config.TrimPrefixes = make([]string, conf.GetItem("trimPrefixes").GetArraySize()) + for i := range config.TrimPrefixes { + config.TrimPrefixes[i] = c.GoString(conf.GetItem("trimPrefixes").GetArrayItem(c.Int(i)).GetStringValue()) + } + return +} + func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { dylibPath, _ := generateDylibPath(lib) nmCmd := exec.Command("nm", "-gU", dylibPath) @@ -106,7 +128,7 @@ func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { } func generateDylibPath(lib string) (string, error) { - output := expandEnv(lib) + output := lib libPath := "" libName := "" for _, part := range strings.Fields(string(output)) { @@ -160,7 +182,6 @@ func decodeSymbolName(symbolName string) (string, error) { return decodedName, nil } -// parseHeaderFile func parseHeaderFile(config types.Config) ([]types.ASTInformation, error) { files := generateHeaderFilePath(config.CFlags, config.Include) fmt.Println(files) @@ -182,7 +203,7 @@ func parseHeaderFile(config types.Config) ([]types.ASTInformation, error) { } func generateHeaderFilePath(cflags string, files []string) []string { - prefixPath := expandEnv(cflags) + prefixPath := cflags prefixPath = strings.TrimPrefix(prefixPath, "-I") var includePaths []string for _, file := range files { @@ -260,43 +281,3 @@ func removePrefix(str string, prefixes []string) string { } return str } - -var ( - reSubcmd = regexp.MustCompile(`\$\([^)]+\)`) - reFlag = regexp.MustCompile(`[^ \t\n]+`) -) - -func expandEnv(s string) string { - return expandEnvWithCmd(s) -} - -func expandEnvWithCmd(s string) string { - expanded := reSubcmd.ReplaceAllStringFunc(s, func(m string) string { - subcmd := strings.TrimSpace(s[2 : len(s)-1]) - - args := parseSubcmd(subcmd) - - cmd := args[0] - - if cmd != "pkg-config" && cmd != "llvm-config" { - fmt.Fprintf(os.Stderr, "expand cmd only support pkg-config and llvm-config: '%s'\n", subcmd) - return "" - } - - var out []byte - var err error - out, err = exec.Command(cmd, args[1:]...).Output() - - if err != nil { - // TODO(kindy): log in verbose mode - return "" - } - - return string(out) - }) - return os.Expand(expanded, os.Getenv) -} - -func parseSubcmd(s string) []string { - return reFlag.FindAllString(s, -1) -} From 01d0338851a3c3cbeaa6fc8ab3856c81bccf0d95 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 17:21:32 +0800 Subject: [PATCH 13/24] c/clang/symg:use llvm to demangle name --- chore/_xtool/llcppsymg/llcppsymg.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index cfc05998..00486d13 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -32,6 +32,7 @@ import ( "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" "github.com/goplus/llgo/chore/llcppg/types" + "github.com/goplus/llgo/cpp/llvm" ) func main() { @@ -53,8 +54,8 @@ func main() { if err != nil { fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) } - symbols, err := parseDylibSymbols(config.Libs) + check(err) files, err := parseHeaderFile(config) @@ -109,7 +110,7 @@ func getConf(data []byte) (config types.Config, err error) { func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { dylibPath, _ := generateDylibPath(lib) nmCmd := exec.Command("nm", "-gU", dylibPath) - nmOutput, err := nmCmd.Output() + nmOutput, err := nmCmd.Output() // maybe lock if err != nil { return nil, errors.New("failed to execute nm command") } @@ -171,13 +172,9 @@ func parseNmOutput(output []byte) []types.CPPSymbol { } func decodeSymbolName(symbolName string) (string, error) { - cppfiltCmd := exec.Command("c++filt", symbolName) - cppfiltOutput, err := cppfiltCmd.Output() - if err != nil { - return "", errors.New("failed to execute c++filt command") - } - - decodedName := strings.TrimSpace(string(cppfiltOutput)) + llvm.ItaniumDemangle(symbolName, true) + demangleName := c.GoString(llvm.ItaniumDemangle(symbolName, true)) + decodedName := strings.TrimSpace(string(demangleName)) decodedName = strings.ReplaceAll(decodedName, "std::__1::basic_string, std::__1::allocator > const", "std::string") return decodedName, nil } From 84ca145663cfd93ae0ae118c0d949bee2083f849 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 17:57:38 +0800 Subject: [PATCH 14/24] c/clang/symg:merge llcppinfofetch to llcppsymg --- chore/_xtool/llcppsymg/llcppsymg.go | 28 +----- .../parse/parse.go} | 91 +++++++++---------- 2 files changed, 46 insertions(+), 73 deletions(-) rename chore/_xtool/{llcppinfofetch/llcppinfofetch.go => llcppsymg/parse/parse.go} (65%) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 00486d13..33aabe67 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -31,6 +31,7 @@ import ( "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/llcppg/types" "github.com/goplus/llgo/cpp/llvm" ) @@ -58,10 +59,11 @@ func main() { check(err) - files, err := parseHeaderFile(config) + filepaths := generateHeaderFilePath(config.CFlags, config.Include) + astInfos, err := parse.ParseHeaderFile(filepaths) check(err) - symbolInfo := getCommonSymbols(symbols, files, config.TrimPrefixes) + symbolInfo := getCommonSymbols(symbols, astInfos, config.TrimPrefixes) jsonData, err := json.MarshalIndent(symbolInfo, "", " ") check(err) @@ -91,7 +93,7 @@ func getConf(data []byte) (config types.Config, err error) { conf := cjson.ParseBytes(data) defer conf.Delete() if conf == nil { - return config, errors.New("failed to execute nm command") + return config, errors.New("failed to parse config") } config.Name = c.GoString(conf.GetItem("name").GetStringValue()) config.CFlags = c.GoString(conf.GetItem("cflags").GetStringValue()) @@ -179,26 +181,6 @@ func decodeSymbolName(symbolName string) (string, error) { return decodedName, nil } -func parseHeaderFile(config types.Config) ([]types.ASTInformation, error) { - files := generateHeaderFilePath(config.CFlags, config.Include) - fmt.Println(files) - headerFileCmd := exec.Command("llcppinfofetch", files...) - - fmt.Println("Executing command:", headerFileCmd.String()) - - headerFileOutput, err := headerFileCmd.Output() - if err != nil { - return nil, errors.New("failed to execute header file command") - } - fmt.Println("headerFileOutput:", string(headerFileOutput), len(headerFileOutput)) - t := make([]types.ASTInformation, 0) - err = json.Unmarshal(headerFileOutput, &t) - if err != nil { - return nil, err - } - return t, nil -} - func generateHeaderFilePath(cflags string, files []string) []string { prefixPath := cflags prefixPath = strings.TrimPrefix(prefixPath, "-I") diff --git a/chore/_xtool/llcppinfofetch/llcppinfofetch.go b/chore/_xtool/llcppsymg/parse/parse.go similarity index 65% rename from chore/_xtool/llcppinfofetch/llcppinfofetch.go rename to chore/_xtool/llcppsymg/parse/parse.go index 374aa252..092c93fd 100644 --- a/chore/_xtool/llcppinfofetch/llcppinfofetch.go +++ b/chore/_xtool/llcppsymg/parse/parse.go @@ -1,23 +1,20 @@ -package main +package parse import ( - "fmt" - "os" + "errors" "strconv" "unsafe" - "github.com/goplus/llgo/chore/llcppg/types" - "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/cjson" "github.com/goplus/llgo/c/clang" + "github.com/goplus/llgo/chore/llcppg/types" ) type Context struct { namespaceName string className string astInfo []types.ASTInformation - currentFile *c.Char + currentFile string } func newContext() *Context { @@ -34,7 +31,7 @@ func (c *Context) setClassName(name string) { c.className = name } -func (c *Context) setCurrentFile(filename *c.Char) { +func (c *Context) setCurrentFile(filename string) { c.currentFile = filename } @@ -109,37 +106,50 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe loc.SpellingLocation(&file, &line, &column, nil) filename := file.FileName() - if c.Strcmp(filename.CStr(), context.currentFile) == 0 { + 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) } defer filename.Dispose() - } return clang.ChildVisit_Continue } -func parse(filenames []*c.Char) []types.ASTInformation { +// func main() { +// if c.Argc < 2 { +// fmt.Fprintln(os.Stderr, "Usage: [ ...]\n") +// return +// } else { +// filenames := make([]*c.Char, c.Argc-1) +// for i := 1; i < int(c.Argc); i++ { +// filenames[i-1] = c.Index(c.Argv, c.Int(i)) +// } +// printJson(parse(filenames)) +// } +// } + +func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, 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() - for _, filename := range filenames { + for _, filename := range filepaths { unit := index.ParseTranslationUnit( - filename, + c.AllocaCStr(filename), unsafe.SliceData(args), 3, nil, 0, clang.TranslationUnit_None, ) if unit == nil { - fmt.Printf("Unable to parse translation unit for file: %s. Skipping.\n", c.GoString(filename)) - continue + return nil, errors.New("Unable to parse translation unit for file " + filename) } cursor := unit.Cursor() @@ -152,42 +162,23 @@ func parse(filenames []*c.Char) []types.ASTInformation { index.Dispose() - return context.astInfo -} -func printJson(infos []types.ASTInformation) { - root := cjson.Array() + return context.astInfo, nil - for _, info := range infos { - item := cjson.Object() - item.SetItem(c.Str("namespace"), cjson.String(c.AllocaCStr(info.Namespace))) - item.SetItem(c.Str("class"), cjson.String(c.AllocaCStr(info.Class))) - item.SetItem(c.Str("name"), cjson.String(c.AllocaCStr(info.Name))) - item.SetItem(c.Str("returnType"), cjson.String(c.AllocaCStr(info.ReturnType))) - item.SetItem(c.Str("location"), cjson.String(c.AllocaCStr(info.Location))) - item.SetItem(c.Str("symbol"), cjson.String(c.AllocaCStr(info.Symbol))) + // files := generateHeaderFilePath(config.CFlags, config.Include) + // fmt.Println(files) + // headerFileCmd := exec.Command("llcppinfofetch", files...) - params := cjson.Array() - for _, param := range info.Parameters { - paramObj := cjson.Object() - paramObj.SetItem(c.Str("name"), cjson.String(c.AllocaCStr(param.Name))) - paramObj.SetItem(c.Str("type"), cjson.String(c.AllocaCStr(param.Type))) - params.AddItem(paramObj) - } - item.SetItem(c.Str("parameters"), params) + // fmt.Println("Executing command:", headerFileCmd.String()) - root.AddItem(item) - } - c.Printf(c.Str("%s\n"), root.Print()) -} -func main() { - if c.Argc < 2 { - fmt.Fprintln(os.Stderr, "Usage: [ ...]\n") - return - } else { - filenames := make([]*c.Char, c.Argc-1) - for i := 1; i < int(c.Argc); i++ { - filenames[i-1] = c.Index(c.Argv, c.Int(i)) - } - printJson(parse(filenames)) - } + // headerFileOutput, err := headerFileCmd.Output() + // if err != nil { + // return nil, errors.New("failed to execute header file command") + // } + // fmt.Println("headerFileOutput:", string(headerFileOutput), len(headerFileOutput)) + // t := make([]types.ASTInformation, 0) + // err = json.Unmarshal(headerFileOutput, &t) + // if err != nil { + // return nil, err + // } + // return t, nil } From aca3a0522264237d1dfe99de56a4935986b3431f Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 20:36:04 +0800 Subject: [PATCH 15/24] c/clang/symg:abstract json item fetch --- c/cjson/cjson.go | 2 -- chore/_xtool/llcppsymg/llcppsymg.go | 34 +++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/c/cjson/cjson.go b/c/cjson/cjson.go index 51edb48e..af969e2d 100644 --- a/c/cjson/cjson.go +++ b/c/cjson/cjson.go @@ -137,8 +137,6 @@ func (o *JSON) PrintBuffered(prebuffer c.Int, fmt c.Int) *c.Char { return nil } // llgo:link (*JSON).GetObjectItemCaseSensitive C.cJSON_GetObjectItemCaseSensitive func (o *JSON) GetObjectItemCaseSensitive(key *c.Char) *JSON { return nil } -func (o *JSON) GetItem(key string) *JSON { return o.GetObjectItemCaseSensitive(c.AllocaCStr(key)) } - // llgo:link (*JSON).GetArraySize C.cJSON_GetArraySize func (o *JSON) GetArraySize() c.Int { return 0 } diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 33aabe67..0296e0fa 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -52,6 +52,8 @@ func main() { check(err) config, err := getConf(data) + check(err) + if err != nil { fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) } @@ -95,16 +97,30 @@ func getConf(data []byte) (config types.Config, err error) { if conf == nil { return config, errors.New("failed to parse config") } - config.Name = c.GoString(conf.GetItem("name").GetStringValue()) - config.CFlags = c.GoString(conf.GetItem("cflags").GetStringValue()) - config.Libs = c.GoString(conf.GetItem("libs").GetStringValue()) - config.Include = make([]string, conf.GetItem("include").GetArraySize()) - for i := range config.Include { - config.Include[i] = c.GoString(conf.GetItem("include").GetArrayItem(c.Int(i)).GetStringValue()) + config.Name = getStringItem(conf, "name", "") + config.CFlags = getStringItem(conf, "cflags", "") + config.Libs = getStringItem(conf, "libs", "") + config.Include = getStringArrayItem(conf, "include") + config.TrimPrefixes = getStringArrayItem(conf, "trimPrefixes") + return +} + +func getStringItem(obj *cjson.JSON, key string, defval string) (value string) { + item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key)) + if item == nil { + return defval } - config.TrimPrefixes = make([]string, conf.GetItem("trimPrefixes").GetArraySize()) - for i := range config.TrimPrefixes { - config.TrimPrefixes[i] = c.GoString(conf.GetItem("trimPrefixes").GetArrayItem(c.Int(i)).GetStringValue()) + return c.GoString(item.GetStringValue()) +} + +func getStringArrayItem(obj *cjson.JSON, key string) (value []string) { + item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key)) + if item == nil { + return + } + value = make([]string, item.GetArraySize()) + for i := range value { + value[i] = c.GoString(item.GetArrayItem(c.Int(i)).GetStringValue()) } return } From 87382aad4da77e53abd38866408a39319f765c6d Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 22:10:30 +0800 Subject: [PATCH 16/24] c/clang/symg:use unsafe.String to avoid memory copy --- chore/_xtool/llcppsymg/llcppsymg.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 0296e0fa..f63c5711 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -28,6 +28,7 @@ import ( "path/filepath" "strconv" "strings" + "unsafe" "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" @@ -91,18 +92,24 @@ func check(err error) { } } -func getConf(data []byte) (config types.Config, err error) { +func getConf(data []byte) (*types.Config, error) { conf := cjson.ParseBytes(data) - defer conf.Delete() if conf == nil { - return config, errors.New("failed to parse config") + return nil, errors.New("failed to parse config") } - config.Name = getStringItem(conf, "name", "") - config.CFlags = getStringItem(conf, "cflags", "") - config.Libs = getStringItem(conf, "libs", "") - config.Include = getStringArrayItem(conf, "include") - config.TrimPrefixes = getStringArrayItem(conf, "trimPrefixes") - return + config := &types.Config{ + Name: getStringItem(conf, "name", ""), + CFlags: getStringItem(conf, "cflags", ""), + Libs: getStringItem(conf, "libs", ""), + Include: getStringArrayItem(conf, "include"), + TrimPrefixes: getStringArrayItem(conf, "trimPrefixes"), + } + return config, nil +} + +func getString(obj *cjson.JSON) (value string) { + str := obj.GetStringValue() + return unsafe.String((*byte)(unsafe.Pointer(str)), c.Strlen(str)) } func getStringItem(obj *cjson.JSON, key string, defval string) (value string) { @@ -110,7 +117,7 @@ func getStringItem(obj *cjson.JSON, key string, defval string) (value string) { if item == nil { return defval } - return c.GoString(item.GetStringValue()) + return getString(item) } func getStringArrayItem(obj *cjson.JSON, key string) (value []string) { @@ -120,7 +127,7 @@ func getStringArrayItem(obj *cjson.JSON, key string) (value []string) { } value = make([]string, item.GetArraySize()) for i := range value { - value[i] = c.GoString(item.GetArrayItem(c.Int(i)).GetStringValue()) + value[i] = getString(item.GetArrayItem(c.Int(i))) } return } From 8d840e694d8cc2856a1b38873e4edde7fd27ba9c Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 29 Jul 2024 22:11:44 +0800 Subject: [PATCH 17/24] c/clang/symg:remove unuse comment --- chore/_xtool/llcppsymg/parse/parse.go | 31 --------------------------- 1 file changed, 31 deletions(-) diff --git a/chore/_xtool/llcppsymg/parse/parse.go b/chore/_xtool/llcppsymg/parse/parse.go index 092c93fd..5a15d26a 100644 --- a/chore/_xtool/llcppsymg/parse/parse.go +++ b/chore/_xtool/llcppsymg/parse/parse.go @@ -118,19 +118,6 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe return clang.ChildVisit_Continue } -// func main() { -// if c.Argc < 2 { -// fmt.Fprintln(os.Stderr, "Usage: [ ...]\n") -// return -// } else { -// filenames := make([]*c.Char, c.Argc-1) -// for i := 1; i < int(c.Argc); i++ { -// filenames[i-1] = c.Index(c.Argv, c.Int(i)) -// } -// printJson(parse(filenames)) -// } -// } - func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, error) { index := clang.CreateIndex(0, 0) @@ -163,22 +150,4 @@ func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, error) { index.Dispose() return context.astInfo, nil - - // files := generateHeaderFilePath(config.CFlags, config.Include) - // fmt.Println(files) - // headerFileCmd := exec.Command("llcppinfofetch", files...) - - // fmt.Println("Executing command:", headerFileCmd.String()) - - // headerFileOutput, err := headerFileCmd.Output() - // if err != nil { - // return nil, errors.New("failed to execute header file command") - // } - // fmt.Println("headerFileOutput:", string(headerFileOutput), len(headerFileOutput)) - // t := make([]types.ASTInformation, 0) - // err = json.Unmarshal(headerFileOutput, &t) - // if err != nil { - // return nil, err - // } - // return t, nil } From 121923016873cde4a7ce62651b34d81c665507b6 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 00:05:23 +0800 Subject: [PATCH 18/24] c/clang/symg:genSymbolTableFile --- chore/_xtool/llcppsymg/llcppsymg.go | 45 +++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index f63c5711..af1a8538 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -19,7 +19,6 @@ package main import ( "bufio" "bytes" - "encoding/json" "errors" "fmt" "io" @@ -68,21 +67,7 @@ func main() { symbolInfo := getCommonSymbols(symbols, astInfos, config.TrimPrefixes) - jsonData, err := json.MarshalIndent(symbolInfo, "", " ") - check(err) - - fileName := "llcppg.symb.json" - err = os.WriteFile(fileName, jsonData, 0644) - check(err) - - absJSONPath, err := filepath.Abs(fileName) - check(err) - - config.JSONPath = absJSONPath - updatedCfgData, err := json.MarshalIndent(config, "", " ") - check(err) - - err = os.WriteFile(cfgFile, updatedCfgData, 0644) + err = genSymbolTableFile(symbolInfo) check(err) } @@ -283,3 +268,31 @@ func removePrefix(str string, prefixes []string) string { } return str } + +func genSymbolTableFile(symbolInfos []types.SymbolInfo) error { + root := cjson.Array() + defer root.Delete() + + for _, symbol := range symbolInfos { + item := cjson.Object() + item.SetItem(c.Str("mangle"), cjson.String(c.AllocaCStr(symbol.Mangle))) + item.SetItem(c.Str("c++"), cjson.String(c.AllocaCStr(symbol.CPP))) + item.SetItem(c.Str("go"), cjson.String(c.AllocaCStr(symbol.Go))) + root.AddItem(item) + } + + fileName := "llcppg.symb.json" + cStr := root.Print() + if cStr == nil { + return errors.New("symbol table is empty") + } + defer c.Free(unsafe.Pointer(cStr)) + + data := unsafe.Slice((*byte)(unsafe.Pointer(cStr)), c.Strlen(cStr)) + + if err := os.WriteFile(fileName, data, 0644); err != nil { + return errors.New("failed to write symbol table file") + } + + return nil +} From 67b10d8d38a9c2517b1fcab37d814093d2d59d07 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 09:33:05 +0800 Subject: [PATCH 19/24] c/clang/symg:refine config usage --- chore/_xtool/llcppsymg/llcppsymg.go | 26 ++++++++++++++++---------- chore/llcppg/types/types.go | 9 +++++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index af1a8538..8d356a63 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -53,6 +53,7 @@ func main() { config, err := getConf(data) check(err) + defer config.Delete() if err != nil { fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) @@ -77,19 +78,24 @@ func check(err error) { } } -func getConf(data []byte) (*types.Config, error) { - conf := cjson.ParseBytes(data) - if conf == nil { - return nil, errors.New("failed to parse config") +func getConf(data []byte) (types.Conf, error) { + parsedConf := cjson.ParseBytes(data) + if parsedConf == nil { + return types.Conf{}, errors.New("failed to parse config") } + config := &types.Config{ - Name: getStringItem(conf, "name", ""), - CFlags: getStringItem(conf, "cflags", ""), - Libs: getStringItem(conf, "libs", ""), - Include: getStringArrayItem(conf, "include"), - TrimPrefixes: getStringArrayItem(conf, "trimPrefixes"), + Name: getStringItem(parsedConf, "name", ""), + CFlags: getStringItem(parsedConf, "cflags", ""), + Libs: getStringItem(parsedConf, "libs", ""), + Include: getStringArrayItem(parsedConf, "include"), + TrimPrefixes: getStringArrayItem(parsedConf, "trimPrefixes"), } - return config, nil + + return types.Conf{ + JSON: parsedConf, + Config: config, + }, nil } func getString(obj *cjson.JSON) (value string) { diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index e71885ef..bd516458 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -16,6 +16,10 @@ package types +import ( + "github.com/goplus/llgo/c/cjson" +) + // Config represents a configuration for the llcppg tool. type Config struct { Name string `json:"name"` @@ -26,6 +30,11 @@ type Config struct { JSONPath string `json:"jsonPath"` } +type Conf struct { + *cjson.JSON + *Config +} + type CPPSymbol struct { Symbol string `json:"symbol"` Type string `json:"type"` From 14face336e1596461eb3549d2b86bfd301a8b5bc Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 10:33:52 +0800 Subject: [PATCH 20/24] c/clang/symg:remove JSONPath --- chore/llcppg/types/types.go | 1 - 1 file changed, 1 deletion(-) diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index bd516458..ece5c0e3 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -27,7 +27,6 @@ type Config struct { Libs string `json:"libs"` Include []string `json:"include"` TrimPrefixes []string `json:"trimPrefixes"` - JSONPath string `json:"jsonPath"` } type Conf struct { From 099c80e04b3caecbc64c7c30e1599bb7c3670189 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 15:07:33 +0800 Subject: [PATCH 21/24] c/clang/symg: use xtool/nm to parse symbol --- chore/_xtool/llcppsymg/llcppsymg.go | 78 ++++++++++++++--------------- chore/llcppg/types/types.go | 6 +-- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 8d356a63..a3d1bede 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -17,13 +17,10 @@ package main import ( - "bufio" - "bytes" "errors" "fmt" "io" "os" - "os/exec" "path/filepath" "strconv" "strings" @@ -34,6 +31,7 @@ import ( "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/llcppg/types" "github.com/goplus/llgo/cpp/llvm" + "github.com/goplus/llgo/xtool/nm" ) func main() { @@ -124,21 +122,26 @@ func getStringArrayItem(obj *cjson.JSON, key string) (value []string) { } func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { - dylibPath, _ := generateDylibPath(lib) - nmCmd := exec.Command("nm", "-gU", dylibPath) - nmOutput, err := nmCmd.Output() // maybe lock + dylibPath, err := generateDylibPath(lib) if err != nil { - return nil, errors.New("failed to execute nm command") + return nil, errors.New("failed to generate dylib path") } - symbols := parseNmOutput(nmOutput) + files, err := nm.New("").List(dylibPath) + if err != nil { + return nil, errors.New("failed to list symbols in dylib") + } - for i, sym := range symbols { - decodedName, err := decodeSymbolName(sym.Name) - if err != nil { - return nil, err + var symbols []types.CPPSymbol + + for _, file := range files { + for _, sym := range file.Symbols { + demangleName := decodeSymbolName(sym.Name) + symbols = append(symbols, types.CPPSymbol{ + Symbol: sym, + DemangleName: demangleName, + }) } - symbols[i].Name = decodedName } return symbols, nil @@ -164,35 +167,28 @@ func generateDylibPath(lib string) (string, error) { return dylibPath, nil } -func parseNmOutput(output []byte) []types.CPPSymbol { - scanner := bufio.NewScanner(bytes.NewReader(output)) - var symbols []types.CPPSymbol - - for scanner.Scan() { - line := scanner.Text() - fields := strings.Fields(line) - if len(fields) < 3 { - continue - } - symbolName := fields[2] - // Check if the symbol name starts with an underscore and remove it if present - symbolName = strings.TrimPrefix(symbolName, "_") - symbols = append(symbols, types.CPPSymbol{ - Symbol: symbolName, - Type: fields[1], - Name: fields[2], - }) +func decodeSymbolName(symbolName string) string { + if symbolName == "" { + return "" } - return symbols -} + demangled := llvm.ItaniumDemangle(symbolName, true) + if demangled == nil { + return symbolName + } + defer c.Free(unsafe.Pointer(demangled)) -func decodeSymbolName(symbolName string) (string, error) { - llvm.ItaniumDemangle(symbolName, true) - demangleName := c.GoString(llvm.ItaniumDemangle(symbolName, true)) - decodedName := strings.TrimSpace(string(demangleName)) - decodedName = strings.ReplaceAll(decodedName, "std::__1::basic_string, std::__1::allocator > const", "std::string") - return decodedName, nil + 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 } func generateHeaderFilePath(cflags string, files []string) []string { @@ -211,11 +207,11 @@ func getCommonSymbols(dylibSymbols []types.CPPSymbol, astInfoList []types.ASTInf for _, astInfo := range astInfoList { for _, dylibSym := range dylibSymbols { - if dylibSym.Symbol == astInfo.Symbol { + if strings.TrimPrefix(dylibSym.Name, "_") == astInfo.Symbol { cppName := generateCPPName(astInfo) functionNameMap[cppName]++ symbolInfo := types.SymbolInfo{ - Mangle: dylibSym.Symbol, + Mangle: strings.TrimPrefix(dylibSym.Name, "_"), CPP: cppName, Go: generateMangle(astInfo, functionNameMap[cppName], prefix), } diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index ece5c0e3..6ca9d833 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -18,6 +18,7 @@ package types import ( "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/xtool/nm" ) // Config represents a configuration for the llcppg tool. @@ -35,9 +36,8 @@ type Conf struct { } type CPPSymbol struct { - Symbol string `json:"symbol"` - Type string `json:"type"` - Name string `json:"name"` + DemangleName string + *nm.Symbol } type ASTInformation struct { From f93d3381e08c12408da25c0ab4939f34cc73583c Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 15:17:37 +0800 Subject: [PATCH 22/24] c/clang/symg:move get conf func --- chore/_xtool/llcppsymg/config/config.go | 60 +++++++++++++++++++++++++ chore/_xtool/llcppsymg/llcppsymg.go | 56 +++-------------------- chore/llcppg/types/types.go | 6 --- 3 files changed, 66 insertions(+), 56 deletions(-) create mode 100644 chore/_xtool/llcppsymg/config/config.go diff --git a/chore/_xtool/llcppsymg/config/config.go b/chore/_xtool/llcppsymg/config/config.go new file mode 100644 index 00000000..3545e25b --- /dev/null +++ b/chore/_xtool/llcppsymg/config/config.go @@ -0,0 +1,60 @@ +package config + +import ( + "errors" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/chore/llcppg/types" +) + +type Conf struct { + *cjson.JSON + *types.Config +} + +func GetConf(data []byte) (Conf, error) { + parsedConf := cjson.ParseBytes(data) + if parsedConf == nil { + return Conf{}, errors.New("failed to parse config") + } + + config := &types.Config{ + Name: GetStringItem(parsedConf, "name", ""), + CFlags: GetStringItem(parsedConf, "cflags", ""), + Libs: GetStringItem(parsedConf, "libs", ""), + Include: GetStringArrayItem(parsedConf, "include"), + TrimPrefixes: GetStringArrayItem(parsedConf, "trimPrefixes"), + } + + return Conf{ + JSON: parsedConf, + Config: config, + }, nil +} + +func GetString(obj *cjson.JSON) (value string) { + str := obj.GetStringValue() + return unsafe.String((*byte)(unsafe.Pointer(str)), c.Strlen(str)) +} + +func GetStringItem(obj *cjson.JSON, key string, defval string) (value string) { + item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key)) + if item == nil { + return defval + } + return GetString(item) +} + +func GetStringArrayItem(obj *cjson.JSON, key string) (value []string) { + item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key)) + if item == nil { + return + } + value = make([]string, item.GetArraySize()) + for i := range value { + value[i] = GetString(item.GetArrayItem(c.Int(i))) + } + return +} diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index a3d1bede..6edde02f 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -28,6 +28,7 @@ import ( "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/config" "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/llcppg/types" "github.com/goplus/llgo/cpp/llvm" @@ -49,22 +50,22 @@ func main() { } check(err) - config, err := getConf(data) + conf, err := config.GetConf(data) check(err) - defer config.Delete() + defer conf.Delete() if err != nil { fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile) } - symbols, err := parseDylibSymbols(config.Libs) + symbols, err := parseDylibSymbols(conf.Libs) check(err) - filepaths := generateHeaderFilePath(config.CFlags, config.Include) + filepaths := generateHeaderFilePath(conf.CFlags, conf.Include) astInfos, err := parse.ParseHeaderFile(filepaths) check(err) - symbolInfo := getCommonSymbols(symbols, astInfos, config.TrimPrefixes) + symbolInfo := getCommonSymbols(symbols, astInfos, conf.TrimPrefixes) err = genSymbolTableFile(symbolInfo) check(err) @@ -76,51 +77,6 @@ func check(err error) { } } -func getConf(data []byte) (types.Conf, error) { - parsedConf := cjson.ParseBytes(data) - if parsedConf == nil { - return types.Conf{}, errors.New("failed to parse config") - } - - config := &types.Config{ - Name: getStringItem(parsedConf, "name", ""), - CFlags: getStringItem(parsedConf, "cflags", ""), - Libs: getStringItem(parsedConf, "libs", ""), - Include: getStringArrayItem(parsedConf, "include"), - TrimPrefixes: getStringArrayItem(parsedConf, "trimPrefixes"), - } - - return types.Conf{ - JSON: parsedConf, - Config: config, - }, nil -} - -func getString(obj *cjson.JSON) (value string) { - str := obj.GetStringValue() - return unsafe.String((*byte)(unsafe.Pointer(str)), c.Strlen(str)) -} - -func getStringItem(obj *cjson.JSON, key string, defval string) (value string) { - item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key)) - if item == nil { - return defval - } - return getString(item) -} - -func getStringArrayItem(obj *cjson.JSON, key string) (value []string) { - item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key)) - if item == nil { - return - } - value = make([]string, item.GetArraySize()) - for i := range value { - value[i] = getString(item.GetArrayItem(c.Int(i))) - } - return -} - func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) { dylibPath, err := generateDylibPath(lib) if err != nil { diff --git a/chore/llcppg/types/types.go b/chore/llcppg/types/types.go index 6ca9d833..9d700881 100644 --- a/chore/llcppg/types/types.go +++ b/chore/llcppg/types/types.go @@ -17,7 +17,6 @@ package types import ( - "github.com/goplus/llgo/c/cjson" "github.com/goplus/llgo/xtool/nm" ) @@ -30,11 +29,6 @@ type Config struct { TrimPrefixes []string `json:"trimPrefixes"` } -type Conf struct { - *cjson.JSON - *Config -} - type CPPSymbol struct { DemangleName string *nm.Symbol From 63f4c73ef083f08133de6198bea9626ef42121d9 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 15:27:03 +0800 Subject: [PATCH 23/24] c/clang/symg:remove example config file --- chore/_xtool/llcppsymg/llcppg.cfg | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 chore/_xtool/llcppsymg/llcppg.cfg diff --git a/chore/_xtool/llcppsymg/llcppg.cfg b/chore/_xtool/llcppsymg/llcppg.cfg deleted file mode 100644 index 163284b3..00000000 --- a/chore/_xtool/llcppsymg/llcppg.cfg +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "inih", - "cflags": "$(pkg-config --cflags INIReader)", - "include": [ - "INIReader.h" - ], - "libs": "$(pkg-config --libs INIReader)", - "trimPrefixes": ["Ini", "INI"] -} \ No newline at end of file From 9afe26f1d62b05d0676bc5d55dc9ec5bdd8ea227 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 30 Jul 2024 20:50:22 +0800 Subject: [PATCH 24/24] c/clang/symg:keep user edit symbol --- chore/_xtool/llcppsymg/llcppsymg.go | 53 +++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 6edde02f..93c2194d 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -228,6 +228,23 @@ func removePrefix(str string, prefixes []string) string { } func genSymbolTableFile(symbolInfos []types.SymbolInfo) error { + // keep open follow code block can run successfully + for i := range symbolInfos { + println("symbol", symbolInfos[i].Go) + } + + fileName := "llcppg.symb.json" + existingSymbols, err := readExistingSymbolTable(fileName) + if err != nil { + return err + } + + for i := range symbolInfos { + if existingSymbol, exists := existingSymbols[symbolInfos[i].Mangle]; exists { + symbolInfos[i].Go = existingSymbol.Go + } + } + root := cjson.Array() defer root.Delete() @@ -239,7 +256,6 @@ func genSymbolTableFile(symbolInfos []types.SymbolInfo) error { root.AddItem(item) } - fileName := "llcppg.symb.json" cStr := root.Print() if cStr == nil { return errors.New("symbol table is empty") @@ -251,6 +267,39 @@ func genSymbolTableFile(symbolInfos []types.SymbolInfo) error { if err := os.WriteFile(fileName, data, 0644); err != nil { return errors.New("failed to write symbol table file") } - return nil } +func readExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, error) { + existingSymbols := make(map[string]types.SymbolInfo) + + if _, err := os.Stat(fileName); err != nil { + return existingSymbols, nil + } + + data, err := os.ReadFile(fileName) + if err != nil { + return nil, errors.New("failed to read symbol table file") + } + + parsedJSON := cjson.ParseBytes(data) + if parsedJSON == nil { + return nil, errors.New("failed to parse JSON") + } + + arraySize := parsedJSON.GetArraySize() + + for i := 0; i < int(arraySize); i++ { + item := parsedJSON.GetArrayItem(c.Int(i)) + if item == nil { + continue + } + symbol := types.SymbolInfo{ + Mangle: config.GetStringItem(item, "mangle", ""), + CPP: config.GetStringItem(item, "c++", ""), + Go: config.GetStringItem(item, "go", ""), + } + existingSymbols[symbol.Mangle] = symbol + } + + return existingSymbols, nil +}