github.com/SahandAslani/gomobile@v0.0.0-20210909130135-2cb2d44c09b2/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/types" 13 "io/ioutil" 14 "log" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "strings" 19 20 "github.com/SahandAslani/gomobile/internal/importers" 21 "github.com/SahandAslani/gomobile/internal/importers/java" 22 "github.com/SahandAslani/gomobile/internal/importers/objc" 23 "golang.org/x/tools/go/packages" 24 ) 25 26 var ( 27 lang = flag.String("lang", "", "target languages for bindings, either java, go, or objc. If empty, all languages are generated.") 28 outdir = flag.String("outdir", "", "result will be written to the directory instead of stdout.") 29 javaPkg = flag.String("javapkg", "", "custom Java package path prefix. Valid only with -lang=java.") 30 prefix = flag.String("prefix", "", "custom Objective-C name prefix. Valid only with -lang=objc.") 31 bootclasspath = flag.String("bootclasspath", "", "Java bootstrap classpath.") 32 classpath = flag.String("classpath", "", "Java classpath.") 33 tags = flag.String("tags", "", "build tags.") 34 ) 35 36 var usage = `The Gobind tool generates Java language bindings for Go. 37 38 For usage details, see doc.go.` 39 40 func main() { 41 flag.Parse() 42 43 run() 44 os.Exit(exitStatus) 45 } 46 47 func run() { 48 var langs []string 49 if *lang != "" { 50 langs = strings.Split(*lang, ",") 51 } else { 52 langs = []string{"go", "java", "objc"} 53 } 54 55 // We need to give appropriate environment variables like CC or CXX so that the returned packages no longer have errors. 56 // However, getting such environment variables is difficult or impossible so far. 57 // Gomobile can obtain such environment variables in env.go, but this logic assumes some condiitons gobind doesn't assume. 58 cfg := &packages.Config{ 59 Mode: packages.NeedName | packages.NeedFiles | 60 packages.NeedImports | packages.NeedDeps | 61 packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo, 62 BuildFlags: []string{"-tags", strings.Join(strings.Split(*tags, ","), " ")}, 63 } 64 65 // Call Load twice to warm the cache. There is a known issue that the result of Load 66 // depends on build cache state. See golang/go#33687. 67 packages.Load(cfg, flag.Args()...) 68 69 allPkg, err := packages.Load(cfg, flag.Args()...) 70 if err != nil { 71 log.Fatal(err) 72 } 73 74 jrefs, err := importers.AnalyzePackages(allPkg, "Java/") 75 if err != nil { 76 log.Fatal(err) 77 } 78 orefs, err := importers.AnalyzePackages(allPkg, "ObjC/") 79 if err != nil { 80 log.Fatal(err) 81 } 82 var classes []*java.Class 83 if len(jrefs.Refs) > 0 { 84 jimp := &java.Importer{ 85 Bootclasspath: *bootclasspath, 86 Classpath: *classpath, 87 JavaPkg: *javaPkg, 88 } 89 classes, err = jimp.Import(jrefs) 90 if err != nil { 91 log.Fatal(err) 92 } 93 } 94 var otypes []*objc.Named 95 if len(orefs.Refs) > 0 { 96 otypes, err = objc.Import(orefs) 97 if err != nil { 98 log.Fatal(err) 99 } 100 } 101 102 if len(classes) > 0 || len(otypes) > 0 { 103 srcDir := *outdir 104 if srcDir == "" { 105 srcDir, err = ioutil.TempDir(os.TempDir(), "gobind-") 106 if err != nil { 107 log.Fatal(err) 108 } 109 defer os.RemoveAll(srcDir) 110 } else { 111 srcDir, err = filepath.Abs(srcDir) 112 if err != nil { 113 log.Fatal(err) 114 } 115 } 116 if len(classes) > 0 { 117 if err := genJavaPackages(srcDir, classes, jrefs.Embedders); err != nil { 118 log.Fatal(err) 119 } 120 } 121 if len(otypes) > 0 { 122 if err := genObjcPackages(srcDir, otypes, orefs.Embedders); err != nil { 123 log.Fatal(err) 124 } 125 } 126 127 // Add a new directory to GOPATH where the file for reverse bindings exist, and recreate allPkg. 128 // It is because the current allPkg did not solve imports for reverse bindings. 129 var gopath string 130 if out, err := exec.Command("go", "env", "GOPATH").Output(); err != nil { 131 log.Fatal(err) 132 } else { 133 gopath = string(bytes.TrimSpace(out)) 134 } 135 if gopath != "" { 136 gopath = string(filepath.ListSeparator) + gopath 137 } 138 gopath = srcDir + gopath 139 cfg.Env = append(os.Environ(), "GOPATH="+gopath) 140 allPkg, err = packages.Load(cfg, flag.Args()...) 141 if err != nil { 142 log.Fatal(err) 143 } 144 } 145 146 typePkgs := make([]*types.Package, len(allPkg)) 147 astPkgs := make([][]*ast.File, len(allPkg)) 148 for i, pkg := range allPkg { 149 // Ignore pkg.Errors. pkg.Errors can exist when Cgo is used, but this should not affect the result. 150 // See the discussion at golang/go#36547. 151 typePkgs[i] = pkg.Types 152 astPkgs[i] = pkg.Syntax 153 } 154 for _, l := range langs { 155 for i, pkg := range typePkgs { 156 genPkg(l, pkg, astPkgs[i], typePkgs, classes, otypes) 157 } 158 // Generate the error package and support files 159 genPkg(l, nil, nil, typePkgs, classes, otypes) 160 } 161 } 162 163 var exitStatus = 0 164 165 func errorf(format string, args ...interface{}) { 166 fmt.Fprintf(os.Stderr, format, args...) 167 fmt.Fprintln(os.Stderr) 168 exitStatus = 1 169 }