main.go 4.6 KB

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