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
9 changes: 9 additions & 0 deletions cl/_testcpp/type_alias/in.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"LLGoPackage": "link: -L/path/foo -lfoo",
"CFlags": "-I/path/foo/include",
"WrapFileHeader": "#include <foo.h>\n",
"TypeAlias": {
"std::ptrdiff_t": "ptrdiff_t"
},
"LoadLibcPubFile": true
}
3 changes: 3 additions & 0 deletions cl/_testcpp/type_alias/in.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace std {
using ptrdiff_t = decltype(static_cast<int*>(nullptr) - static_cast<int*>(nullptr));
}
7 changes: 7 additions & 0 deletions cl/_testcpp/type_alias/out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package foo

import "github.com/goplus/lib/c"

const LLGoPackage = "link: -L/path/foo -lfoo"

type StdPtrdiffT = c.PtrdiffT
2 changes: 1 addition & 1 deletion cl/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ func baseClass(ctx *pkgCtx, decl clang.Cursor, feats *int) *types.TypeName {
}
switch t.Kind {
case lc.Type_Record:
cName := clang.String(t.Declaration().Type())
cName := cTypeName(t)
if t, ok := ctx.typeObj(cName); ok {
return t
}
Expand Down
14 changes: 8 additions & 6 deletions cl/cltest/cltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ import (

// Config represents the lltest configuration.
type Config struct {
LLGoPackage string `json:"LLGoPackage"`
WrapFileHeader string `json:"WrapFileHeader"`
CFlags string `json:"CFlags"`
Files []string `json:"Files"`
MacroIgnore []string `json:"MacroIgnore"`
KeepDoc bool `json:"KeepDoc"`
LLGoPackage string `json:"LLGoPackage"`
WrapFileHeader string `json:"WrapFileHeader"`
CFlags string `json:"CFlags"`
Files []string `json:"Files"`
TypeAlias map[string]string `json:"TypeAlias"`
MacroIgnore []string `json:"MacroIgnore"`
LoadLibcPubFile bool `json:"LoadLibcPubFile"`
KeepDoc bool `json:"KeepDoc"`
}

// LoadConf loads the lltest configuration.
Expand Down
5 changes: 4 additions & 1 deletion cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ type Config struct {
// TypeIgnore specifies a list of C/C++ type names to be ignored (optional).
TypeIgnore []string

// TypeAlias specifies a mapping of C/C++ type names to another C/C++ name (optional).
TypeAlias map[string]string

// TypeAbbr specifies a mapping of Go type name to its abbreviated name(s). The abbreviated
// name(s) can be a name or name list. They will be used in function names (optional).
TypeAbbr map[string]any
Expand Down Expand Up @@ -234,7 +237,7 @@ func NewPackage(pkgPath, pkgName string, files []Source, conf *Config) (ret Pack
keepDoc: !conf.DontKeepDoc, stdRecvName: conf.UseStdRecvName,
cflags: conf.CFlags, wrapFileHeader: conf.WrapFileHeader,
typeAbbr: conf.TypeAbbr, typeAbbrSuffix: conf.TypeAbbrSuffix,
typePrefix: conf.TypePrefix, typeSuffix: conf.TypeSuffix,
typePrefix: conf.TypePrefix, typeSuffix: conf.TypeSuffix, typeAlias: conf.TypeAlias,
fnPrefix: conf.FuncPrefix, enumPrefix: conf.EnumPrefix, rename: rename,
nsPrefix: conf.NSPrefix, macroPrefix: conf.MacroPrefix, varPrefix: conf.VarPrefix,
nsIgnore: conf.NSIgnore, macroIgnore: conf.MacroIgnore, typeIgnores: conf.TypeIgnore,
Expand Down
35 changes: 27 additions & 8 deletions cl/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cl_test

import (
"bytes"
"log"
"os"
"path/filepath"
"strings"
Expand All @@ -28,10 +29,12 @@ import (
"github.com/goplus/llcppg/cl"
"github.com/goplus/llcppg/cl/cltest"
"github.com/goplus/llcppg/clang"
"github.com/goplus/llcppg/tool"
"github.com/qiniu/x/test"
)

func init() {
log.SetFlags(0)
cl.SetDebug(cl.DbgFlagAll)
}

Expand Down Expand Up @@ -60,14 +63,26 @@ func testGenGo(t *testing.T, pkg *gogen.Package, dir string, exp any) {
func testFromDir(t *testing.T, sel, relDir string, lang cl.Language) {
idx := clang.CreateIndex(1, 1)
defer idx.Dispose()

cltest.TestFromDir(t, sel, relDir, func(t *testing.T, pkgDir string) {
pkgDir, _ = filepath.Abs(pkgDir)

conf, _ := cltest.LoadConf(pkgDir + "/in.cfg")
srcFiles := conf.Files
if len(srcFiles) == 0 {
srcFiles = []string{"in.h"}
}

var mod tool.Module
if conf.LoadLibcPubFile {
m, err := tool.LoadModuleFrom(pkgDir)
if err != nil {
t.Errorf("failed to load module: %v", err)
return
}
mod = m
}

files := make([]cl.Source, len(srcFiles))
for i, srcFile := range srcFiles {
presumedFile := filepath.Join(pkgDir, srcFile)
Expand All @@ -84,17 +99,21 @@ func testFromDir(t *testing.T, sel, relDir string, lang cl.Language) {
rootDir, myPkgName := filepath.Split(pkgDir)
imp := packages.NewImporter(nil, rootDir)
pkg, err := cl.NewPackage(pkgPrefix+myPkgName, "foo", files, &cl.Config{
Importer: imp,
LLGoPackage: conf.LLGoPackage,
Language: lang,
WrapFileHeader: conf.WrapFileHeader,
MacroIgnore: conf.MacroIgnore,
CFlags: conf.CFlags,
NameLookup: nil,
DontKeepDoc: !conf.KeepDoc,
Importer: imp,
LLGoPackage: conf.LLGoPackage,
Language: lang,
WrapFileHeader: conf.WrapFileHeader,
TypeAlias: conf.TypeAlias,
MacroIgnore: conf.MacroIgnore,
CFlags: conf.CFlags,
LoadLibcPubFile: conf.LoadLibcPubFile,
DontKeepDoc: !conf.KeepDoc,
NameLookup: nil,
PubFileLookup: func(pkgPath string) (pubFile string, ok bool) {
if name, ok := strings.CutPrefix(pkgPath, pkgPrefix); ok {
return filepath.Join(rootDir, name, "llcppg.pub"), true
} else if conf.LoadLibcPubFile {
return mod.PubFileLookup(pkgPath)
}
return
},
Expand Down
7 changes: 4 additions & 3 deletions cl/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type pkgCtx struct {
nonClasses []string // typedef names to be treated as non-classes
typeAbbr map[string]any // Go type name => abbreviated name(s), used in function names
rename map[string]string // C/C++ name => Go name
typeAlias map[string]string // C/C++ type name => another C/C++ type name
typeIgnores []string // C/C++ type names to be ignored
macroIgnore []string // C/C++ macro names to be ignored
nsIgnore []string // C/C++ namespace names to be ignored
Expand Down Expand Up @@ -258,18 +259,18 @@ func (p *pkgCtx) ignoreType(cName string, feats int) {
}

func (p *pkgCtx) isTypeIgnored(cName string) bool {
return contains(trimTypeTag(cName), p.typeIgnores)
return contains(cName, p.typeIgnores)
}

func (p *pkgCtx) typeObj(cName string) (*types.TypeName, bool) {
if o, ok := p.types[cName]; ok {
if o, ok := p.types[cName]; ok && o.feats&featQuietIgnore == 0 {
return o.TypeName, true
}
return nil, false
}

func (p *pkgCtx) typeOf(cName string) (types.Type, bool) {
if o, ok := p.types[cName]; ok {
if o, ok := p.types[cName]; ok && o.feats&featQuietIgnore == 0 {
return o.Type(), true
}
return nil, false
Expand Down
2 changes: 1 addition & 1 deletion cl/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func toTypeEx(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, feats *in
default:
ctx.logtf(typ, "toType: unknown kind - %v", typ.Kind)
}
ctx.logtf(typ, "unsupported type - %s", clang.String(typ))
ctx.logtf(typ, "toType: unsupported type - %s", clang.String(typ))
*feats |= featExplicitIgnore
return types.Typ[types.Invalid]
}
Expand Down
27 changes: 20 additions & 7 deletions cl/typedef.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,23 @@ import (
// -----------------------------------------------------------------------------

func loadTypedef(ctx *pkgCtx, decl clang.Cursor, scope *scopeCtx) {
cName := cNameOf(decl)
pkg := ctx.pkg
pkgTypes := pkg.Types

var feats int
var underlying lc.Type
var tunder types.Type
var cName = cNameOf(decl)
var goName = ctx.typeName(cName, true)
if cNewName, ok := ctx.typeAlias[cName]; ok {
if t, ok := ctx.typeOf(cNewName); ok {
tunder = t
goto lzFind
}
ctx.logf(decl, "typedef %s: alias to %s but not found, skipped", cName, cNewName)
return
}

if ctx.isTypeIgnored(cName) {
ctx.ignoref(featQuietIgnore, decl, "typedef %s: ignored by config", cName)
ctx.ignoreType(cName, featQuietIgnore)
Expand All @@ -38,15 +54,12 @@ func loadTypedef(ctx *pkgCtx, decl clang.Cursor, scope *scopeCtx) {
return
}

pkg := ctx.pkg
pkgTypes := pkg.Types
underlying := decl.TypedefDeclUnderlyingType()
underlying = decl.TypedefDeclUnderlyingType()
if debugCompileDecl {
ctx.logf(decl, "typedef %ss: %s", cName, clang.String(underlying))
}

feats := 0
tunder := toTypeEx(ctx, pkgTypes, underlying, flagIsTypeDef, &feats, scope)
tunder = toTypeEx(ctx, pkgTypes, underlying, flagIsTypeDef, &feats, scope)
if feats&featQuietIgnore != 0 || isTypedefUnsupported(tunder) {
ctx.ignoref(featQuietIgnore, decl, "typedef %s: unsupported underlying type, ignored", cName)
ctx.ignoreType(cName, featQuietIgnore)
Expand All @@ -58,13 +71,13 @@ func loadTypedef(ctx *pkgCtx, decl clang.Cursor, scope *scopeCtx) {
return
}

goName := ctx.typeName(cName, true)
if tn, ok := tunder.(*types.Named); ok {
if o := tn.Obj(); o.Pkg() == pkgTypes && o.Name() == goName {
return // already defined
}
}

lzFind:
var obj *types.TypeName
var typDefs = pkg.NewTypeDefs()
if doc := ctx.directiveTypeC(decl, feats&featHasCallback != 0); doc != nil {
Expand Down
20 changes: 0 additions & 20 deletions cl/var.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,12 @@ import (

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

// loadVar loads a C/C++ variable declaration (a global variable, a variable
// within a namespace, or a static variable within a class) and schedules it to
// be compiled into a Go variable.
//
// The Go name is prefixed by ns, which encodes the enclosing namespaces and/or
// class (the class name acts like a namespace, mirroring how static methods are
// handled). Non-static class member variables are fields, not VarDecls, and are
// handled separately in loadClassMember.
func loadVar(ctx *pkgCtx, decl clang.Cursor) {
ctx.addCompileUnit(func(ctx *pkgCtx) {
compileVar(ctx, decl)
})
}

// compileVar compiles a C/C++ variable into a Go variable declared with a
// //go:linkname directive that binds it to the external C/C++ symbol, similar
// to how a global function is compiled in compileFuncOrMethod.
//
// A const-qualified variable (e.g. const int x;) is handled the same way: in
// terms of C/C++ semantics a const is just an immutable var, and there is no
// difference in the underlying binding logic. It maps to the same Go var linked
// to the same C/C++ symbol; Go has no way to express a linkname-bound immutable
// value, so the const-ness is not reflected in the generated declaration. The
// const qualifier is a property of the type, not a distinct type kind, so
// toType (which switches on the type kind) already yields the unqualified Go
// type without any special casing here.
func compileVar(ctx *pkgCtx, decl clang.Cursor) {
cName := cNameOf(decl)
if varHasInitExpr(ctx, decl) {
Expand Down
2 changes: 2 additions & 0 deletions cmd/llcppg/llcppg.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package main
import (
"flag"
"fmt"
"log"
"os"

"github.com/goplus/gogen"
Expand All @@ -45,6 +46,7 @@ func main() {
srcDir = args[1]
}

log.SetFlags(0)
if *debug {
cl.SetDebug(cl.DbgFlagAll)
tool.SetDebug(tool.DbgFlagAll)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.27.0 // llgo 1.0

require (
github.com/goplus/gogen v1.25.3
github.com/goplus/lib v0.5.5
github.com/goplus/lib v0.5.6
github.com/goplus/mod v0.22.1
github.com/llarhub/clang-c v0.7.0
github.com/qiniu/x v1.18.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/goplus/gogen v1.25.3 h1:g8VWgNcCwTG9DFs08umVNtxl/BSLHH1cbvqWzyxrPVk=
github.com/goplus/gogen v1.25.3/go.mod h1:Y7ulYW3wonQ3d9er00b0uGFEV/IUZa6okWJZh892ACQ=
github.com/goplus/lib v0.5.5 h1:COcqsafjaXBI6ikcyJgnc7l9Hu03K8kymUSIZtXNTz8=
github.com/goplus/lib v0.5.5/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
github.com/goplus/lib v0.5.6 h1:lSr4QKgTtIZtD/9aAjwhQW2fzHyyWLNT8FviNSBZEgs=
github.com/goplus/lib v0.5.6/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
github.com/goplus/mod v0.22.1 h1:3GQZqKlcQAiMpRUDAHvFryGYie+mT0JMjguEqOtIjkE=
github.com/goplus/mod v0.22.1/go.mod h1:APrczG2FtFcQelU4vTq9xw+GrVs4sPPKnRfGidWBlXY=
github.com/llarhub/clang-c v0.7.0 h1:YkO1FR1R1ScKJijF1PUVIpHnIC4uNgsSg/7CLzEBpFE=
Expand Down
2 changes: 1 addition & 1 deletion tool/_testc/clang-c-22.1.8/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ module clang

go 1.20

require github.com/goplus/lib v0.5.4
require github.com/goplus/lib v0.5.6
4 changes: 2 additions & 2 deletions tool/_testc/clang-c-22.1.8/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/goplus/lib v0.5.4 h1:Ltrj+lY844/jx0nJqCRQEq3YzBkHb3jBjCQZWFUdlTc=
github.com/goplus/lib v0.5.4/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
github.com/goplus/lib v0.5.6 h1:lSr4QKgTtIZtD/9aAjwhQW2fzHyyWLNT8FviNSBZEgs=
github.com/goplus/lib v0.5.6/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
2 changes: 1 addition & 1 deletion tool/_testcpp/llvm-22.1.8-support/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module llvm
go 1.23

require (
github.com/goplus/lib v0.5.4
github.com/goplus/lib v0.5.6
github.com/llarhub/libcxx v0.1.1
github.com/llarhub/llvm-c v0.2.0
)
4 changes: 2 additions & 2 deletions tool/_testcpp/llvm-22.1.8-support/go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/goplus/lib v0.5.4 h1:Ltrj+lY844/jx0nJqCRQEq3YzBkHb3jBjCQZWFUdlTc=
github.com/goplus/lib v0.5.4/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
github.com/goplus/lib v0.5.6 h1:lSr4QKgTtIZtD/9aAjwhQW2fzHyyWLNT8FviNSBZEgs=
github.com/goplus/lib v0.5.6/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
github.com/llarhub/libcxx v0.1.1 h1:pq/qd3sgtDsima+rrgwOEHYGd/YnyePe6p86rHFD+Xs=
github.com/llarhub/libcxx v0.1.1/go.mod h1:5ANUOJMknbqPXhwxbXnLLA8NbHHyfYWUVQNCPiz04f8=
github.com/llarhub/llvm-c v0.2.0 h1:KXSm+1A9AjyxOcVTtZnlgvWDaWwBySMR27xSouaOaGg=
Expand Down
Loading