Skip to content

Commit

Permalink
Merge pull request #139 from luoliwoshang/gogensig/cppgpub
Browse files Browse the repository at this point in the history
gogensig:llcppg.pub gen
  • Loading branch information
luoliwoshang authored Nov 8, 2024
2 parents 2fba545 + f3005c9 commit f81bf7e
Show file tree
Hide file tree
Showing 24 changed files with 234 additions and 41 deletions.
12 changes: 7 additions & 5 deletions chore/gogensig/cmptest/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import (

// The validateFunc is used to validate the generated file,
func RunTest(t *testing.T, pkgName string, isCpp bool, symbolEntries []config.SymbolEntry, cppgConf *cppgtypes.Config, originalCode, expectedOutput string, validateFunc func(t *testing.T, pkg *convert.Package)) {
RunTestWithCheckEqual(t, pkgName, isCpp, symbolEntries, cppgConf, originalCode, expectedOutput, validateFunc, func(t *testing.T, expected, content string) {
if strings.TrimSpace(expected) != strings.TrimSpace(content) {
t.Errorf("does not match expected.\nExpected:\n%s\nGot:\n%s", expected, string(content))
}
})
RunTestWithCheckEqual(t, pkgName, isCpp, symbolEntries, cppgConf, originalCode, expectedOutput, validateFunc, CheckResult)
}

func CheckResult(t *testing.T, expected, content string) {
if strings.TrimSpace(expected) != strings.TrimSpace(content) {
t.Errorf("does not match expected.\nExpected:\n%s\nGot:\n%s", expected, string(content))
}
}

// RunTestWithCheckEqual initializes a test Go project with local llgo dependency
Expand Down
1 change: 1 addition & 0 deletions chore/gogensig/convert/basic/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func ConvertProcesser(cfg *Config) (*processor.DocFileSetProcessor, *convert.Pac
DepIncs: astConvert.Pkg.AllDepIncs(),
Done: func() {
astConvert.WriteLinkFile()
astConvert.WritePubFile()
},
}), astConvert.Pkg, nil
}
4 changes: 4 additions & 0 deletions chore/gogensig/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func (p *AstConvert) WriteLinkFile() {
p.Pkg.WriteLinkFile()
}

func (p *AstConvert) WritePubFile() {
p.Pkg.WritePubFile()
}

func (p *AstConvert) VisitFuncDecl(funcDecl *ast.FuncDecl) {
err := p.Pkg.NewFuncDecl(funcDecl)
if err != nil {
Expand Down
85 changes: 83 additions & 2 deletions chore/gogensig/convert/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package convert_test
import (
"log"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
Expand Down Expand Up @@ -330,24 +331,34 @@ func TestSkipBuiltinTypedefine(t *testing.T) {
cmptest.RunTest(t, "skip", false, []config.SymbolEntry{
{MangleName: "testInt", CppName: "testInt", GoName: "TestInt"},
{MangleName: "testUint", CppName: "testUint", GoName: "TestUint"},
{MangleName: "testFile", CppName: "testFile", GoName: "TestFile"},
}, &cppgtypes.Config{
Deps: []string{"github.com/goplus/llgo/chore/gogensig/convert/testdata/stdint"},
Deps: []string{
"github.com/goplus/llgo/chore/gogensig/convert/testdata/stdint",
"github.com/goplus/llgo/chore/gogensig/convert/testdata/stdio",
},
}, `
#include <stdint.h>
#include <stdio.h>
void testInt(int8_t a, int16_t b, int32_t c, int64_t d);
void testUint(u_int8_t a, u_int16_t b, u_int32_t c, u_int64_t d);
void testFile(FILE *f);
`,
`package skip
import (
"github.com/goplus/llgo/chore/gogensig/convert/testdata/stdint"
"github.com/goplus/llgo/chore/gogensig/convert/testdata/stdio"
_ "unsafe"
)
//go:linkname TestInt C.testInt
func TestInt(a stdint.Int8_t, b stdint.Int16_t, c stdint.Int32_t, d stdint.Int64_t)
//go:linkname TestUint C.testUint
func TestUint(a stdint.U_int8_t, b stdint.U_int16_t, c stdint.U_int32_t, d stdint.U_int64_t)
//go:linkname TestFile C.testFile
func TestFile(f *stdio.FILE)
`, func(t *testing.T, pkg *convert.Package) {
files, err := os.ReadDir(pkg.GetOutputDir())
if err != nil {
Expand All @@ -358,13 +369,83 @@ func TestUint(a stdint.U_int8_t, b stdint.U_int16_t, c stdint.U_int32_t, d stdin
log.Println("Generated file:", file.Name())
for _, headerFile := range needSkipHeaderFiles {
if file.Name() == convert.HeaderFileToGo(headerFile) {
t.Fatal("skip file should not be output")
content, err := os.ReadFile(filepath.Join(pkg.GetOutputDir(), file.Name()))
if err != nil {
t.Fatal(err)
}
t.Fatal("skip file should not be output: " + headerFile + "\n" + string(content))
}
}
}
})
}

func TestPubFile(t *testing.T) {
cmptest.RunTest(t, "pub", false, []config.SymbolEntry{
{MangleName: "func", CppName: "func", GoName: "Func"},
}, &cppgtypes.Config{
Include: []string{"temp.h"},
}, `
struct point {
int x;
int y;
};
struct Capital {
int x;
int y;
};
union data {
float f;
char str[20];
};
typedef unsigned int uint_t;
enum color {
RED = 0,
};
void func(int a, int b);
`, `
package pub
import (
"github.com/goplus/llgo/c"
_ "unsafe"
)
type Point struct {
X c.Int
Y c.Int
}
type Capital struct {
X c.Int
Y c.Int
}
type Data struct {
Str [20]int8
}
type Uint_t c.Uint
type Color c.Int
const Color_RED Color = 0
//go:linkname Func C.func
func Func(a c.Int, b c.Int)
`, func(t *testing.T, pkg *convert.Package) {
bytes, err := os.ReadFile(filepath.Join(pkg.GetOutputDir(), "llcppg.pub"))
if err != nil {
t.Fatal("llcppg.pub not found")
}
expectedPub := `
Capital
color Color
data Data
point Point
uint_t Uint_t
`
cmptest.CheckResult(t, expectedPub, string(bytes))
})
}

// ===========================error
func TestNewAstConvert(t *testing.T) {
_, err := convert.NewAstConvert(&convert.AstConvertConfig{
Expand Down
29 changes: 26 additions & 3 deletions chore/gogensig/convert/deps/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"

"github.com/goplus/llgo/chore/gogensig/config"
Expand Down Expand Up @@ -52,7 +53,7 @@ func Import(mod *Module, pkgPath string) (p *CPackage, err error) {
if err != nil {
return nil, err
}
pubs, err := readPubFile(filepath.Join(pkgDir, "llcppg.pub"))
pubs, err := ReadPubFile(filepath.Join(pkgDir, "llcppg.pub"))
if err != nil {
return nil, err
}
Expand All @@ -63,7 +64,7 @@ func Import(mod *Module, pkgPath string) (p *CPackage, err error) {
return &CPackage{Package: pkg, Path: pkgPath, Dir: pkgDir, Pubs: pubs, StdIncs: pkgIncs}, nil
}

func readPubFile(pubfile string) (ret map[string]string, err error) {
func ReadPubFile(pubfile string) (ret map[string]string, err error) {
b, err := os.ReadFile(pubfile)
if err != nil {
if os.IsNotExist(err) {
Expand Down Expand Up @@ -93,11 +94,33 @@ func readPubFile(pubfile string) (ret map[string]string, err error) {
return
}

func WritePubFile(file string, public map[string]string) (err error) {
if len(public) == 0 {
return
}
f, err := os.Create(file)
if err != nil {
return
}
defer f.Close()
ret := make([]string, 0, len(public))
for name, goName := range public {
if goName == "" {
ret = append(ret, name)
} else {
ret = append(ret, name+" "+goName)
}
}
sort.Strings(ret)
_, err = f.WriteString(strings.Join(ret, "\n"))
return
}

func findStdIncs(pkgDir string) (incs []string, err error) {
file := filepath.Join(pkgDir, "llcppg.cfg")
cfg, err := config.GetCppgCfgFromPath(file)
if err != nil {
return nil, err
}
return cfg.StdIncludes, nil
return cfg.Include, nil
}
57 changes: 41 additions & 16 deletions chore/gogensig/convert/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ type Package struct {
outputDir string
conf *PackageConfig
depIncs []string
inCurPkg bool // whether the current file is in the llcppg package not the dependent files
inCurPkg bool // whether the current file is in the llcppg package not the dependent files
public map[string]string // original C name -> public Go name

}

type PackageConfig struct {
Expand All @@ -57,9 +59,10 @@ type PackageConfig struct {
// If SetCurFile is not called, all type conversions will be written to this default Go file.
func NewPackage(config *PackageConfig) *Package {
p := &Package{
p: gogen.NewPackage(config.PkgPath, config.Name, config.GenConf),
name: config.Name,
conf: config,
p: gogen.NewPackage(config.PkgPath, config.Name, config.GenConf),
name: config.Name,
conf: config,
public: make(map[string]string),
}

p.outputDir = config.OutputDir
Expand Down Expand Up @@ -88,7 +91,7 @@ func NewPackage(config *PackageConfig) *Package {
func (p *Package) SetCurFile(file string, isHeaderFile bool, inCurPkg bool) error {
var fileName string
if isHeaderFile {
// headerfile to go filename
// include path to go filename
fileName = HeaderFileToGo(file)
} else {
// package name as the default file
Expand Down Expand Up @@ -160,7 +163,7 @@ func (p *Package) NewTypeDecl(typeDecl *ast.TypeDecl) error {
return nil
}
// every type name should be public
name, changed, err := p.DeclName(typeDecl.Name.Name)
name, changed, err := p.DeclName(typeDecl.Name.Name, true)
if err != nil {
return err
}
Expand All @@ -185,7 +188,7 @@ func (p *Package) NewTypeDecl(typeDecl *ast.TypeDecl) error {
}

func (p *Package) NewTypedefDecl(typedefDecl *ast.TypedefDecl) error {
name, changed, err := p.DeclName(typedefDecl.Name.Name)
name, changed, err := p.DeclName(typedefDecl.Name.Name, true)
if err != nil {
// for a typedef ,always appear same name like
// typedef struct foo { int a; } foo;
Expand Down Expand Up @@ -247,7 +250,7 @@ func (p *Package) createEnumType(enumName *ast.Ident) (types.Type, string, error
var err error
var t *gogen.TypeDecl
if enumName != nil {
name, changed, err = p.DeclName(enumName.Name)
name, changed, err = p.DeclName(enumName.Name, true)
if err != nil {
return nil, "", fmt.Errorf("enum type %s already defined", enumName.Name)
}
Expand All @@ -273,7 +276,7 @@ func (p *Package) createEnumItems(items []*ast.EnumItem, enumType types.Type, en
} else {
constName = item.Name.Name
}
name, changed, err := p.DeclName(constName)
name, changed, err := p.DeclName(constName, false)
if err != nil {
return fmt.Errorf("enum item %s already defined %w", name, err)
}
Expand Down Expand Up @@ -357,28 +360,42 @@ func (p *Package) WriteToBuffer(genFName string) (*bytes.Buffer, error) {

// /path/to/foo.h -> foo.go
// /path/to/_intptr.h -> SYS_intptr.go

func HeaderFileToGo(headerFile string) string {
_, fileName := filepath.Split(headerFile)
// for std include header file path
func HeaderFileToGo(incPath string) string {
// _, fileName := filepath.Split(headerFile)
fileName := strings.ReplaceAll(incPath, string(filepath.Separator), "_")
ext := filepath.Ext(fileName)
if len(ext) > 0 {
fileName = strings.TrimSuffix(fileName, ext)
}
if strings.HasPrefix(fileName, "_") {
fileName = "SYS" + fileName
fileName = "X" + fileName
}
return fileName + ".go"
}

func (p *Package) WritePubFile() error {
return deps.WritePubFile(filepath.Join(p.outputDir, "llcppg.pub"), p.public)
}

func (p *Package) initDepPkgs() {
allDepIncs := make([]string, 0)
scope := p.p.Types.Scope()
for _, dep := range p.deps {
allDepIncs = append(allDepIncs, dep.StdIncs...)
depPkg := p.p.Import(dep.Path)
for cName, pubGoName := range dep.Pubs {
if pubGoName == "" {
pubGoName = cName
}
if obj := depPkg.TryRef(pubGoName); obj != nil {
if old := scope.Insert(gogen.NewSubst(token.NoPos, p.p.Types, cName, obj)); old != nil {
var preObj types.Object
if pubGoName == cName {
preObj = obj
} else {
preObj = gogen.NewSubst(token.NoPos, p.p.Types, cName, obj)
}
if old := scope.Insert(preObj); old != nil {
log.Printf("conflicted name `%v` in %v, previous definition is %v\n", pubGoName, dep.Path, old)
}
}
Expand All @@ -390,7 +407,7 @@ func (p *Package) initDepPkgs() {
// For a decl name, if it's a current package, remove the prefixed name
// For a decl name, it should be unique
// todo(zzy): not current converter package file,need not remove prefixed name
func (p *Package) DeclName(name string) (pubName string, changed bool, err error) {
func (p *Package) DeclName(name string, collect bool) (pubName string, changed bool, err error) {
originName := name
if p.inCurPkg {
name = p.cvt.RemovePrefixedName(name)
Expand All @@ -399,7 +416,15 @@ func (p *Package) DeclName(name string) (pubName string, changed bool, err error
if obj := p.p.Types.Scope().Lookup(name); obj != nil {
return "", false, fmt.Errorf("type %s already defined,original name is %s", name, originName)
}
return name, name != originName, nil
changed = name != originName
if collect && p.inCurPkg {
if changed {
p.public[originName] = name
} else {
p.public[originName] = ""
}
}
return name, changed, nil
}

// AllDepIncs returns all std include paths of dependent packages
Expand Down
Loading

0 comments on commit f81bf7e

Please sign in to comment.