| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- // Copyright 2014 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package main
- import (
- "bytes"
- "fmt"
- "go/ast"
- "go/token"
- "go/types"
- "io"
- "os"
- "path/filepath"
- "strings"
- "unicode"
- "unicode/utf8"
- "golang.org/x/mobile/bind"
- "golang.org/x/mobile/internal/importers"
- "golang.org/x/mobile/internal/importers/java"
- "golang.org/x/mobile/internal/importers/objc"
- "golang.org/x/tools/go/packages"
- )
- func genPkg(lang string, p *types.Package, astFiles []*ast.File, allPkg []*types.Package, classes []*java.Class, otypes []*objc.Named) {
- fname := defaultFileName(lang, p)
- conf := &bind.GeneratorConfig{
- Fset: fset,
- Pkg: p,
- AllPkg: allPkg,
- }
- var pname string
- if p != nil {
- pname = p.Name()
- } else {
- pname = "universe"
- }
- var buf bytes.Buffer
- generator := &bind.Generator{
- Printer: &bind.Printer{Buf: &buf, IndentEach: []byte("\t")},
- Fset: conf.Fset,
- AllPkg: conf.AllPkg,
- Pkg: conf.Pkg,
- Files: astFiles,
- }
- switch lang {
- case "java":
- g := &bind.JavaGen{
- JavaPkg: *javaPkg,
- Generator: generator,
- }
- g.Init(classes)
- pkgname := bind.JavaPkgName(*javaPkg, p)
- pkgDir := strings.Replace(pkgname, ".", "/", -1)
- buf.Reset()
- w, closer := writer(filepath.Join("java", pkgDir, fname))
- processErr(g.GenJava())
- io.Copy(w, &buf)
- closer()
- for i, name := range g.ClassNames() {
- buf.Reset()
- w, closer := writer(filepath.Join("java", pkgDir, name+".java"))
- processErr(g.GenClass(i))
- io.Copy(w, &buf)
- closer()
- }
- buf.Reset()
- w, closer = writer(filepath.Join("src", "gobind", pname+"_android.c"))
- processErr(g.GenC())
- io.Copy(w, &buf)
- closer()
- buf.Reset()
- w, closer = writer(filepath.Join("src", "gobind", pname+"_android.h"))
- processErr(g.GenH())
- io.Copy(w, &buf)
- closer()
- // Generate support files along with the universe package
- if p == nil {
- dir, err := packageDir("golang.org/x/mobile/bind")
- if err != nil {
- errorf(`"golang.org/x/mobile/bind" is not found; run go get golang.org/x/mobile/bind: %v`, err)
- return
- }
- repo := filepath.Clean(filepath.Join(dir, "..")) // golang.org/x/mobile directory.
- for _, javaFile := range []string{"Seq.java"} {
- src := filepath.Join(repo, "bind/java/"+javaFile)
- in, err := os.Open(src)
- if err != nil {
- errorf("failed to open Java support file: %v", err)
- }
- defer in.Close()
- w, closer := writer(filepath.Join("java", "go", javaFile))
- defer closer()
- if _, err := io.Copy(w, in); err != nil {
- errorf("failed to copy Java support file: %v", err)
- return
- }
- }
- // Copy support files
- if err != nil {
- errorf("unable to import bind/java: %v", err)
- return
- }
- javaDir, err := packageDir("golang.org/x/mobile/bind/java")
- if err != nil {
- errorf("unable to import bind/java: %v", err)
- return
- }
- copyFile(filepath.Join("src", "gobind", "seq_android.c"), filepath.Join(javaDir, "seq_android.c.support"))
- copyFile(filepath.Join("src", "gobind", "seq_android.go"), filepath.Join(javaDir, "seq_android.go.support"))
- copyFile(filepath.Join("src", "gobind", "seq_android.h"), filepath.Join(javaDir, "seq_android.h"))
- }
- case "go":
- w, closer := writer(filepath.Join("src", "gobind", fname))
- conf.Writer = w
- processErr(bind.GenGo(conf))
- closer()
- w, closer = writer(filepath.Join("src", "gobind", pname+".h"))
- genPkgH(w, pname)
- io.Copy(w, &buf)
- closer()
- w, closer = writer(filepath.Join("src", "gobind", "seq.h"))
- genPkgH(w, "seq")
- io.Copy(w, &buf)
- closer()
- dir, err := packageDir("golang.org/x/mobile/bind")
- if err != nil {
- errorf("unable to import bind: %v", err)
- return
- }
- copyFile(filepath.Join("src", "gobind", "seq.go"), filepath.Join(dir, "seq.go.support"))
- case "objc":
- g := &bind.ObjcGen{
- Generator: generator,
- Prefix: *prefix,
- }
- g.Init(otypes)
- w, closer := writer(filepath.Join("src", "gobind", pname+"_darwin.h"))
- processErr(g.GenGoH())
- io.Copy(w, &buf)
- closer()
- hname := strings.Title(fname[:len(fname)-2]) + ".objc.h"
- w, closer = writer(filepath.Join("src", "gobind", hname))
- processErr(g.GenH())
- io.Copy(w, &buf)
- closer()
- mname := strings.Title(fname[:len(fname)-2]) + "_darwin.m"
- w, closer = writer(filepath.Join("src", "gobind", mname))
- conf.Writer = w
- processErr(g.GenM())
- io.Copy(w, &buf)
- closer()
- if p == nil {
- // Copy support files
- dir, err := packageDir("golang.org/x/mobile/bind/objc")
- if err != nil {
- errorf("unable to import bind/objc: %v", err)
- return
- }
- copyFile(filepath.Join("src", "gobind", "seq_darwin.m"), filepath.Join(dir, "seq_darwin.m.support"))
- copyFile(filepath.Join("src", "gobind", "seq_darwin.go"), filepath.Join(dir, "seq_darwin.go.support"))
- copyFile(filepath.Join("src", "gobind", "ref.h"), filepath.Join(dir, "ref.h"))
- copyFile(filepath.Join("src", "gobind", "seq_darwin.h"), filepath.Join(dir, "seq_darwin.h"))
- }
- default:
- errorf("unknown target language: %q", lang)
- }
- }
- func genPkgH(w io.Writer, pname string) {
- fmt.Fprintf(w, `// Code generated by gobind. DO NOT EDIT.
- #ifdef __GOBIND_ANDROID__
- #include "%[1]s_android.h"
- #endif
- #ifdef __GOBIND_DARWIN__
- #include "%[1]s_darwin.h"
- #endif`, pname)
- }
- func genObjcPackages(dir string, types []*objc.Named, embedders []importers.Struct) error {
- var buf bytes.Buffer
- cg := &bind.ObjcWrapper{
- Printer: &bind.Printer{
- IndentEach: []byte("\t"),
- Buf: &buf,
- },
- }
- var genNames []string
- for _, emb := range embedders {
- genNames = append(genNames, emb.Name)
- }
- cg.Init(types, genNames)
- for i, opkg := range cg.Packages() {
- pkgDir := filepath.Join(dir, "src", "ObjC", opkg)
- if err := os.MkdirAll(pkgDir, 0700); err != nil {
- return err
- }
- pkgFile := filepath.Join(pkgDir, "package.go")
- buf.Reset()
- cg.GenPackage(i)
- if err := os.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil {
- return err
- }
- }
- buf.Reset()
- cg.GenInterfaces()
- objcBase := filepath.Join(dir, "src", "ObjC")
- if err := os.MkdirAll(objcBase, 0700); err != nil {
- return err
- }
- if err := os.WriteFile(filepath.Join(objcBase, "interfaces.go"), buf.Bytes(), 0600); err != nil {
- return err
- }
- goBase := filepath.Join(dir, "src", "gobind")
- if err := os.MkdirAll(goBase, 0700); err != nil {
- return err
- }
- buf.Reset()
- cg.GenGo()
- if err := os.WriteFile(filepath.Join(goBase, "interfaces_darwin.go"), buf.Bytes(), 0600); err != nil {
- return err
- }
- buf.Reset()
- cg.GenH()
- if err := os.WriteFile(filepath.Join(goBase, "interfaces.h"), buf.Bytes(), 0600); err != nil {
- return err
- }
- buf.Reset()
- cg.GenM()
- if err := os.WriteFile(filepath.Join(goBase, "interfaces_darwin.m"), buf.Bytes(), 0600); err != nil {
- return err
- }
- return nil
- }
- func genJavaPackages(dir string, classes []*java.Class, embedders []importers.Struct) error {
- var buf bytes.Buffer
- cg := &bind.ClassGen{
- JavaPkg: *javaPkg,
- Printer: &bind.Printer{
- IndentEach: []byte("\t"),
- Buf: &buf,
- },
- }
- cg.Init(classes, embedders)
- for i, jpkg := range cg.Packages() {
- pkgDir := filepath.Join(dir, "src", "Java", jpkg)
- if err := os.MkdirAll(pkgDir, 0700); err != nil {
- return err
- }
- pkgFile := filepath.Join(pkgDir, "package.go")
- buf.Reset()
- cg.GenPackage(i)
- if err := os.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil {
- return err
- }
- }
- buf.Reset()
- cg.GenInterfaces()
- javaBase := filepath.Join(dir, "src", "Java")
- if err := os.MkdirAll(javaBase, 0700); err != nil {
- return err
- }
- if err := os.WriteFile(filepath.Join(javaBase, "interfaces.go"), buf.Bytes(), 0600); err != nil {
- return err
- }
- goBase := filepath.Join(dir, "src", "gobind")
- if err := os.MkdirAll(goBase, 0700); err != nil {
- return err
- }
- buf.Reset()
- cg.GenGo()
- if err := os.WriteFile(filepath.Join(goBase, "classes_android.go"), buf.Bytes(), 0600); err != nil {
- return err
- }
- buf.Reset()
- cg.GenH()
- if err := os.WriteFile(filepath.Join(goBase, "classes.h"), buf.Bytes(), 0600); err != nil {
- return err
- }
- buf.Reset()
- cg.GenC()
- if err := os.WriteFile(filepath.Join(goBase, "classes_android.c"), buf.Bytes(), 0600); err != nil {
- return err
- }
- return nil
- }
- func processErr(err error) {
- if err != nil {
- if list, _ := err.(bind.ErrorList); len(list) > 0 {
- for _, err := range list {
- errorf("%v", err)
- }
- } else {
- errorf("%v", err)
- }
- }
- }
- var fset = token.NewFileSet()
- func writer(fname string) (w io.Writer, closer func()) {
- if *outdir == "" {
- return os.Stdout, func() { return }
- }
- name := filepath.Join(*outdir, fname)
- dir := filepath.Dir(name)
- if err := os.MkdirAll(dir, 0755); err != nil {
- errorf("invalid output dir: %v", err)
- os.Exit(exitStatus)
- }
- f, err := os.Create(name)
- if err != nil {
- errorf("invalid output dir: %v", err)
- os.Exit(exitStatus)
- }
- closer = func() {
- if err := f.Close(); err != nil {
- errorf("error in closing output file: %v", err)
- }
- }
- return f, closer
- }
- func copyFile(dst, src string) {
- w, closer := writer(dst)
- f, err := os.Open(src)
- if err != nil {
- errorf("unable to open file: %v", err)
- closer()
- os.Exit(exitStatus)
- }
- if _, err := io.Copy(w, f); err != nil {
- errorf("unable to copy file: %v", err)
- f.Close()
- closer()
- os.Exit(exitStatus)
- }
- f.Close()
- closer()
- }
- func defaultFileName(lang string, pkg *types.Package) string {
- switch lang {
- case "java":
- if pkg == nil {
- return "Universe.java"
- }
- firstRune, size := utf8.DecodeRuneInString(pkg.Name())
- className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:]
- return className + ".java"
- case "go":
- if pkg == nil {
- return "go_main.go"
- }
- return "go_" + pkg.Name() + "main.go"
- case "objc":
- if pkg == nil {
- return "Universe.m"
- }
- firstRune, size := utf8.DecodeRuneInString(pkg.Name())
- className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:]
- return *prefix + className + ".m"
- }
- errorf("unknown target language: %q", lang)
- os.Exit(exitStatus)
- return ""
- }
- func packageDir(path string) (string, error) {
- mode := packages.NeedFiles
- pkgs, err := packages.Load(&packages.Config{Mode: mode}, path)
- if err != nil {
- return "", err
- }
- if len(pkgs) == 0 || len(pkgs[0].GoFiles) == 0 {
- return "", fmt.Errorf("no Go package in %v", path)
- }
- pkg := pkgs[0]
- if len(pkg.Errors) > 0 {
- return "", fmt.Errorf("%v", pkg.Errors)
- }
- return filepath.Dir(pkg.GoFiles[0]), nil
- }
|