llcppsymg:symbol generate test
llcppsymg:symbo test llcppsymg:exist symb file test llcppsymg:GenSymbolTabledata llcppsymg:GenSymbolTableData test llcppsymg:full symg operation test
This commit is contained in:
@@ -4,43 +4,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/header"
|
||||
)
|
||||
|
||||
func GenHeaderFilePath(cflags string, files []string) ([]string, error) {
|
||||
prefixPath := strings.TrimPrefix(cflags, "-I")
|
||||
|
||||
var validPaths []string
|
||||
var errs []string
|
||||
|
||||
for _, file := range files {
|
||||
if file == "" {
|
||||
continue
|
||||
}
|
||||
fullPath := filepath.Join(prefixPath, file)
|
||||
if f, err := os.Open(fullPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
errs = append(errs, fmt.Sprintf("file not found: %s", file))
|
||||
} else {
|
||||
errs = append(errs, fmt.Sprintf("error accessing file %s: %v", file, err))
|
||||
}
|
||||
} else {
|
||||
f.Close()
|
||||
validPaths = append(validPaths, fullPath)
|
||||
}
|
||||
}
|
||||
|
||||
if len(validPaths) == 0 && len(errs) == 0 {
|
||||
return nil, fmt.Errorf("no valid header files")
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return validPaths, fmt.Errorf("some files not found or inaccessible: %v", errs)
|
||||
}
|
||||
|
||||
return validPaths, nil
|
||||
}
|
||||
|
||||
func TestGenHeaderFilePath() {
|
||||
fmt.Println("=== Test GenHeaderFilePath ===")
|
||||
|
||||
@@ -83,7 +50,7 @@ func TestGenHeaderFilePath() {
|
||||
fmt.Printf("Test case: %s\n", tc.name)
|
||||
fmt.Printf("Input files: %v\n", tc.files)
|
||||
|
||||
result, err := GenHeaderFilePath(tc.cflags, tc.files)
|
||||
result, err := header.GenHeaderFilePath(tc.cflags, tc.files)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
46
chore/_xtool/llcppsymg/_cmptest/symbol_test/llgo.expect
Normal file
46
chore/_xtool/llcppsymg/_cmptest/symbol_test/llgo.expect
Normal file
@@ -0,0 +1,46 @@
|
||||
#stdout
|
||||
=== Test GetCommonSymbols ===
|
||||
|
||||
Test Case: Lua symbols
|
||||
Common Symbols (4):
|
||||
Mangle: lua_absindex, CPP: lua_absindex(lua_State *, int), Go: Absindex
|
||||
Mangle: lua_arith, CPP: lua_arith(lua_State *, int), Go: Arith
|
||||
Mangle: lua_atpanic, CPP: lua_atpanic(lua_State *, lua_CFunction), Go: Atpanic
|
||||
Mangle: lua_callk, CPP: lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction), Go: Callk
|
||||
|
||||
Test Case: INIReader and Std library symbols
|
||||
Common Symbols (3):
|
||||
Mangle: ZNK9INIReader12GetInteger64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_x, CPP: INIReader::GetInteger64(const std::string &, const std::string &, int64_t), Go: (*Reader).GetInteger64
|
||||
Mangle: ZNK9INIReader7GetRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_d, CPP: INIReader::GetReal(const std::string &, const std::string &, double), Go: (*Reader).GetReal
|
||||
Mangle: ZNK9INIReader10ParseErrorEv, CPP: INIReader::ParseError(), Go: (*Reader).ParseError
|
||||
|
||||
=== Test ReadExistingSymbolTable ===
|
||||
Symbols read from the file:
|
||||
Symbol Map GoName: (*Reader).Init__1, ProtoName In HeaderFile: INIReader::INIReader(const char *, size_t), MangledName: _ZN9INIReaderC1EPKcm
|
||||
Symbol Map GoName: (*Reader).GetBoolean, ProtoName In HeaderFile: INIReader::GetBoolean(const std::string &, const std::string &, bool), MangledName: _ZNK9INIReader10GetBooleanERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_b
|
||||
Symbol Map GoName: (*Reader).ParseError, ProtoName In HeaderFile: INIReader::ParseError(), MangledName: _ZNK9INIReader10ParseErrorEv
|
||||
Havent existed symb file
|
||||
|
||||
=== Test GenSymbolTableData ===
|
||||
[{
|
||||
"mangle": "lua_absindex",
|
||||
"c++": "lua_absindex(lua_State *, int)",
|
||||
"go": "Absindex"
|
||||
}, {
|
||||
"mangle": "lua_arith",
|
||||
"c++": "lua_arith(lua_State *, int)",
|
||||
"go": "Arith"
|
||||
}, {
|
||||
"mangle": "lua_atpanic",
|
||||
"c++": "lua_atpanic(lua_State *, lua_CFunction)",
|
||||
"go": "Atpanic"
|
||||
}, {
|
||||
"mangle": "lua_callk",
|
||||
"c++": "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)",
|
||||
"go": "ModifiedCallk"
|
||||
}]
|
||||
|
||||
|
||||
#stderr
|
||||
|
||||
#exit 0
|
||||
152
chore/_xtool/llcppsymg/_cmptest/symbol_test/symbol.go
Normal file
152
chore/_xtool/llcppsymg/_cmptest/symbol_test/symbol.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
||||
"github.com/goplus/llgo/chore/llcppg/types"
|
||||
"github.com/goplus/llgo/xtool/nm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
TestGetCommonSymbols()
|
||||
TestReadExistingSymbolTable()
|
||||
TestGenSymbolTableData()
|
||||
}
|
||||
func TestGetCommonSymbols() {
|
||||
fmt.Println("=== Test GetCommonSymbols ===")
|
||||
testCases := []struct {
|
||||
name string
|
||||
dylibSymbols []*nm.Symbol
|
||||
headerSymbols map[string]*parse.SymbolInfo
|
||||
}{
|
||||
{
|
||||
name: "Lua symbols",
|
||||
dylibSymbols: []*nm.Symbol{
|
||||
{Name: "_lua_absindex"},
|
||||
{Name: "_lua_arith"},
|
||||
{Name: "_lua_atpanic"},
|
||||
{Name: "_lua_callk"},
|
||||
{Name: "_lua_lib_nonexistent"},
|
||||
},
|
||||
headerSymbols: map[string]*parse.SymbolInfo{
|
||||
"lua_absindex": {ProtoName: "lua_absindex(lua_State *, int)", GoName: "Absindex"},
|
||||
"lua_arith": {ProtoName: "lua_arith(lua_State *, int)", GoName: "Arith"},
|
||||
"lua_atpanic": {ProtoName: "lua_atpanic(lua_State *, lua_CFunction)", GoName: "Atpanic"},
|
||||
"lua_callk": {ProtoName: "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)", GoName: "Callk"},
|
||||
"lua_header_nonexistent": {ProtoName: "lua_header_nonexistent()", GoName: "HeaderNonexistent"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "INIReader and Std library symbols",
|
||||
dylibSymbols: []*nm.Symbol{
|
||||
{Name: "_ZNK9INIReader12GetInteger64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_x"},
|
||||
{Name: "_ZNK9INIReader7GetRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_d"},
|
||||
{Name: "_ZNK9INIReader10ParseErrorEv"},
|
||||
},
|
||||
headerSymbols: map[string]*parse.SymbolInfo{
|
||||
"ZNK9INIReader12GetInteger64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_x": {GoName: "(*Reader).GetInteger64", ProtoName: "INIReader::GetInteger64(const std::string &, const std::string &, int64_t)"},
|
||||
"ZNK9INIReader13GetUnsigned64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_y": {GoName: "(*Reader).GetUnsigned64", ProtoName: "INIReader::GetUnsigned64(const std::string &, const std::string &, uint64_t)"},
|
||||
"ZNK9INIReader7GetRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_d": {GoName: "(*Reader).GetReal", ProtoName: "INIReader::GetReal(const std::string &, const std::string &, double)"},
|
||||
"ZNK9INIReader10ParseErrorEv": {GoName: "(*Reader).ParseError", ProtoName: "INIReader::ParseError()"},
|
||||
"ZNK9INIReader10GetBooleanERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_b": {GoName: "(*Reader).GetBoolean", ProtoName: "INIReader::GetBoolean(const std::string &, const std::string &, bool)"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
fmt.Printf("\nTest Case: %s\n", tc.name)
|
||||
commonSymbols := symbol.GetCommonSymbols(tc.dylibSymbols, tc.headerSymbols)
|
||||
fmt.Printf("Common Symbols (%d):\n", len(commonSymbols))
|
||||
for _, sym := range commonSymbols {
|
||||
fmt.Printf("Mangle: %s, CPP: %s, Go: %s\n", sym.Mangle, sym.CPP, sym.Go)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func TestReadExistingSymbolTable() {
|
||||
fmt.Println("=== Test ReadExistingSymbolTable ===")
|
||||
|
||||
tmpFile, err := os.CreateTemp("", "llcppg.symb.json")
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create temp file: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
testData := `[
|
||||
{
|
||||
"mangle": "_ZN9INIReaderC1EPKcm",
|
||||
"c++": "INIReader::INIReader(const char *, size_t)",
|
||||
"go": "(*Reader).Init__1"
|
||||
},
|
||||
{
|
||||
"mangle": "_ZNK9INIReader10GetBooleanERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_b",
|
||||
"c++": "INIReader::GetBoolean(const std::string &, const std::string &, bool)",
|
||||
"go": "(*Reader).GetBoolean"
|
||||
},
|
||||
{
|
||||
"mangle": "_ZNK9INIReader10ParseErrorEv",
|
||||
"c++": "INIReader::ParseError()",
|
||||
"go": "(*Reader).ParseError"
|
||||
}
|
||||
]`
|
||||
if _, err := tmpFile.Write([]byte(testData)); err != nil {
|
||||
fmt.Printf("Failed to write test data: %v\n", err)
|
||||
return
|
||||
}
|
||||
tmpFile.Close()
|
||||
|
||||
symbols, exist := symbol.ReadExistingSymbolTable(tmpFile.Name())
|
||||
if !exist {
|
||||
fmt.Printf("ReadExistingSymbolTable failed")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Symbols read from the file:")
|
||||
var keys []string
|
||||
for key := range symbols {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
info := symbols[key]
|
||||
fmt.Printf("Symbol Map GoName: %s, ProtoName In HeaderFile: %s, MangledName: %s\n",
|
||||
info.Go, info.CPP, key)
|
||||
}
|
||||
|
||||
_, exist = symbol.ReadExistingSymbolTable("other.json")
|
||||
if !exist {
|
||||
fmt.Println("Havent existed symb file")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
func TestGenSymbolTableData() {
|
||||
fmt.Println("=== Test GenSymbolTableData ===")
|
||||
|
||||
commonSymbols := []*types.SymbolInfo{
|
||||
{Mangle: "lua_absindex", CPP: "lua_absindex(lua_State *, int)", Go: "Absindex"},
|
||||
{Mangle: "lua_arith", CPP: "lua_arith(lua_State *, int)", Go: "Arith"},
|
||||
{Mangle: "lua_atpanic", CPP: "lua_atpanic(lua_State *, lua_CFunction)", Go: "Atpanic"},
|
||||
{Mangle: "lua_callk", CPP: "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)", Go: "Callk"},
|
||||
}
|
||||
|
||||
existingSymbols := map[string]types.SymbolInfo{
|
||||
"lua_absindex": {Mangle: "lua_absindex", CPP: "lua_absindex(lua_State *, int)", Go: "Absindex"},
|
||||
"lua_arith": {Mangle: "lua_arith", CPP: "lua_arith(lua_State *, int)", Go: "Arith"},
|
||||
"lua_callk": {Mangle: "lua_callk", CPP: "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)", Go: "ModifiedCallk"},
|
||||
}
|
||||
|
||||
data, err := symbol.GenSymbolTableData(commonSymbols, existingSymbols)
|
||||
if err != nil {
|
||||
fmt.Printf("Error generating symbol table data: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
fmt.Println()
|
||||
}
|
||||
45
chore/_xtool/llcppsymg/_cmptest/symg_test/llgo.expect
Normal file
45
chore/_xtool/llcppsymg/_cmptest/symg_test/llgo.expect
Normal file
@@ -0,0 +1,45 @@
|
||||
#stdout
|
||||
=== Test Case: inireader ===
|
||||
[{
|
||||
"mangle": "_ZN9INIReaderC1EPKc",
|
||||
"c++": "INIReader::INIReader(const char *)",
|
||||
"go": "(*Reader).Init"
|
||||
}, {
|
||||
"mangle": "_ZN9INIReaderC1EPKcl",
|
||||
"c++": "INIReader::INIReader(const char *, long)",
|
||||
"go": "(*Reader).Init__1"
|
||||
}, {
|
||||
"mangle": "_ZN9INIReaderD1Ev",
|
||||
"c++": "INIReader::~INIReader()",
|
||||
"go": "(*Reader).Dispose"
|
||||
}, {
|
||||
"mangle": "_ZNK9INIReader10ParseErrorEv",
|
||||
"c++": "INIReader::ParseError()",
|
||||
"go": "(*Reader).ModifyedParseError"
|
||||
}, {
|
||||
"mangle": "_ZNK9INIReader3GetEPKcS1_S1_",
|
||||
"c++": "INIReader::Get(const char *, const char *, const char *)",
|
||||
"go": "(*Reader).Get"
|
||||
}]
|
||||
=== Test Case: lua ===
|
||||
[{
|
||||
"mangle": "lua_error",
|
||||
"c++": "lua_error(lua_State *)",
|
||||
"go": "Error"
|
||||
}, {
|
||||
"mangle": "lua_next",
|
||||
"c++": "lua_next(lua_State *, int)",
|
||||
"go": "Next"
|
||||
}, {
|
||||
"mangle": "lua_concat",
|
||||
"c++": "lua_concat(lua_State *, int)",
|
||||
"go": "Concat"
|
||||
}, {
|
||||
"mangle": "lua_stringtonumber",
|
||||
"c++": "lua_stringtonumber(lua_State *, const char *)",
|
||||
"go": "Stringtonumber"
|
||||
}]
|
||||
|
||||
#stderr
|
||||
|
||||
#exit 0
|
||||
117
chore/_xtool/llcppsymg/_cmptest/symg_test/symg.go
Normal file
117
chore/_xtool/llcppsymg/_cmptest/symg_test/symg.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
||||
"github.com/goplus/llgo/xtool/nm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
TestParseHeaderFile()
|
||||
}
|
||||
func TestParseHeaderFile() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
content string
|
||||
isCpp bool
|
||||
prefixes []string
|
||||
dylibSymbols []*nm.Symbol
|
||||
symbFileContent string
|
||||
}{
|
||||
{
|
||||
name: "inireader",
|
||||
content: `
|
||||
#define INI_API __attribute__((visibility("default")))
|
||||
class INIReader {
|
||||
public:
|
||||
__attribute__((visibility("default"))) explicit INIReader(const char *filename);
|
||||
INI_API explicit INIReader(const char *buffer, long buffer_size);
|
||||
~INIReader();
|
||||
INI_API int ParseError() const;
|
||||
INI_API const char * Get(const char *section, const char *name,
|
||||
const char *default_value) const;
|
||||
private:
|
||||
static const char * MakeKey(const char *section, const char *name);
|
||||
};
|
||||
`,
|
||||
isCpp: true,
|
||||
prefixes: []string{"INI"},
|
||||
dylibSymbols: []*nm.Symbol{
|
||||
{Name: "__ZN9INIReaderC1EPKc"},
|
||||
{Name: "__ZN9INIReaderC1EPKcl"},
|
||||
{Name: "__ZN9INIReaderD1Ev"},
|
||||
{Name: "__ZNK9INIReader10ParseErrorEv"},
|
||||
{Name: "__ZNK9INIReader3GetEPKcS1_S1_"},
|
||||
},
|
||||
symbFileContent: `
|
||||
[{
|
||||
"mangle": "_ZN9INIReaderC1EPKc",
|
||||
"c++": "INIReader::INIReader(const char *)",
|
||||
"go": "(*Reader).Init"
|
||||
}, {
|
||||
"mangle": "_ZN9INIReaderC1EPKcl",
|
||||
"c++": "INIReader::INIReader(const char *, long)",
|
||||
"go": "(*Reader).Init__1"
|
||||
}, {
|
||||
"mangle": "_ZN9INIReaderD1Ev",
|
||||
"c++": "INIReader::~INIReader()",
|
||||
"go": "(*Reader).Dispose"
|
||||
}, {
|
||||
"mangle": "_ZNK9INIReader10ParseErrorEv",
|
||||
"c++": "INIReader::ParseError()",
|
||||
"go": "(*Reader).ModifyedParseError"
|
||||
}]`,
|
||||
},
|
||||
{
|
||||
name: "lua",
|
||||
content: `
|
||||
typedef struct lua_State lua_State;
|
||||
|
||||
LUA_API int(lua_error)(lua_State *L);
|
||||
|
||||
LUA_API int(lua_next)(lua_State *L, int idx);
|
||||
|
||||
LUA_API void(lua_concat)(lua_State *L, int n);
|
||||
LUA_API void(lua_len)(lua_State *L, int idx);
|
||||
|
||||
LUA_API long unsigned int(lua_stringtonumber)(lua_State *L, const char *s);
|
||||
|
||||
LUA_API void(lua_setallocf)(lua_State *L, lua_Alloc f, void *ud);
|
||||
|
||||
LUA_API void(lua_toclose)(lua_State *L, int idx);
|
||||
LUA_API void(lua_closeslot)(lua_State *L, int idx);
|
||||
`,
|
||||
isCpp: false,
|
||||
prefixes: []string{"lua_"},
|
||||
dylibSymbols: []*nm.Symbol{
|
||||
{Name: "_lua_error"},
|
||||
{Name: "_lua_next"},
|
||||
{Name: "_lua_concat"},
|
||||
{Name: "_lua_stringtonumber"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
fmt.Printf("=== Test Case: %s ===\n", tc.name)
|
||||
headerSymbolMap, err := parse.ParseHeaderFile([]string{tc.content}, tc.prefixes, tc.isCpp, true)
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
}
|
||||
tmpFile, err := os.CreateTemp("", "llcppg.symb.json")
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create temp file: %v\n", err)
|
||||
return
|
||||
}
|
||||
tmpFile.Write([]byte(tc.symbFileContent))
|
||||
symbolData, err := symbol.GenerateAndUpdateSymbolTable(tc.dylibSymbols, headerSymbolMap, tmpFile.Name())
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
}
|
||||
fmt.Println(string(symbolData))
|
||||
os.Remove(tmpFile.Name())
|
||||
}
|
||||
}
|
||||
@@ -2,22 +2,41 @@ package header
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GenHeaderFilePath(cflags string, files []string) ([]string, error) {
|
||||
fmt.Printf("get filepath from config cflags%s & include:%v\n", cflags, files)
|
||||
prefixPath := strings.TrimPrefix(cflags, "-I")
|
||||
var includePaths []string
|
||||
|
||||
var validPaths []string
|
||||
var errs []string
|
||||
|
||||
for _, file := range files {
|
||||
if file == "" {
|
||||
continue
|
||||
}
|
||||
includePaths = append(includePaths, filepath.Join(prefixPath, "/"+file))
|
||||
fullPath := filepath.Join(prefixPath, file)
|
||||
if f, err := os.Open(fullPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
errs = append(errs, fmt.Sprintf("file not found: %s", file))
|
||||
} else {
|
||||
errs = append(errs, fmt.Sprintf("error accessing file %s: %v", file, err))
|
||||
}
|
||||
} else {
|
||||
f.Close()
|
||||
validPaths = append(validPaths, fullPath)
|
||||
}
|
||||
}
|
||||
if len(includePaths) == 0 {
|
||||
|
||||
if len(validPaths) == 0 && len(errs) == 0 {
|
||||
return nil, fmt.Errorf("no valid header files")
|
||||
}
|
||||
return includePaths, nil
|
||||
|
||||
if len(errs) > 0 {
|
||||
return validPaths, fmt.Errorf("some files not found or inaccessible: %v", errs)
|
||||
}
|
||||
|
||||
return validPaths, nil
|
||||
}
|
||||
|
||||
@@ -17,25 +17,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"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/dylib"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/header"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
||||
"github.com/goplus/llgo/chore/llcppg/types"
|
||||
"github.com/goplus/llgo/xtool/nm"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfgFile := "llcppg.cfg"
|
||||
symbFile := "llcppg.symb.json"
|
||||
if len(os.Args) > 1 {
|
||||
cfgFile = os.Args[1]
|
||||
}
|
||||
@@ -63,9 +58,10 @@ func main() {
|
||||
headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes, conf.Cplusplus, false)
|
||||
check(err)
|
||||
|
||||
symbolInfo := getCommonSymbols(symbols, headerInfos, conf.TrimPrefixes)
|
||||
symbolData, err := symbol.GenerateAndUpdateSymbolTable(symbols, headerInfos, symbFile)
|
||||
check(err)
|
||||
|
||||
err = genSymbolTableFile(symbolInfo)
|
||||
err = os.WriteFile(symbFile, symbolData, 0644)
|
||||
check(err)
|
||||
}
|
||||
|
||||
@@ -74,92 +70,3 @@ func check(err error) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getCommonSymbols(dylibSymbols []*nm.Symbol, symbolMap map[string]*parse.SymbolInfo, prefix []string) []*types.SymbolInfo {
|
||||
var commonSymbols []*types.SymbolInfo
|
||||
for _, dylibSym := range dylibSymbols {
|
||||
symName := strings.TrimPrefix(dylibSym.Name, "_")
|
||||
if symInfo, ok := symbolMap[symName]; ok {
|
||||
symbolInfo := &types.SymbolInfo{
|
||||
Mangle: symName,
|
||||
CPP: symInfo.ProtoName,
|
||||
Go: symInfo.GoName,
|
||||
}
|
||||
commonSymbols = append(commonSymbols, symbolInfo)
|
||||
}
|
||||
}
|
||||
return commonSymbols
|
||||
}
|
||||
|
||||
func genSymbolTableFile(symbolInfos []*types.SymbolInfo) error {
|
||||
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()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
107
chore/_xtool/llcppsymg/symbol/symbol.go
Normal file
107
chore/_xtool/llcppsymg/symbol/symbol.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package symbol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"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/xtool/nm"
|
||||
)
|
||||
|
||||
// finds the intersection of symbols from the dynamic library's symbol table and the symbols parsed from header files.
|
||||
// It returns a list of symbols that can be externally linked.
|
||||
func GetCommonSymbols(dylibSymbols []*nm.Symbol, headerSymbols map[string]*parse.SymbolInfo) []*types.SymbolInfo {
|
||||
var commonSymbols []*types.SymbolInfo
|
||||
for _, dylibSym := range dylibSymbols {
|
||||
symName := strings.TrimPrefix(dylibSym.Name, "_")
|
||||
if symInfo, ok := headerSymbols[symName]; ok {
|
||||
symbolInfo := &types.SymbolInfo{
|
||||
Mangle: symName,
|
||||
CPP: symInfo.ProtoName,
|
||||
Go: symInfo.GoName,
|
||||
}
|
||||
commonSymbols = append(commonSymbols, symbolInfo)
|
||||
}
|
||||
}
|
||||
return commonSymbols
|
||||
}
|
||||
|
||||
func ReadExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, bool) {
|
||||
if _, err := os.Stat(fileName); err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
parsedJSON := cjson.ParseBytes(data)
|
||||
if parsedJSON == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
existingSymbols := make(map[string]types.SymbolInfo)
|
||||
arraySize := parsedJSON.GetArraySize()
|
||||
|
||||
for i := 0; i < int(arraySize); i++ {
|
||||
item := parsedJSON.GetArrayItem(c.Int(i))
|
||||
symbol := types.SymbolInfo{
|
||||
Mangle: config.GetStringItem(item, "mangle", ""),
|
||||
CPP: config.GetStringItem(item, "c++", ""),
|
||||
Go: config.GetStringItem(item, "go", ""),
|
||||
}
|
||||
existingSymbols[symbol.Mangle] = symbol
|
||||
}
|
||||
|
||||
return existingSymbols, true
|
||||
}
|
||||
|
||||
func GenSymbolTableData(commonSymbols []*types.SymbolInfo, existingSymbols map[string]types.SymbolInfo) ([]byte, error) {
|
||||
// todo(zzy): len(existingSymbols) !=0
|
||||
// https://github.com/goplus/llgo/issues/808 will cause unexpected panic
|
||||
// https://github.com/goplus/llgo/pull/793 this pr can fix it
|
||||
for i := range commonSymbols {
|
||||
if existingSymbol, exists := existingSymbols[commonSymbols[i].Mangle]; exists {
|
||||
commonSymbols[i].Go = existingSymbol.Go
|
||||
}
|
||||
}
|
||||
|
||||
root := cjson.Array()
|
||||
defer root.Delete()
|
||||
|
||||
for _, symbol := range commonSymbols {
|
||||
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)
|
||||
}
|
||||
|
||||
cStr := root.Print()
|
||||
if cStr == nil {
|
||||
return nil, errors.New("symbol table is empty")
|
||||
}
|
||||
defer c.Free(unsafe.Pointer(cStr))
|
||||
result := []byte(c.GoString(cStr))
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GenerateAndUpdateSymbolTable(symbols []*nm.Symbol, headerInfos map[string]*parse.SymbolInfo, symbFile string) ([]byte, error) {
|
||||
commonSymbols := GetCommonSymbols(symbols, headerInfos)
|
||||
|
||||
existSymbols, _ := ReadExistingSymbolTable(symbFile)
|
||||
|
||||
symbolData, err := GenSymbolTableData(commonSymbols, existSymbols)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return symbolData, nil
|
||||
}
|
||||
Reference in New Issue
Block a user