mirror of
https://github.com/go-i2p/gomobile-java.git
synced 2025-07-13 03:53:12 -04:00
bind: support for custom java package name and objective-c prefix.
Introduce options -javapkg and -prefix for gobind command. The following generates java class Testpkg with package name com.example. gobind -lang=java -javapkg=com.example testpkg The following generates objective-c files where function and type names are prefixed with ExampleTestpkg. gobind -lang=objc -prefix=Example testpkg As discussed in golang/go#9660 and golang/go#12245. Gomobile support is not yet implemented. Change-Id: Ib9e39997ce915580a5a2e25643c0c28373f27ee1 Reviewed-on: https://go-review.googlesource.com/13969 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:

committed by
Hyang-Ah Hana Kim

parent
4628c38e0f
commit
c384607ef3
13
bind/bind.go
13
bind/bind.go
@ -21,12 +21,16 @@ import (
|
||||
)
|
||||
|
||||
// GenJava generates a Java API from a Go package.
|
||||
func GenJava(w io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||
func GenJava(w io.Writer, fset *token.FileSet, pkg *types.Package, javaPkg string) error {
|
||||
if javaPkg == "" {
|
||||
javaPkg = javaPkgName(pkg.Name())
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
g := &javaGen{
|
||||
printer: &printer{buf: buf, indentEach: []byte(" ")},
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
javaPkg: javaPkg,
|
||||
}
|
||||
if err := g.gen(); err != nil {
|
||||
return err
|
||||
@ -57,12 +61,17 @@ func GenGo(w io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||
}
|
||||
|
||||
// GenObjc generates the Objective-C API from a Go package.
|
||||
func GenObjc(w io.Writer, fset *token.FileSet, pkg *types.Package, isHeader bool) error {
|
||||
func GenObjc(w io.Writer, fset *token.FileSet, pkg *types.Package, prefix string, isHeader bool) error {
|
||||
if prefix == "" {
|
||||
prefix = "Go"
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
g := &objcGen{
|
||||
printer: &printer{buf: buf, indentEach: []byte("\t")},
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
prefix: prefix,
|
||||
}
|
||||
var err error
|
||||
if isHeader {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@ -96,7 +97,7 @@ func TestGenObjc(t *testing.T) {
|
||||
|
||||
for isHeader, suffix := range suffixes {
|
||||
var buf bytes.Buffer
|
||||
if err := GenObjc(&buf, fset, pkg, isHeader); err != nil {
|
||||
if err := GenObjc(&buf, fset, pkg, "", isHeader); err != nil {
|
||||
t.Errorf("%s: %v", filename, err)
|
||||
continue
|
||||
}
|
||||
@ -121,7 +122,7 @@ func TestGenJava(t *testing.T) {
|
||||
for _, filename := range tests {
|
||||
var buf bytes.Buffer
|
||||
pkg := typeCheck(t, filename)
|
||||
if err := GenJava(&buf, fset, pkg); err != nil {
|
||||
if err := GenJava(&buf, fset, pkg, ""); err != nil {
|
||||
t.Errorf("%s: %v", filename, err)
|
||||
continue
|
||||
}
|
||||
@ -165,3 +166,47 @@ func TestGenGo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomPrefix(t *testing.T) {
|
||||
const datafile = "testdata/customprefix.go"
|
||||
const isHeader = true
|
||||
pkg := typeCheck(t, datafile)
|
||||
|
||||
testCases := []struct {
|
||||
golden string
|
||||
gen func(w io.Writer) error
|
||||
}{
|
||||
{
|
||||
"testdata/customprefix.java.golden",
|
||||
func(w io.Writer) error { return GenJava(w, fset, pkg, "com.example") },
|
||||
},
|
||||
{
|
||||
"testdata/customprefix.objc.h.golden",
|
||||
func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", isHeader) },
|
||||
},
|
||||
{
|
||||
"testdata/customprefix.objc.m.golden",
|
||||
func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", !isHeader) },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
var buf bytes.Buffer
|
||||
if err := tc.gen(&buf); err != nil {
|
||||
t.Errorf("generating %s: %v", tc.golden, err)
|
||||
continue
|
||||
}
|
||||
out := writeTempFile(t, "generated", buf.Bytes())
|
||||
defer os.Remove(out)
|
||||
if diffstr := diff(tc.golden, out); diffstr != "" {
|
||||
t.Errorf("%s: generated file does not match:\b%s", tc.golden, diffstr)
|
||||
if *updateFlag {
|
||||
t.Logf("Updating %s...", tc.golden)
|
||||
err := exec.Command("/bin/cp", out, tc.golden).Run()
|
||||
if err != nil {
|
||||
t.Errorf("Update failed: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,10 @@ func (list ErrorList) Error() string {
|
||||
|
||||
type javaGen struct {
|
||||
*printer
|
||||
fset *token.FileSet
|
||||
pkg *types.Package
|
||||
err ErrorList
|
||||
fset *token.FileSet
|
||||
pkg *types.Package
|
||||
javaPkg string
|
||||
err ErrorList
|
||||
}
|
||||
|
||||
func (g *javaGen) genStruct(obj *types.TypeName, T *types.Struct) {
|
||||
@ -545,11 +546,19 @@ func (g *javaGen) errorf(format string, args ...interface{}) {
|
||||
g.err = append(g.err, fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
const javaPreamble = `// Java Package %s is a proxy for talking to a Go program.
|
||||
// gobind -lang=java %s
|
||||
func (g *javaGen) gobindOpts() string {
|
||||
opts := []string{"-lang=java"}
|
||||
if g.javaPkg != javaPkgName(g.pkg.Name()) {
|
||||
opts = append(opts, "-javapkg="+g.javaPkg)
|
||||
}
|
||||
return strings.Join(opts, " ")
|
||||
}
|
||||
|
||||
const javaPreamble = `// Java class %[1]s.%[2]s is a proxy for talking to a Go program.
|
||||
// gobind %[3]s %[4]s
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go.%s;
|
||||
package %[1]s;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
@ -560,8 +569,8 @@ var javaNameReplacer = strings.NewReplacer(
|
||||
".", "_",
|
||||
)
|
||||
|
||||
func (g *javaGen) javaPkgName() string {
|
||||
s := javaNameReplacer.Replace(g.pkg.Name())
|
||||
func javaPkgName(pkgName string) string {
|
||||
s := javaNameReplacer.Replace(pkgName)
|
||||
// Look for Java keywords that are not Go keywords, and avoid using
|
||||
// them as a package name.
|
||||
//
|
||||
@ -579,7 +588,7 @@ func (g *javaGen) javaPkgName() string {
|
||||
"void", "volatile", "while":
|
||||
s += "_"
|
||||
}
|
||||
return s
|
||||
return "go." + s
|
||||
}
|
||||
|
||||
func (g *javaGen) className() string {
|
||||
@ -587,7 +596,7 @@ func (g *javaGen) className() string {
|
||||
}
|
||||
|
||||
func (g *javaGen) gen() error {
|
||||
g.Printf(javaPreamble, g.javaPkgName(), g.pkg.Path(), g.javaPkgName())
|
||||
g.Printf(javaPreamble, g.javaPkg, g.className(), g.gobindOpts(), g.pkg.Path())
|
||||
|
||||
g.Printf("public abstract class %s {\n", g.className())
|
||||
g.Indent()
|
||||
|
@ -9,8 +9,6 @@ import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// TODO(hyangah): error code/domain propagation
|
||||
@ -21,6 +19,8 @@ type objcGen struct {
|
||||
pkg *types.Package
|
||||
err ErrorList
|
||||
|
||||
prefix string // prefix arg passed by flag.
|
||||
|
||||
// fields set by init.
|
||||
pkgName string
|
||||
namePrefix string
|
||||
@ -28,14 +28,9 @@ type objcGen struct {
|
||||
names []*types.TypeName
|
||||
}
|
||||
|
||||
func capitalize(n string) string {
|
||||
firstRune, size := utf8.DecodeRuneInString(n)
|
||||
return string(unicode.ToUpper(firstRune)) + n[size:]
|
||||
}
|
||||
|
||||
func (g *objcGen) init() {
|
||||
g.pkgName = g.pkg.Name()
|
||||
g.namePrefix = "Go" + capitalize(g.pkgName)
|
||||
g.namePrefix = g.prefix + strings.Title(g.pkgName)
|
||||
g.funcs = nil
|
||||
g.names = nil
|
||||
|
||||
@ -57,8 +52,8 @@ func (g *objcGen) init() {
|
||||
}
|
||||
}
|
||||
|
||||
const objcPreamble = `// Objective-C API for talking to %s Go package.
|
||||
// gobind -lang=objc %s
|
||||
const objcPreamble = `// Objective-C API for talking to %[1]s Go package.
|
||||
// gobind %[2]s %[3]s
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
@ -67,9 +62,9 @@ const objcPreamble = `// Objective-C API for talking to %s Go package.
|
||||
func (g *objcGen) genH() error {
|
||||
g.init()
|
||||
|
||||
g.Printf(objcPreamble, g.pkg.Path(), g.pkg.Path())
|
||||
g.Printf("#ifndef __Go%s_H__\n", capitalize(g.pkgName))
|
||||
g.Printf("#define __Go%s_H__\n", capitalize(g.pkgName))
|
||||
g.Printf(objcPreamble, g.pkg.Path(), g.gobindOpts(), g.pkg.Path())
|
||||
g.Printf("#ifndef __Go%s_H__\n", strings.Title(g.pkgName))
|
||||
g.Printf("#define __Go%s_H__\n", strings.Title(g.pkgName))
|
||||
g.Printf("\n")
|
||||
g.Printf("#include <Foundation/Foundation.h>")
|
||||
g.Printf("\n\n")
|
||||
@ -115,10 +110,18 @@ func (g *objcGen) genH() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *objcGen) gobindOpts() string {
|
||||
opts := []string{"-lang=objc"}
|
||||
if g.prefix != "Go" {
|
||||
opts = append(opts, "-prefix="+g.prefix)
|
||||
}
|
||||
return strings.Join(opts, " ")
|
||||
}
|
||||
|
||||
func (g *objcGen) genM() error {
|
||||
g.init()
|
||||
|
||||
g.Printf(objcPreamble, g.pkg.Path(), g.pkg.Path())
|
||||
g.Printf(objcPreamble, g.pkg.Path(), g.gobindOpts(), g.pkg.Path())
|
||||
g.Printf("#include %q\n", g.namePrefix+".h")
|
||||
g.Printf("#include <Foundation/Foundation.h>\n")
|
||||
g.Printf("#include \"seq.h\"\n")
|
||||
|
2
bind/testdata/basictypes.java.golden
vendored
2
bind/testdata/basictypes.java.golden
vendored
@ -1,4 +1,4 @@
|
||||
// Java Package basictypes is a proxy for talking to a Go program.
|
||||
// Java class go.basictypes.Basictypes is a proxy for talking to a Go program.
|
||||
// gobind -lang=java basictypes
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
10
bind/testdata/customprefix.go
vendored
Normal file
10
bind/testdata/customprefix.go
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Data for -pkgpath and -prefix options.
|
||||
|
||||
package customprefix
|
||||
|
||||
func F() {
|
||||
}
|
20
bind/testdata/customprefix.java.golden
vendored
Normal file
20
bind/testdata/customprefix.java.golden
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Java class com.example.Customprefix is a proxy for talking to a Go program.
|
||||
// gobind -lang=java -javapkg=com.example customprefix
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package com.example;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
public abstract class Customprefix {
|
||||
private Customprefix() {} // uninstantiable
|
||||
|
||||
public static void F() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
Seq.send(DESCRIPTOR, CALL_F, _in, _out);
|
||||
}
|
||||
|
||||
private static final int CALL_F = 1;
|
||||
private static final String DESCRIPTOR = "customprefix";
|
||||
}
|
13
bind/testdata/customprefix.objc.h.golden
vendored
Normal file
13
bind/testdata/customprefix.objc.h.golden
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Objective-C API for talking to customprefix Go package.
|
||||
// gobind -lang=objc -prefix=EX customprefix
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
#ifndef __GoCustomprefix_H__
|
||||
#define __GoCustomprefix_H__
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
FOUNDATION_EXPORT void EXCustomprefixF();
|
||||
|
||||
#endif
|
27
bind/testdata/customprefix.objc.m.golden
vendored
Normal file
27
bind/testdata/customprefix.objc.m.golden
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Objective-C API for talking to customprefix Go package.
|
||||
// gobind -lang=objc -prefix=EX customprefix
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
#include "EXCustomprefix.h"
|
||||
#include <Foundation/Foundation.h>
|
||||
#include "seq.h"
|
||||
|
||||
static NSString* errDomain = @"go.customprefix";
|
||||
|
||||
@protocol goSeqRefInterface
|
||||
-(GoSeqRef*) ref;
|
||||
@end
|
||||
|
||||
#define _DESCRIPTOR_ "customprefix"
|
||||
|
||||
#define _CALL_F_ 1
|
||||
|
||||
void EXCustomprefixF() {
|
||||
GoSeq in_ = {};
|
||||
GoSeq out_ = {};
|
||||
go_seq_send(_DESCRIPTOR_, _CALL_F_, &in_, &out_);
|
||||
go_seq_free(&in_);
|
||||
go_seq_free(&out_);
|
||||
}
|
||||
|
2
bind/testdata/interfaces.java.golden
vendored
2
bind/testdata/interfaces.java.golden
vendored
@ -1,4 +1,4 @@
|
||||
// Java Package interfaces is a proxy for talking to a Go program.
|
||||
// Java class go.interfaces.Interfaces is a proxy for talking to a Go program.
|
||||
// gobind -lang=java interfaces
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
2
bind/testdata/issue10788.java.golden
vendored
2
bind/testdata/issue10788.java.golden
vendored
@ -1,4 +1,4 @@
|
||||
// Java Package issue10788 is a proxy for talking to a Go program.
|
||||
// Java class go.issue10788.Issue10788 is a proxy for talking to a Go program.
|
||||
// gobind -lang=java issue10788
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
2
bind/testdata/issue12328.java.golden
vendored
2
bind/testdata/issue12328.java.golden
vendored
@ -1,4 +1,4 @@
|
||||
// Java Package issue12328 is a proxy for talking to a Go program.
|
||||
// Java class go.issue12328.Issue12328 is a proxy for talking to a Go program.
|
||||
// gobind -lang=java issue12328
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
2
bind/testdata/structs.java.golden
vendored
2
bind/testdata/structs.java.golden
vendored
@ -1,4 +1,4 @@
|
||||
// Java Package structs is a proxy for talking to a Go program.
|
||||
// Java class go.structs.Structs is a proxy for talking to a Go program.
|
||||
// gobind -lang=java structs
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
2
bind/testdata/try.java.golden
vendored
2
bind/testdata/try.java.golden
vendored
@ -1,4 +1,4 @@
|
||||
// Java Package try_ is a proxy for talking to a Go program.
|
||||
// Java class go.try_.Try is a proxy for talking to a Go program.
|
||||
// gobind -lang=java try
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
@ -53,7 +53,7 @@ func genPkg(pkg *build.Package) {
|
||||
switch *lang {
|
||||
case "java":
|
||||
w, closer := writer(fname, p)
|
||||
processErr(bind.GenJava(w, fset, p))
|
||||
processErr(bind.GenJava(w, fset, p, *javaPkg))
|
||||
closer()
|
||||
case "go":
|
||||
w, closer := writer(fname, p)
|
||||
@ -61,15 +61,15 @@ func genPkg(pkg *build.Package) {
|
||||
closer()
|
||||
case "objc":
|
||||
if fname == "" {
|
||||
processErr(bind.GenObjc(os.Stdout, fset, p, true))
|
||||
processErr(bind.GenObjc(os.Stdout, fset, p, false))
|
||||
processErr(bind.GenObjc(os.Stdout, fset, p, *prefix, true))
|
||||
processErr(bind.GenObjc(os.Stdout, fset, p, *prefix, false))
|
||||
} else {
|
||||
hname := fname[:len(fname)-2] + ".h"
|
||||
w, closer := writer(hname, p)
|
||||
processErr(bind.GenObjc(w, fset, p, true))
|
||||
processErr(bind.GenObjc(w, fset, p, *prefix, true))
|
||||
closer()
|
||||
w, closer = writer(fname, p)
|
||||
processErr(bind.GenObjc(w, fset, p, false))
|
||||
processErr(bind.GenObjc(w, fset, p, *prefix, false))
|
||||
closer()
|
||||
}
|
||||
default:
|
||||
|
@ -13,8 +13,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
lang = flag.String("lang", "java", "target language for bindings, either java, go, or objc (experimental).")
|
||||
outdir = flag.String("outdir", "", "result will be written to the directory instead of stdout.")
|
||||
lang = flag.String("lang", "java", "target language for bindings, either java, go, or objc (experimental).")
|
||||
outdir = flag.String("outdir", "", "result will be written to the directory instead of stdout.")
|
||||
javaPkg = flag.String("javapkg", "", "custom Java package path used instead of the default 'go.<go package name>'. Valid only with -lang=java.")
|
||||
prefix = flag.String("prefix", "", "custom Objective-C name prefix used instead of the default 'Go'. Valid only with -lang=objc.")
|
||||
)
|
||||
|
||||
var usage = `The Gobind tool generates Java language bindings for Go.
|
||||
@ -24,6 +26,12 @@ For usage details, see doc.go.`
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *lang != "java" && *javaPkg != "" {
|
||||
log.Fatalf("Invalid option -javapkg for gobind -lang=%s", *lang)
|
||||
} else if *lang != "objc" && *prefix != "" {
|
||||
log.Fatalf("Invalid option -prefix for gobind -lang=%s", *lang)
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -119,14 +119,16 @@ func (b *binder) GenObjc(outdir string) error {
|
||||
printcmd("gobind -lang=objc %s > %s", b.pkg.Path(), mfile)
|
||||
}
|
||||
|
||||
const objcPrefix = "" // TODO(hyangah): -prefix
|
||||
|
||||
generate := func(w io.Writer) error {
|
||||
return bind.GenObjc(w, b.fset, b.pkg, false)
|
||||
return bind.GenObjc(w, b.fset, b.pkg, objcPrefix, false)
|
||||
}
|
||||
if err := writeFile(mfile, generate); err != nil {
|
||||
return err
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
return bind.GenObjc(w, b.fset, b.pkg, true)
|
||||
return bind.GenObjc(w, b.fset, b.pkg, objcPrefix, true)
|
||||
}
|
||||
if err := writeFile(hfile, generate); err != nil {
|
||||
return err
|
||||
@ -147,8 +149,9 @@ func (b *binder) GenJava(outdir string) error {
|
||||
printcmd("gobind -lang=java %s > %s", b.pkg.Path(), javaFile)
|
||||
}
|
||||
|
||||
const javaPkg = "" // TODO(hyangah): -javapkg
|
||||
generate := func(w io.Writer) error {
|
||||
return bind.GenJava(w, b.fset, b.pkg)
|
||||
return bind.GenJava(w, b.fset, b.pkg, javaPkg)
|
||||
}
|
||||
if err := writeFile(javaFile, generate); err != nil {
|
||||
return err
|
||||
|
@ -126,7 +126,7 @@ mkdir -p $GOMOBILE/android-{{.NDK}}/openal
|
||||
mv $WORK/openal/lib $GOMOBILE/android-{{.NDK}}/openal/lib{{if eq .GOOS "darwin"}}
|
||||
go install -p={{.NumCPU}} -x golang.org/x/mobile/gl
|
||||
go install -p={{.NumCPU}} -x golang.org/x/mobile/app
|
||||
go install -p={{.NumCPU}} -x golang.org/x/mobile/exp/app/debug {{end}}
|
||||
go install -p={{.NumCPU}} -x golang.org/x/mobile/exp/app/debug{{end}}
|
||||
GOOS=android GOARCH=arm GOARM=7 CC=$GOMOBILE/android-{{.NDK}}/arm/bin/arm-linux-androideabi-gcc{{.EXE}} CXX=$GOMOBILE/android-{{.NDK}}/arm/bin/arm-linux-androideabi-g++{{.EXE}} CGO_ENABLED=1 go install -p={{.NumCPU}} -pkgdir=$GOMOBILE/pkg_android_arm -x std
|
||||
{{if eq .GOOS "darwin"}}GOOS=darwin GOARCH=arm GOARM=7 CC=clang-iphoneos CXX=clang-iphoneos CGO_CFLAGS=-isysroot=iphoneos -arch armv7 CGO_LDFLAGS=-isysroot=iphoneos -arch armv7 CGO_ENABLED=1 go install -p={{.NumCPU}} -pkgdir=$GOMOBILE/pkg_darwin_arm -x std
|
||||
GOOS=darwin GOARCH=arm64 CC=clang-iphoneos CXX=clang-iphoneos CGO_CFLAGS=-isysroot=iphoneos -arch arm64 CGO_LDFLAGS=-isysroot=iphoneos -arch arm64 CGO_ENABLED=1 go install -p={{.NumCPU}} -pkgdir=$GOMOBILE/pkg_darwin_arm64 -x std
|
||||
|
Reference in New Issue
Block a user