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
3 changes: 2 additions & 1 deletion cl/_testc/inline/in.cfg
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"LLGoPackage": "link: -L/path/foo -lfoo",
"CFlags": "-I/path/foo/include"
"CFlags": "-I/path/foo/include",
"WrapFileHeader": "#include <foo.h>\n"
}
4 changes: 4 additions & 0 deletions cl/_testc/inline/wrap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include <foo.h>

int _llcppg_add(int a, int b) {
return add(a, b);
}

int _llcppg_mul(int a, int b) {
return mul(a, b);
}
3 changes: 2 additions & 1 deletion cl/_testcpp/inline/in.cfg
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"LLGoPackage": "link: -L/path/foo -lfoo",
"CFlags": "-I/path/foo/include"
"CFlags": "-I/path/foo/include",
"WrapFileHeader": "#include <foo.h>\n"
}
8 changes: 6 additions & 2 deletions cl/_testcpp/inline/wrap.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
unsigned int _llcppg__ZN3bar1fEi(int a) {
#include <foo.h>

unsigned int _llcppg__ZN3bar1fEi(bar* this, int a) {
return this->f(a);
}

void _llcppg__ZN3bar2_gEv() {
void _llcppg__ZN3bar2_gEv(bar* this) {
this->_g();
}
8 changes: 6 additions & 2 deletions cl/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type classMethod struct {

type classCtx struct {
scopeCtx
decl clang.Cursor
typNamed *types.Named
fields []*types.Var
publicMethods []*classMethod
inPublic bool
Expand All @@ -55,12 +57,13 @@ func compileClass(ctx *pkgCtx, scope *classCtx, cls clang.Cursor) {
substObj(pkgTypes, pkgTypes.Scope(), origName, typNamed.Obj())
}
scope.reorder()
scope.typNamed = typNamed
for _, method := range scope.publicMethods {
obj := method.obj
if decl := method.outsideDecl; decl.Kind != 0 {
compileFuncOrMethod(ctx, decl, obj, typNamed)
compileFuncOrMethod(ctx, decl, obj, scope)
} else {
compileFuncOrMethod(ctx, obj.decl, obj, typNamed)
compileFuncOrMethod(ctx, obj.decl, obj, scope)
}
}
}
Expand All @@ -69,6 +72,7 @@ func loadClass(ctx *pkgCtx, cls clang.Cursor, defaultInPublic bool) {
pkg := ctx.pkg
pkgTypes := pkg.Types
scope := &classCtx{
decl: cls,
overloads: make(map[string]*overloads),
inPublic: defaultInPublic,
}
Expand Down
5 changes: 3 additions & 2 deletions cl/cltest/cltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ import (

// Config represents the lltest configuration.
type Config struct {
LLGoPackage string `json:"LLGoPackage"`
CFlags string `json:"CFlags"`
LLGoPackage string `json:"LLGoPackage"`
WrapFileHeader string `json:"WrapFileHeader"`
CFlags string `json:"CFlags"`
}

// LoadConf loads the lltest configuration.
Expand Down
8 changes: 6 additions & 2 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ type Config struct {
// If not specified, llcppg will skip wrapping inline functions/methods.
CFlags string

// WrapFileHeader specifies the header content to be included at the top of the generated
// wrapper file (optional).
WrapFileHeader string

// NameLookup looks up the archive path for a given mangling name. It returns the
// archive path and a boolean indicating whether the lookup was successful. If not
// specified, llcppg uses a default lookup function that returns an empty archivePath
Expand Down Expand Up @@ -136,8 +140,8 @@ func NewPackage(pkgPath, pkgName string, conf *Config, tu clang.TranslationUnit,
}
ctx := &pkgCtx{
pkg: pkg, cb: pkg.CB(), llgo: llgo, fset: pkg.Fset, tu: tu, c: c,
lang: conf.Language, cflags: conf.CFlags, nameLookup: nameLookup,
methods: make(map[string]*classMethod),
lang: conf.Language, cflags: conf.CFlags, wrapFileHeader: conf.WrapFileHeader,
nameLookup: nameLookup, methods: make(map[string]*classMethod),
}
ctx.initFiles(files)
loadFiles(ctx)
Expand Down
11 changes: 6 additions & 5 deletions cl/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ func testFromDir(t *testing.T, sel, relDir string, lang cl.Language) {
conf, _ := cltest.LoadConf(pkgDir + "/in.cfg")
imp := packages.NewImporter(nil)
pkg, err := cl.NewPackage("", "foo", &cl.Config{
Importer: imp,
LLGoPackage: conf.LLGoPackage,
Language: lang,
CFlags: conf.CFlags,
NameLookup: nil,
Importer: imp,
LLGoPackage: conf.LLGoPackage,
Language: lang,
WrapFileHeader: conf.WrapFileHeader,
CFlags: conf.CFlags,
NameLookup: nil,
}, u, filename)
if err != nil {
t.Error("cl.NewPackage:", err)
Expand Down
2 changes: 2 additions & 0 deletions cl/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ type pkgCtx struct {
cflags string
lang Language

wrapFileHeader string

nameLookup func(manglingName string) (archivePath string, ok bool)

fileBases map[clang.File]int // clang.File => base
Expand Down
9 changes: 5 additions & 4 deletions cl/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func loadGlobalFunc(ctx *pkgCtx, scope *scopeCtx, decl clang.Cursor) {
})
}

func compileFuncOrMethod(ctx *pkgCtx, fn clang.Cursor, obj *object, typNamed *types.Named) {
func compileFuncOrMethod(ctx *pkgCtx, fn clang.Cursor, obj *object, cls *classCtx) {
manglingName := clang.Mangling(fn)
origName := obj.name
if fn.IsFunctionInlined() != 0 {
Expand All @@ -47,7 +47,7 @@ func compileFuncOrMethod(ctx *pkgCtx, fn clang.Cursor, obj *object, typNamed *ty
}
return
}
manglingName = wrapInlineFunc(ctx, manglingName, fn)
manglingName = wrapInlineFunc(ctx, manglingName, fn, cls)
} else if _, ok := ctx.nameLookup(manglingName); !ok {
if debugCompileDecl {
log.Println("func", origName, "- skipped")
Expand All @@ -65,9 +65,10 @@ func compileFuncOrMethod(ctx *pkgCtx, fn clang.Cursor, obj *object, typNamed *ty
var recv *types.Var
var nameInPkg string
var fnName, rewritten = ctx.getPubName(origName, obj.order())
if typNamed == nil {
if cls == nil {
nameInPkg = fnName
} else {
typNamed := cls.typNamed
nameInPkg = "(*" + typNamed.Obj().Name() + ")." + fnName
recv = types.NewParam(token.NoPos, pkgTypes, "this", types.NewPointer(typNamed))
}
Expand All @@ -80,7 +81,7 @@ func compileFuncOrMethod(ctx *pkgCtx, fn clang.Cursor, obj *object, typNamed *ty
log.Panicln("compileFunc:", origName, err)
}

if typNamed == nil {
if cls == nil {
ctx.forceImportUnsafe()
f.SetComments(pkg, &ast.CommentGroup{
List: []*ast.Comment{
Expand Down
44 changes: 33 additions & 11 deletions cl/wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,45 +49,67 @@ func newWrapFile(ctx *pkgCtx) *WrapFile {
return &WrapFile{Filename: filename}
}

func wrapInlineFunc(ctx *pkgCtx, manglingName string, fn clang.Cursor) string {
func wrapInlineFunc(ctx *pkgCtx, manglingName string, fn clang.Cursor, cls *classCtx) string {
first := ctx.wrap == nil
if first {
ctx.wrap = newWrapFile(ctx)
}
w := &ctx.wrap.Content
if !first {
w.WriteByte('\n')
if first {
w.WriteString(ctx.wrapFileHeader)
}
w.WriteByte('\n')
wrapName := "_llcppg_" + manglingName
writeFunc(w, wrapName, fn)
writeFunc(w, wrapName, fn, cls)
return wrapName
}

// -----------------------------------------------------------------------------

type writerT = bytes.Buffer

func writeFunc(b *writerT, name string, fn clang.Cursor) {
writeFuncProto(b, name, fn)
b.WriteString(` {
}
`)
func writeFunc(b *writerT, name string, fn clang.Cursor, cls *classCtx) {
var call writerT
writeFuncProto(b, &call, name, fn, cls)
b.WriteString(" {\n")
b.Write(call.Bytes())
b.WriteString("}\n")
}

func writeFuncProto(out *writerT, name string, fn clang.Cursor) {
func writeFuncProto(out, call *writerT, name string, fn clang.Cursor, cls *classCtx) {
var b writerT
b.WriteString(name)
b.WriteByte('(')
call.WriteByte('\t')
retType := fn.ResultType()
if retType.Kind != lc.TypeVoid {
call.WriteString("return ")
}
notFirst := cls != nil
if notFirst {
b.WriteString(clang.String(cls.decl.Type()))
b.WriteString("* this")
call.WriteString("this->")
}
call.WriteString(clang.String(fn))
call.WriteByte('(')
for i := range c.Uint(fn.NumArguments()) {
if i > 0 {
call.WriteString(", ")
}
if notFirst {
b.WriteString(", ")
} else {
notFirst = true
}
arg := fn.Argument(i)
argName := clang.String(arg)
writeParam(&b, arg.Type(), argName)
call.WriteString(argName)
}
b.WriteByte(')')
writeParam(out, fn.ResultType(), b.String())
call.WriteString(");\n")
writeParam(out, retType, b.String())
}

func writeParam(b *writerT, typ lc.Type, name string) {
Expand Down
Loading