diff --git a/_xtool/llcppsymg/internal/symg/symg_test.go b/_xtool/llcppsymg/internal/symg/symg_test.go index 35eb275e..48f52111 100644 --- a/_xtool/llcppsymg/internal/symg/symg_test.go +++ b/_xtool/llcppsymg/internal/symg/symg_test.go @@ -1,6 +1,7 @@ package symg_test import ( + "bytes" "encoding/json" "fmt" "log" @@ -13,8 +14,6 @@ import ( "strings" "testing" - "github.com/goplus/llcppg/_xtool/internal/clangtool" - "github.com/goplus/llcppg/_xtool/internal/header" "github.com/goplus/llcppg/_xtool/internal/symbol" "github.com/goplus/llcppg/_xtool/llcppsymg/internal/symg" llcppg "github.com/goplus/llcppg/config" @@ -272,6 +271,27 @@ class INIReader { }, }, }, + + { + name: "Non-exported functions", + content: ` + void Foo_Bar(); + #define private static + static void Foo_Bar_Private(); + private + void Foo_Bar_Private2(); + + `, + isCpp: false, + expect: []*llcppg.SymbolInfo{ + { + Go: "FooBar", + CPP: "Foo_Bar()", + Mangle: "Foo_Bar", + }, + }, + }, + { name: "InvalidReceiver PointerLevel > 1", content: ` @@ -379,110 +399,41 @@ class INIReader { } func TestGen(t *testing.T) { - gen := false testCases := []struct { - name string - path string - libSymbols []string + name string + path string }{ { name: "c", path: "./testdata/c", - libSymbols: []string{ - "Foo_Print", - "Foo_ParseWithLength", - "Foo_Delete", - "Foo_ParseWithSize", - "Foo_ignoreFunc", - "Foo_Bar", - "Foo_ForBar", - "Foo_Bar2", - "Foo_ForBar2", - "Foo_Prefix_BarMethod", - "Foo_BarMethod", - "Foo_ForBarMethod", - "Foo_ReceiverParse", - "Foo_FunctionParse", - "Foo_ReceiverParse2", - "Foo_Receiver2Parse2", - }, }, { name: "cpp", path: "./testdata/cpp", - libSymbols: []string{ - "ZN3FooC1EPKc", - "ZN3FooC1EPKcl", - "ZN3FooD1Ev", - "ZNK3Foo8ParseBarEv", - "ZNK3Foo3GetEPKcS1_S1_", - "ZN3Foo6HasBarEv", - }, }, { name: "inireader", path: "./testdata/inireader", - libSymbols: []string{ - "ZN9INIReaderC1EPKc", - "ZN9INIReaderC1EPKcl", - "ZN9INIReaderD1Ev", - "ZNK9INIReader10ParseErrorEv", - "ZNK9INIReader3GetEPKcS1_S1_", - // Check whether private fields are filtered. - // If not, the result will certainly not match expect.json. - // NOTE(MeteorsLiu): Symbols below this comment must be removed during regeneration. - "ZN9INIReader7MakeKeyERKiS1_", - }, }, { name: "lua", path: "./testdata/lua", - libSymbols: []string{ - "lua_error", - "lua_next", - "lua_concat", - "lua_stringtonumber", - }, }, { name: "cjson", path: "./testdata/cjson", - libSymbols: []string{ - "cJSON_Print", - "cJSON_ParseWithLength", - "cJSON_Delete", - // mock multiple symbols - "cJSON_Delete", - }, }, { name: "isl", path: "./testdata/isl", - libSymbols: []string{ - "isl_pw_qpolynomial_get_ctx", - }, }, { name: "gpgerror", path: "./testdata/gpgerror", - libSymbols: []string{ - "gpg_strsource", - "gpg_strerror_r", - "gpg_strerror", - }, }, { name: "include", path: "./testdata/include", - libSymbols: []string{ - "Foo", - "Foo_Bar", - "Foo_Conf", - // only for checking the result of private fields filtering - // NOTE(MeteorsLiu): Symbols below this comment must be removed during regeneration. - "Foo_Bar_Private", - "Foo_Bar_Private2", - }, }, } @@ -496,50 +447,67 @@ func TestGen(t *testing.T) { if err != nil { t.Fatal(err) } + libName := filepath.Base(projPath) + libDir := filepath.Join(projPath, runtime.GOOS) + cfg.Libs = fmt.Sprintf("-L%s -l%s", libDir, libName) cfg.CFlags = "-I" + projPath - tempFile, err := os.CreateTemp("", "combine*.h") - if err != nil { - t.Fatal(err) + gen := false + + if gen { + cFiles, hasCpp := scanCFiles(projPath) + + // make sure we have this dir + os.MkdirAll(libDir, 0700) + staticLibFile := filepath.Join(libDir, "lib"+filepath.Base(projPath)+".a") + + compileCommand := []string{cfg.CFlags, "-o", staticLibFile, "-c"} + if !hasCpp { + compileCommand = append(compileCommand, "-x", "c") + } + compileCommand = append(compileCommand, cFiles...) + + cmd := exec.Command("clang++", compileCommand...) + res, err := cmd.CombinedOutput() + if err != nil { + t.Fatal(string(res)) + return + } } - defer os.Remove(tempFile.Name()) - clangtool.ComposeIncludes(cfg.Include, tempFile.Name()) - pkgHfileInfo := header.PkgHfileInfo(&header.Config{ - Includes: cfg.Include, - Args: strings.Fields(cfg.CFlags), - Mix: false, + symbolTable, err := symg.Do(&symg.Config{ + Libs: cfg.Libs, + CFlags: cfg.CFlags, + Includes: cfg.Include, + Mix: cfg.Mix, + TrimPrefixes: cfg.TrimPrefixes, + SymMap: cfg.SymMap, + IsCpp: cfg.Cplusplus, + LibMode: symbol.ModeStatic, }) - headerSymbolMap, err := symg.ParseHeaderFile(tempFile.Name(), pkgHfileInfo.CurPkgFiles(), cfg.TrimPrefixes, strings.Fields(cfg.CFlags), cfg.SymMap, cfg.Cplusplus) + if err != nil { t.Fatal(err) + return } + expectFile := filepath.Join(projPath, "expect.json") - // trim to nm symbols - var libSymbols []*nm.Symbol - for _, symb := range tc.libSymbols { - libSymbols = append(libSymbols, &nm.Symbol{Name: addSymbolPrefixUnder(symb, cfg.Cplusplus)}) - } - symbols := symg.GetCommonSymbols(libSymbols, headerSymbolMap) + symbolData, err := json.MarshalIndent(&symbolTable, "", " ") if err != nil { t.Fatal(err) } - symbolData, err := json.MarshalIndent(symbols, "", " ") + if gen { + os.WriteFile(expectFile, symbolData, 0644) + return + } + + expectData, err := os.ReadFile(expectFile) if err != nil { t.Fatal(err) } - expectFile := filepath.Join(projPath, "expect.json") - if gen { - os.WriteFile(expectFile, symbolData, 0644) - } else { - expectData, err := os.ReadFile(expectFile) - if err != nil { - t.Fatal(err) - } - if string(symbolData) != string(expectData) { - t.Fatalf("expect %s, but got %s", expectData, symbolData) - } + if !bytes.Equal(expectData, symbolData) { + t.Fatalf("expect %s, but got %s", string(expectData), string(symbolData)) } }) } @@ -686,3 +654,21 @@ func getDynamicLibExt() string { } return ".so" } + +// the reason why this function appears here is that llgo dones't support os.ReadDir() currently +func scanCFiles(dir string) (ret []string, hasCpp bool) { + cmd := exec.Command("ls") + cmd.Dir = dir + res, _ := cmd.Output() + + for _, fileName := range strings.Fields(string(res)) { + if strings.HasSuffix(fileName, ".c") || strings.HasSuffix(fileName, ".cpp") { + if strings.HasSuffix(fileName, ".cpp") { + hasCpp = true + } + ret = append(ret, filepath.Join(dir, fileName)) + } + } + + return +} diff --git a/_xtool/llcppsymg/internal/symg/testdata/c/c.c b/_xtool/llcppsymg/internal/symg/testdata/c/c.c new file mode 100644 index 00000000..ed626c7a --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/c/c.c @@ -0,0 +1,28 @@ +#include "c.h" + +char *Foo_Print(const Foo *item) {} +// config not be a method in llcppg.cfg/symMap +void Foo_Delete(Foo *item) {} +// normal function no be a method +Foo *Foo_ParseWithLength(const char *value, size_t buffer_length) {} +// only can be a normal function but config be a method,keep output as function +Foo *Foo_ParseWithSize(const char *value, size_t buffer_length) {} + +Foo *Foo_ignoreFunc() {} + +// config Foo_ForBar to Bar,so Foo_Bar to Bar__1 +void Foo_Bar() {} +void Foo_ForBar() {} + +void Foo_Prefix_BarMethod(Foo *item) {} // to BarMethod,but follow config the BarMethod,so it need add prefix +void Foo_BarMethod(Foo *item) {} // config BarMethod +void Foo_ForBarMethod(Foo *item) {} // config BarMethod,so it need add suffix + +// first receiver Foo's method,with name 'Parse' +void Foo_ReceiverParse(Foo *item) {} +// first function with name 'Parse' +void Foo_FunctionParse() {} +// second receiver Foo's method,with name 'Parse', and the next method name is the same,so we need add suffix +void Foo_ReceiverParse2(Foo *item) {} +// not same receiver,but same function name,we don't need add suffix +void Foo_Receiver2Parse2(Foo2 *item) {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/c/darwin/libc.a b/_xtool/llcppsymg/internal/symg/testdata/c/darwin/libc.a new file mode 100644 index 00000000..e962ecc2 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/c/darwin/libc.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/c/linux/libc.a b/_xtool/llcppsymg/internal/symg/testdata/c/linux/libc.a new file mode 100644 index 00000000..a0b90501 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/c/linux/libc.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/cjson/cJSON.c b/_xtool/llcppsymg/internal/symg/testdata/cjson/cJSON.c new file mode 100644 index 00000000..fe5782af --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/cjson/cJSON.c @@ -0,0 +1,9 @@ +#include "cJSON.h" + +CJSON_PUBLIC(char *) +cJSON_Print(const cJSON *item) {} +CJSON_PUBLIC(cJSON *) +cJSON_ParseWithLength(const char *value, size_t buffer_length) {} +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) +cJSON_Delete(cJSON *item) {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/cjson/darwin/libcjson.a b/_xtool/llcppsymg/internal/symg/testdata/cjson/darwin/libcjson.a new file mode 100644 index 00000000..b7f54d2a Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/cjson/darwin/libcjson.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/cjson/linux/libcjson.a b/_xtool/llcppsymg/internal/symg/testdata/cjson/linux/libcjson.a new file mode 100644 index 00000000..d0f6bc57 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/cjson/linux/libcjson.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.cpp b/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.cpp new file mode 100644 index 00000000..b3be4285 --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.cpp @@ -0,0 +1,10 @@ +#include "cpp.h" + +Foo::Foo(const char *filename) {} +Foo::Foo(const char *buffer, long buffer_size) {} +Foo::Foo::~Foo() {} +int Foo::ParseBar() const {} +const char *Foo::Get(const char *section, const char *name, + const char *default_value) const {} + +const char *Foo::MakeBar(const char *section, const char *name) {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.h b/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.h index 60c14084..ffd5b02c 100644 --- a/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.h +++ b/_xtool/llcppsymg/internal/symg/testdata/cpp/cpp.h @@ -11,11 +11,9 @@ class Foo int ParseBar() const; // not in llcppg.cfg/symMap,generate automatically const char *Get(const char *section, const char *name, - const char *default_value) const; + const char *default_value) const; + private: // not in output symbol table static const char *MakeBar(const char *section, const char *name); }; - -// method out of class decl -bool Foo::HasBar(); \ No newline at end of file diff --git a/_xtool/llcppsymg/internal/symg/testdata/cpp/darwin/libcpp.a b/_xtool/llcppsymg/internal/symg/testdata/cpp/darwin/libcpp.a new file mode 100644 index 00000000..520fd186 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/cpp/darwin/libcpp.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/cpp/expect.json b/_xtool/llcppsymg/internal/symg/testdata/cpp/expect.json index a75bd83b..20b2648c 100644 --- a/_xtool/llcppsymg/internal/symg/testdata/cpp/expect.json +++ b/_xtool/llcppsymg/internal/symg/testdata/cpp/expect.json @@ -1,9 +1,4 @@ [ - { - "mangle": "_ZN3Foo6HasBarEv", - "c++": "Foo::HasBar()", - "go": "(*Foo).HasBar" - }, { "mangle": "_ZN3FooC1EPKc", "c++": "Foo::Foo(const char *)", diff --git a/_xtool/llcppsymg/internal/symg/testdata/cpp/linux/libcpp.a b/_xtool/llcppsymg/internal/symg/testdata/cpp/linux/libcpp.a new file mode 100644 index 00000000..7d99c726 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/cpp/linux/libcpp.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/gpgerror/darwin/libgpgerror.a b/_xtool/llcppsymg/internal/symg/testdata/gpgerror/darwin/libgpgerror.a new file mode 100644 index 00000000..9864b04f Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/gpgerror/darwin/libgpgerror.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/gpgerror/gpgerror.c b/_xtool/llcppsymg/internal/symg/testdata/gpgerror/gpgerror.c new file mode 100644 index 00000000..d8e69127 --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/gpgerror/gpgerror.c @@ -0,0 +1,5 @@ +#include "gpgrt.h" + +const char *gpg_strerror(gpg_error_t err) {} +int gpg_strerror_r(gpg_error_t err, char *buf, size_t buflen) {} +const char *gpg_strsource(gpg_error_t err) {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/gpgerror/linux/libgpgerror.a b/_xtool/llcppsymg/internal/symg/testdata/gpgerror/linux/libgpgerror.a new file mode 100644 index 00000000..c4fb8566 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/gpgerror/linux/libgpgerror.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/include/darwin/libinclude.a b/_xtool/llcppsymg/internal/symg/testdata/include/darwin/libinclude.a new file mode 100644 index 00000000..6d3ab114 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/include/darwin/libinclude.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/include/linux/libinclude.a b/_xtool/llcppsymg/internal/symg/testdata/include/linux/libinclude.a new file mode 100644 index 00000000..1b7ff300 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/include/linux/libinclude.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/include/temp.c b/_xtool/llcppsymg/internal/symg/testdata/include/temp.c new file mode 100644 index 00000000..64f58c50 --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/include/temp.c @@ -0,0 +1,7 @@ +#include "temp.h" + +void Foo() {} +void Foo_Conf() {} +void Foo_Bar() {} +static void Foo_Bar_Private() {} +private void Foo_Bar_Private2() {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/inireader/INIReader.cpp b/_xtool/llcppsymg/internal/symg/testdata/inireader/INIReader.cpp new file mode 100644 index 00000000..8a55efe2 --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/inireader/INIReader.cpp @@ -0,0 +1,10 @@ +#include "INIReader.h" + +__attribute__((visibility("default"))) INIReader::INIReader(const char *filename) {} +INI_API INIReader::INIReader(const char *buffer, long buffer_size) {} +INIReader::~INIReader() {} +INI_API int INIReader::ParseError() const {} +INI_API const char *INIReader::Get(const char *section, const char *name, + const char *default_value) const {} + +const char *INIReader::MakeKey(const char *section, const char *name) {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/inireader/darwin/libinireader.a b/_xtool/llcppsymg/internal/symg/testdata/inireader/darwin/libinireader.a new file mode 100644 index 00000000..5e4e1de7 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/inireader/darwin/libinireader.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/inireader/linux/libinireader.a b/_xtool/llcppsymg/internal/symg/testdata/inireader/linux/libinireader.a new file mode 100644 index 00000000..30cd6119 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/inireader/linux/libinireader.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/isl/darwin/libisl.a b/_xtool/llcppsymg/internal/symg/testdata/isl/darwin/libisl.a new file mode 100644 index 00000000..0ad42ac9 Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/isl/darwin/libisl.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/isl/isl.c b/_xtool/llcppsymg/internal/symg/testdata/isl/isl.c new file mode 100644 index 00000000..31da05ca --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/isl/isl.c @@ -0,0 +1,3 @@ +#include "isl/polynomial.h" + +isl_ctx *isl_pw_qpolynomial_get_ctx(__isl_keep isl_pw_qpolynomial *pwqp) {} diff --git a/_xtool/llcppsymg/internal/symg/testdata/isl/linux/libisl.a b/_xtool/llcppsymg/internal/symg/testdata/isl/linux/libisl.a new file mode 100644 index 00000000..796f00ae Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/isl/linux/libisl.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/lua/darwin/liblua.a b/_xtool/llcppsymg/internal/symg/testdata/lua/darwin/liblua.a new file mode 100644 index 00000000..2bd4350b Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/lua/darwin/liblua.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/lua/expect.json b/_xtool/llcppsymg/internal/symg/testdata/lua/expect.json index de180c0e..444f84f0 100644 --- a/_xtool/llcppsymg/internal/symg/testdata/lua/expect.json +++ b/_xtool/llcppsymg/internal/symg/testdata/lua/expect.json @@ -1,4 +1,9 @@ [ + { + "mangle": "lua_closeslot", + "c++": "lua_closeslot(lua_State *, int)", + "go": "(*State).Closeslot" + }, { "mangle": "lua_concat", "c++": "lua_concat(lua_State *, int)", @@ -9,14 +14,29 @@ "c++": "lua_error(lua_State *)", "go": "(*State).Error" }, + { + "mangle": "lua_len", + "c++": "lua_len(lua_State *, int)", + "go": "(*State).Len" + }, { "mangle": "lua_next", "c++": "lua_next(lua_State *, int)", "go": "(*State).Next" }, + { + "mangle": "lua_setallocf", + "c++": "lua_setallocf(lua_State *, lua_Alloc, void *)", + "go": "(*State).Setallocf" + }, { "mangle": "lua_stringtonumber", "c++": "lua_stringtonumber(lua_State *, const char *)", "go": "(*State).Stringtonumber" + }, + { + "mangle": "lua_toclose", + "c++": "lua_toclose(lua_State *, int)", + "go": "(*State).Toclose" } ] \ No newline at end of file diff --git a/_xtool/llcppsymg/internal/symg/testdata/lua/linux/liblua.a b/_xtool/llcppsymg/internal/symg/testdata/lua/linux/liblua.a new file mode 100644 index 00000000..a189005e Binary files /dev/null and b/_xtool/llcppsymg/internal/symg/testdata/lua/linux/liblua.a differ diff --git a/_xtool/llcppsymg/internal/symg/testdata/lua/lua.c b/_xtool/llcppsymg/internal/symg/testdata/lua/lua.c new file mode 100644 index 00000000..e9231c10 --- /dev/null +++ b/_xtool/llcppsymg/internal/symg/testdata/lua/lua.c @@ -0,0 +1,10 @@ +#include "lua.h" + +int(lua_error)(lua_State *L) {} +void(lua_concat)(lua_State *L, int n) {} +int(lua_next)(lua_State *L, int idx) {} +void(lua_len)(lua_State *L, int idx) {} +long unsigned int(lua_stringtonumber)(lua_State *L, const char *s) {} +void(lua_setallocf)(lua_State *L, lua_Alloc f, void *ud) {} +void(lua_toclose)(lua_State *L, int idx) {} +void(lua_closeslot)(lua_State *L, int idx) {}