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"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"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() {
|
func TestGenHeaderFilePath() {
|
||||||
fmt.Println("=== Test GenHeaderFilePath ===")
|
fmt.Println("=== Test GenHeaderFilePath ===")
|
||||||
|
|
||||||
@@ -83,7 +50,7 @@ func TestGenHeaderFilePath() {
|
|||||||
fmt.Printf("Test case: %s\n", tc.name)
|
fmt.Printf("Test case: %s\n", tc.name)
|
||||||
fmt.Printf("Input files: %v\n", tc.files)
|
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 {
|
if err != nil {
|
||||||
fmt.Printf("Error: %v\n", err)
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenHeaderFilePath(cflags string, files []string) ([]string, error) {
|
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")
|
prefixPath := strings.TrimPrefix(cflags, "-I")
|
||||||
var includePaths []string
|
|
||||||
|
var validPaths []string
|
||||||
|
var errs []string
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if file == "" {
|
if file == "" {
|
||||||
continue
|
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 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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"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/config"
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/dylib"
|
"github.com/goplus/llgo/chore/_xtool/llcppsymg/dylib"
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/header"
|
"github.com/goplus/llgo/chore/_xtool/llcppsymg/header"
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
||||||
"github.com/goplus/llgo/chore/llcppg/types"
|
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
||||||
"github.com/goplus/llgo/xtool/nm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfgFile := "llcppg.cfg"
|
cfgFile := "llcppg.cfg"
|
||||||
|
symbFile := "llcppg.symb.json"
|
||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
cfgFile = os.Args[1]
|
cfgFile = os.Args[1]
|
||||||
}
|
}
|
||||||
@@ -63,9 +58,10 @@ func main() {
|
|||||||
headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes, conf.Cplusplus, false)
|
headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes, conf.Cplusplus, false)
|
||||||
check(err)
|
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)
|
check(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,92 +70,3 @@ func check(err error) {
|
|||||||
panic(err)
|
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