CL 99316 moved generation of bindings from the the gomobile command to the gobind command. In the process, the ability to copy over documentation from the Go source to the derived Java and ObjC was lost. The relevant test didn't fail because it tests the generator itself, not gobind. Re-add support and add a gobind test for it. Fixes golang/go#25473 Change-Id: I6eee3e79173f37d3e3e65eabc0bad59e4252da64 Reviewed-on: https://go-review.googlesource.com/114056 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
185 lines
4.6 KiB
Go
185 lines
4.6 KiB
Go
// 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"
|
|
"flag"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/build"
|
|
"go/importer"
|
|
"go/parser"
|
|
"go/types"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/mobile/internal/importers"
|
|
"golang.org/x/mobile/internal/importers/java"
|
|
"golang.org/x/mobile/internal/importers/objc"
|
|
)
|
|
|
|
var (
|
|
lang = flag.String("lang", "", "target languages for bindings, either java, go, or objc. If empty, all languages are generated.")
|
|
outdir = flag.String("outdir", "", "result will be written to the directory instead of stdout.")
|
|
javaPkg = flag.String("javapkg", "", "custom Java package path prefix. Valid only with -lang=java.")
|
|
prefix = flag.String("prefix", "", "custom Objective-C name prefix. Valid only with -lang=objc.")
|
|
bootclasspath = flag.String("bootclasspath", "", "Java bootstrap classpath.")
|
|
classpath = flag.String("classpath", "", "Java classpath.")
|
|
tags = flag.String("tags", "", "build tags.")
|
|
)
|
|
|
|
var usage = `The Gobind tool generates Java language bindings for Go.
|
|
|
|
For usage details, see doc.go.`
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
run()
|
|
os.Exit(exitStatus)
|
|
}
|
|
|
|
func run() {
|
|
var langs []string
|
|
if *lang != "" {
|
|
langs = strings.Split(*lang, ",")
|
|
} else {
|
|
langs = []string{"go", "java", "objc"}
|
|
}
|
|
ctx := build.Default
|
|
if *tags != "" {
|
|
ctx.BuildTags = append(ctx.BuildTags, strings.Split(*tags, ",")...)
|
|
}
|
|
var allPkg []*build.Package
|
|
for _, path := range flag.Args() {
|
|
pkg, err := ctx.Import(path, ".", build.ImportComment)
|
|
if err != nil {
|
|
log.Fatalf("package %q: %v", path, err)
|
|
}
|
|
allPkg = append(allPkg, pkg)
|
|
}
|
|
jrefs, err := importers.AnalyzePackages(allPkg, "Java/")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
orefs, err := importers.AnalyzePackages(allPkg, "ObjC/")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
var classes []*java.Class
|
|
if len(jrefs.Refs) > 0 {
|
|
jimp := &java.Importer{
|
|
Bootclasspath: *bootclasspath,
|
|
Classpath: *classpath,
|
|
JavaPkg: *javaPkg,
|
|
}
|
|
classes, err = jimp.Import(jrefs)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
var otypes []*objc.Named
|
|
if len(orefs.Refs) > 0 {
|
|
otypes, err = objc.Import(orefs)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
// Determine GOPATH from go env GOPATH in case the default $HOME/go GOPATH
|
|
// is in effect.
|
|
if out, err := exec.Command("go", "env", "GOPATH").Output(); err != nil {
|
|
log.Fatal(err)
|
|
} else {
|
|
ctx.GOPATH = string(bytes.TrimSpace(out))
|
|
}
|
|
if len(classes) > 0 || len(otypes) > 0 {
|
|
// After generation, reverse bindings needs to be in the GOPATH
|
|
// for user packages to build.
|
|
srcDir := *outdir
|
|
if srcDir == "" {
|
|
srcDir, err = ioutil.TempDir(os.TempDir(), "gobind-")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(srcDir)
|
|
} else {
|
|
srcDir, err = filepath.Abs(srcDir)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
if ctx.GOPATH != "" {
|
|
ctx.GOPATH = string(filepath.ListSeparator) + ctx.GOPATH
|
|
}
|
|
ctx.GOPATH = srcDir + ctx.GOPATH
|
|
if len(classes) > 0 {
|
|
if err := genJavaPackages(srcDir, classes, jrefs.Embedders); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
if len(otypes) > 0 {
|
|
if err := genObjcPackages(srcDir, otypes, orefs.Embedders); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
typePkgs := make([]*types.Package, len(allPkg))
|
|
astPkgs := make([][]*ast.File, len(allPkg))
|
|
// The "source" go/importer package implicitly uses build.Default.
|
|
oldCtx := build.Default
|
|
build.Default = ctx
|
|
defer func() {
|
|
build.Default = oldCtx
|
|
}()
|
|
imp := importer.For("source", nil)
|
|
for i, pkg := range allPkg {
|
|
var err error
|
|
typePkgs[i], err = imp.Import(pkg.ImportPath)
|
|
if err != nil {
|
|
errorf("%v\n", err)
|
|
return
|
|
}
|
|
astPkgs[i], err = parse(pkg)
|
|
if err != nil {
|
|
errorf("%v\n", err)
|
|
return
|
|
}
|
|
}
|
|
for _, l := range langs {
|
|
for i, pkg := range typePkgs {
|
|
genPkg(l, pkg, astPkgs[i], typePkgs, classes, otypes)
|
|
}
|
|
// Generate the error package and support files
|
|
genPkg(l, nil, nil, typePkgs, classes, otypes)
|
|
}
|
|
}
|
|
|
|
func parse(pkg *build.Package) ([]*ast.File, error) {
|
|
fileNames := append(append([]string{}, pkg.GoFiles...), pkg.CgoFiles...)
|
|
var files []*ast.File
|
|
for _, name := range fileNames {
|
|
f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, parser.ParseComments)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
files = append(files, f)
|
|
}
|
|
return files, nil
|
|
}
|
|
|
|
var exitStatus = 0
|
|
|
|
func errorf(format string, args ...interface{}) {
|
|
fmt.Fprintf(os.Stderr, format, args...)
|
|
fmt.Fprintln(os.Stderr)
|
|
exitStatus = 1
|
|
}
|