Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 87 additions & 101 deletions _xtool/llcppsymg/internal/symg/symg_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package symg_test

import (
"bytes"
"encoding/json"
"fmt"
"log"
Expand All @@ -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"
Expand Down Expand Up @@ -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: `
Expand Down Expand Up @@ -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",
},
},
}

Expand All @@ -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))
}
})
}
Expand Down Expand Up @@ -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
}
28 changes: 28 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/c/c.c
Original file line number Diff line number Diff line change
@@ -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) {}
Comment thread
luoliwoshang marked this conversation as resolved.
Binary file not shown.
Binary file not shown.
9 changes: 9 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/cjson/cJSON.c
Original file line number Diff line number Diff line change
@@ -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) {}
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/cpp/cpp.cpp
Original file line number Diff line number Diff line change
@@ -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) {}
6 changes: 2 additions & 4 deletions _xtool/llcppsymg/internal/symg/testdata/cpp/cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Binary file not shown.
5 changes: 0 additions & 5 deletions _xtool/llcppsymg/internal/symg/testdata/cpp/expect.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
[
{
"mangle": "_ZN3Foo6HasBarEv",
"c++": "Foo::HasBar()",
"go": "(*Foo).HasBar"
},
{
"mangle": "_ZN3FooC1EPKc",
"c++": "Foo::Foo(const char *)",
Expand Down
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/gpgerror/gpgerror.c
Original file line number Diff line number Diff line change
@@ -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) {}
Binary file not shown.
Binary file not shown.
Binary file not shown.
7 changes: 7 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/include/temp.c
Original file line number Diff line number Diff line change
@@ -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() {}
10 changes: 10 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/inireader/INIReader.cpp
Original file line number Diff line number Diff line change
@@ -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) {}
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 3 additions & 0 deletions _xtool/llcppsymg/internal/symg/testdata/isl/isl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "isl/polynomial.h"

isl_ctx *isl_pw_qpolynomial_get_ctx(__isl_keep isl_pw_qpolynomial *pwqp) {}
Binary file not shown.
Binary file not shown.
Loading
Loading