Documentation ¶
Overview ¶
Example (ConvertingEnums) ¶
This is an example of how to convert enums.
package main import ( "bytes" "fmt" "strings" "github.com/gorgonia/bindgen" "modernc.org/cc" ) // genEnums represents a list of enums we want to generate var genEnums = map[bindgen.TypeKey]struct{}{ {Kind: cc.Enum, Name: "error"}: {}, } var enumMappings = map[bindgen.TypeKey]string{ {Kind: cc.Enum, Name: "error"}: "Status", } // This is an example of how to convert enums. func main() { t, err := bindgen.Parse(bindgen.Model(), "testdata/dummy.h") if err != nil { panic(err) } enums := func(decl *cc.Declarator) bool { name := bindgen.NameOf(decl) kind := decl.Type.Kind() tk := bindgen.TypeKey{Kind: kind, Name: name} if _, ok := genEnums[tk]; ok { return true } return false } decls, err := bindgen.Get(t, enums) if err != nil { panic(err) } var buf bytes.Buffer for _, d := range decls { // first write the type // type ___ int // This is possible because cznic/cc parses all enums as int. // // you are clearly free to add your own mapping. e := d.(*bindgen.Enum) tk := bindgen.TypeKey{Kind: cc.Enum, Name: e.Name} fmt.Fprintf(&buf, "type %v int\nconst (\n", enumMappings[tk]) // then write the const definitions: // const(...) for _, a := range e.Type.EnumeratorList() { // this is a straightforwards mapping of the C defined name. The name is kept exactly the same, with a lowecase mapping // in real life, you might not want this, (for example, you may not want to export the names, which are typically in all caps), // or you might want different names enumName := string(a.DefTok.S()) goName := strings.ToLower(enumName) fmt.Fprintf(&buf, "%v %v = C.%v\n", goName, enumMappings[tk], enumName) } buf.Write([]byte(")\n")) } fmt.Println(buf.String()) }
Output: type Status int const ( success Status = C.SUCCESS failure Status = C.FAILURE )
Example (Simple) ¶
package main import ( "fmt" "strings" "github.com/gorgonia/bindgen" "modernc.org/cc" ) // GoSignature represents a Go signature type GoSignature struct { Receiver Param Name string Params []Param Ret []Param } func (sig *GoSignature) Format(f fmt.State, c rune) { f.Write([]byte("func ")) if sig.Receiver.Name != "" { fmt.Fprintf(f, "(%v %v) ", sig.Receiver.Name, sig.Receiver.Type) } fmt.Fprintf(f, "%v(", sig.Name) for i, p := range sig.Params { fmt.Fprintf(f, "%v %v", p.Name, p.Type) if i < len(sig.Params)-1 { fmt.Fprint(f, ", ") } } fmt.Fprint(f, ")") switch len(sig.Ret) { case 0: return default: fmt.Fprint(f, " (") for i, p := range sig.Ret { fmt.Fprintf(f, "%v %v", p.Name, p.Type) if i < len(sig.Ret)-1 { fmt.Fprint(f, ", ") } } fmt.Fprint(f, ")") } } // Param represents the parameters in Go type Param struct { Name, Type string } // functions say we only want functions declared func functions(t *cc.TranslationUnit) ([]bindgen.Declaration, error) { filter := func(d *cc.Declarator) bool { if !strings.HasPrefix(bindgen.NameOf(d), "func") { return false } if d.Type.Kind() != cc.Function { return false } return true } return bindgen.Get(t, filter) } func decl2GoSig(d *bindgen.CSignature) *GoSignature { var params []Param sig := new(GoSignature) outer: for _, p := range d.Parameters() { // check if its a receiver if ctxrec, ok := contextualFns[d.Name]; ok { if ctxrec.Name == p.Name() { sig.Receiver = ctxrec continue } } Type := cleanType(p.Type()) if retP, ok := retVals[d.Name]; ok { for _, r := range retP { if p.Name() == r { sig.Ret = append(sig.Ret, Param{p.Name(), Type}) continue outer } } } params = append(params, Param{p.Name(), Type}) } retType := cleanType(d.Return) if !bindgen.IsVoid(d.Return) { sig.Ret = append(sig.Ret, Param{"err", retType}) } sig.Name = d.Name sig.Params = params return sig } func cleanType(t cc.Type) string { Type := t.String() if td := bindgen.TypeDefOf(t); td != "" { Type = td } if bindgen.IsConstType(t) { Type = strings.TrimPrefix(Type, "const ") } if bindgen.IsPointer(t) { Type = strings.TrimSuffix(Type, "*") } return Type } var contextualFns = map[string]Param{ "funcCtx": Param{"ctx", "Ctx"}, } var retVals = map[string][]string{ "funcErr": []string{"retVal"}, "funcCtx": []string{"retVal"}, } func handleErr(err error) { if err != nil { panic(err) } } func main() { t, err := bindgen.Parse(bindgen.Model(), "testdata/dummy.h") handleErr(err) fns, err := functions(t) handleErr(err) for _, fn := range fns { fmt.Println(decl2GoSig(fn.(*bindgen.CSignature))) } }
Output: func func1i(a int) func func1f(a foo) func func1fp(a foo) func func2i(a int, b int) func func2f(a foo, b int) func funcErr(a int) (retVal foo, err error) func (ctx Ctx) funcCtx(a foo) (retVal foo, err error)
Index ¶
- func Explore(t *cc.TranslationUnit, filters ...FilterFunc) error
- func GenIgnored(buf io.Writer, t *cc.TranslationUnit, filters ...FilterFunc) error
- func GenNameMap(buf io.Writer, t *cc.TranslationUnit, varname string, fn func(string) string, ...) error
- func IsConstType(a cc.Type) bool
- func IsPointer(a cc.Type) bool
- func IsVoid(a cc.Type) bool
- func LongestCommonPrefix(strs ...string) string
- func Model() *cc.Model
- func NameOf(any interface{}) (name string)
- func Parse(model *cc.Model, paths ...string) (*cc.TranslationUnit, error)
- func Snake2Camel(s string, exported bool) (retVal string)
- func TypeDefOf(t cc.Type) (name string)
- type CSignature
- type Declaration
- type Enum
- type FilterFunc
- type Namer
- type Other
- type ParamKey
- type Parameter
- type Template
- type TypeKey
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Explore ¶
func Explore(t *cc.TranslationUnit, filters ...FilterFunc) error
Explore is a function used to iterate quickly on a project to translate C functions/types to Go functions/types
Example ¶
functions := func(decl *cc.Declarator) bool { if !strings.HasPrefix(NameOf(decl), "func") { return false } if decl.Type.Kind() == cc.Function { return true } return false } enums := func(decl *cc.Declarator) bool { if decl.Type.Kind() == cc.Enum { return true } return false } others := func(decl *cc.Declarator) bool { if decl.Type.Kind() == cc.Ptr || decl.Type.Kind() == cc.Struct { return true } return false } tu, err := Parse(Model(), "testdata/dummy.h") if err != nil { panic(err) } if err = Explore(tu, functions, enums, others); err != nil { panic(err) }
Output: func1i func1f func1fp func2i func2f funcErr funcCtx error fntype_t dummy_t dummy2_t
func GenIgnored ¶
func GenIgnored(buf io.Writer, t *cc.TranslationUnit, filters ...FilterFunc) error
GenIgnored generates go code for a const data structure that contains all the ignored functions/types
Filename indicates what file needs to be parsed, not the output file.
Example ¶
functions := func(decl *cc.Declarator) bool { if !strings.HasPrefix(NameOf(decl), "func") { return false } if decl.Type.Kind() == cc.Function { return true } return false } tu, err := Parse(Model(), "testdata/dummy.h") if err != nil { panic(err) } var buf bytes.Buffer if err := GenIgnored(&buf, tu, functions); err != nil { panic(err) } fmt.Println(buf.String())
Output: var ignored = map[string]struct{}{ "func1i":{}, "func1f":{}, "func1fp":{}, "func2i":{}, "func2f":{}, "funcErr":{}, "funcCtx":{}, }
func GenNameMap ¶
func GenNameMap(buf io.Writer, t *cc.TranslationUnit, varname string, fn func(string) string, filter FilterFunc, init bool) error
GenNameMap generates go code representing a name mapping scheme
filename indicates the file to be parsed, varname indicates the name of the variable.
- fn is the transformation function.
- init indicates if the mapping should be generated in a func init(){}
Example ¶
functions := func(decl *cc.Declarator) bool { if !strings.HasPrefix(NameOf(decl), "func") { return false } if decl.Type.Kind() == cc.Function { return true } return false } trans := func(a string) string { return strings.ToTitle(strings.TrimPrefix(a, "func")) } tu, err := Parse(Model(), "testdata/dummy.h") if err != nil { panic(err) } var buf bytes.Buffer if err := GenNameMap(&buf, tu, "m", trans, functions, false); err != nil { panic(err) } fmt.Println(buf.String())
Output: var m = map[string]string{ "func1i": "1I", "func1f": "1F", "func1fp": "1FP", "func2i": "2I", "func2f": "2F", "funcErr": "ERR", "funcCtx": "CTX", }
func IsConstType ¶
IsConstType returns true if the C-type is specified with a `const`
func LongestCommonPrefix ¶
LongestCommonPrefix takes a slice of strings, and finds the longest common prefix
This function was taken from github.com/chewxy/lingo/corpus
func Parse ¶
Parse parses with the given model, as well as having some hard coded predefined definitions that are useful for translating C to Go code
func Snake2Camel ¶
Snake2Camel converts snake case to camel case. It's not particularly performant. Rather it's a quick and dirty function.
Types ¶
type CSignature ¶
type CSignature struct { Pos token.Pos Name string Return cc.Type CParameters []cc.Parameter Variadic bool Declarator *cc.Declarator }
CSignature is a description of a C declaration.
func (*CSignature) Decl ¶
func (d *CSignature) Decl() *cc.Declarator
func (*CSignature) Parameters ¶
func (d *CSignature) Parameters() []Parameter
Parameters returns the declaration's CParameters converted to a []Parameter.
func (*CSignature) Position ¶
func (d *CSignature) Position() token.Position
Position returns the token position of the declaration.
type Declaration ¶
type Declaration interface { Position() token.Position Decl() *cc.Declarator }
Declaration is anything with a position
func Get ¶
func Get(t *cc.TranslationUnit, filter FilterFunc) ([]Declaration, error)
Get returns a list of declarations given the filter function
type Enum ¶
Enum is a description of a C enum
func (*Enum) Decl ¶
func (d *Enum) Decl() *cc.Declarator
type FilterFunc ¶
type FilterFunc func(*cc.Declarator) bool
FilterFunc is a function to filter types
type Other ¶
type Other struct { Pos token.Pos Name string Declarator *cc.Declarator }
Other represents other types that are not part of the "batteries included"ness of this package
func (*Other) Decl ¶
func (d *Other) Decl() *cc.Declarator
type Parameter ¶
Parameter is a C function parameter.
func (*Parameter) Elem ¶
Elem returns the pointer type of a pointer parameter or the element type of an array parameter.