github.com/champo/mobile@v0.0.0-20190107162257-dc0771356504/cmd/gobind/main.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "go/ast" 12 "go/build" 13 "go/importer" 14 "go/parser" 15 "go/types" 16 "io/ioutil" 17 "log" 18 "os" 19 "os/exec" 20 "path/filepath" 21 "strings" 22 23 "golang.org/x/mobile/internal/importers" 24 "golang.org/x/mobile/internal/importers/java" 25 "golang.org/x/mobile/internal/importers/objc" 26 ) 27 28 var ( 29 lang = flag.String("lang", "", "target languages for bindings, either java, go, or objc. If empty, all languages are generated.") 30 outdir = flag.String("outdir", "", "result will be written to the directory instead of stdout.") 31 javaPkg = flag.String("javapkg", "", "custom Java package path prefix. Valid only with -lang=java.") 32 prefix = flag.String("prefix", "", "custom Objective-C name prefix. Valid only with -lang=objc.") 33 bootclasspath = flag.String("bootclasspath", "", "Java bootstrap classpath.") 34 classpath = flag.String("classpath", "", "Java classpath.") 35 tags = flag.String("tags", "", "build tags.") 36 ) 37 38 var usage = `The Gobind tool generates Java language bindings for Go. 39 40 For usage details, see doc.go.` 41 42 func main() { 43 flag.Parse() 44 45 run() 46 os.Exit(exitStatus) 47 } 48 49 func run() { 50 var langs []string 51 if *lang != "" { 52 langs = strings.Split(*lang, ",") 53 } else { 54 langs = []string{"go", "java", "objc"} 55 } 56 ctx := build.Default 57 if *tags != "" { 58 ctx.BuildTags = append(ctx.BuildTags, strings.Split(*tags, ",")...) 59 } 60 var allPkg []*build.Package 61 for _, path := range flag.Args() { 62 pkg, err := ctx.Import(path, ".", build.ImportComment) 63 if err != nil { 64 log.Fatalf("package %q: %v", path, err) 65 } 66 allPkg = append(allPkg, pkg) 67 } 68 jrefs, err := importers.AnalyzePackages(allPkg, "Java/") 69 if err != nil { 70 log.Fatal(err) 71 } 72 orefs, err := importers.AnalyzePackages(allPkg, "ObjC/") 73 if err != nil { 74 log.Fatal(err) 75 } 76 var classes []*java.Class 77 if len(jrefs.Refs) > 0 { 78 jimp := &java.Importer{ 79 Bootclasspath: *bootclasspath, 80 Classpath: *classpath, 81 JavaPkg: *javaPkg, 82 } 83 classes, err = jimp.Import(jrefs) 84 if err != nil { 85 log.Fatal(err) 86 } 87 } 88 var otypes []*objc.Named 89 if len(orefs.Refs) > 0 { 90 otypes, err = objc.Import(orefs) 91 if err != nil { 92 log.Fatal(err) 93 } 94 } 95 // Determine GOPATH from go env GOPATH in case the default $HOME/go GOPATH 96 // is in effect. 97 if out, err := exec.Command("go", "env", "GOPATH").Output(); err != nil { 98 log.Fatal(err) 99 } else { 100 ctx.GOPATH = string(bytes.TrimSpace(out)) 101 } 102 if len(classes) > 0 || len(otypes) > 0 { 103 // After generation, reverse bindings needs to be in the GOPATH 104 // for user packages to build. 105 srcDir := *outdir 106 if srcDir == "" { 107 srcDir, err = ioutil.TempDir(os.TempDir(), "gobind-") 108 if err != nil { 109 log.Fatal(err) 110 } 111 defer os.RemoveAll(srcDir) 112 } else { 113 srcDir, err = filepath.Abs(srcDir) 114 if err != nil { 115 log.Fatal(err) 116 } 117 } 118 if ctx.GOPATH != "" { 119 ctx.GOPATH = string(filepath.ListSeparator) + ctx.GOPATH 120 } 121 ctx.GOPATH = srcDir + ctx.GOPATH 122 if len(classes) > 0 { 123 if err := genJavaPackages(srcDir, classes, jrefs.Embedders); err != nil { 124 log.Fatal(err) 125 } 126 } 127 if len(otypes) > 0 { 128 if err := genObjcPackages(srcDir, otypes, orefs.Embedders); err != nil { 129 log.Fatal(err) 130 } 131 } 132 } 133 134 typePkgs := make([]*types.Package, len(allPkg)) 135 astPkgs := make([][]*ast.File, len(allPkg)) 136 // The "source" go/importer package implicitly uses build.Default. 137 oldCtx := build.Default 138 build.Default = ctx 139 defer func() { 140 build.Default = oldCtx 141 }() 142 imp := importer.For("source", nil) 143 for i, pkg := range allPkg { 144 var err error 145 typePkgs[i], err = imp.Import(pkg.ImportPath) 146 if err != nil { 147 errorf("%v\n", err) 148 return 149 } 150 astPkgs[i], err = parse(pkg) 151 if err != nil { 152 errorf("%v\n", err) 153 return 154 } 155 } 156 for _, l := range langs { 157 for i, pkg := range typePkgs { 158 genPkg(l, pkg, astPkgs[i], typePkgs, classes, otypes) 159 } 160 // Generate the error package and support files 161 genPkg(l, nil, nil, typePkgs, classes, otypes) 162 } 163 } 164 165 func parse(pkg *build.Package) ([]*ast.File, error) { 166 fileNames := append(append([]string{}, pkg.GoFiles...), pkg.CgoFiles...) 167 var files []*ast.File 168 for _, name := range fileNames { 169 f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, parser.ParseComments) 170 if err != nil { 171 return nil, err 172 } 173 files = append(files, f) 174 } 175 return files, nil 176 } 177 178 var exitStatus = 0 179 180 func errorf(format string, args ...interface{}) { 181 fmt.Fprintf(os.Stderr, format, args...) 182 fmt.Fprintln(os.Stderr) 183 exitStatus = 1 184 }