bind, cmd: generate complete standalone bindings from gobind
The gobind and gomobile bind tools have historically overlapped: gobind outputs generated bindings, and gomobile bind will generate bindings before building them. However, the gobind bindings were never used for building and thus allowed to not be complete. To simplify version control, debugging, instrumentation and build system flexibility, this CL upgrades the gobind tool to be the canonical binding generator and change gomobile bind to use gobind instead of its own generator code. This greatly simplifies gomobile bind, but also paves the way to skip gomobile bind entirely. For example: $ gobind -outdir=$GOPATH golang.org/x/mobile/example/bind/hello $ GOOS=android GOARCH=arm64 CC=<ndk-toolchain>/bin/clang go build -buildmode=c-shared -o libgobind.so gobind $ ls libgobind.* libgobind.h libgobind.so The same applies to iOS, although the go build command line is more involved. By skipping gomobile it is possible to freely customize the Android or iOS SDK level or any other flags not supported by gomobile bind. By checking in the generated source code, the cost of supporting gomobile in a custom build system is also decreased. Change-Id: I59c14a77d625ac1377c23b3213672e0d83a48c85 Reviewed-on: https://go-review.googlesource.com/99316 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
parent
f16143114e
commit
4600df55ca
@ -930,7 +930,7 @@ extern void init_proxies();
|
||||
|
||||
classesGoHeader = `// File is generated by gobind. Do not edit.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h> // for free()
|
||||
|
@ -32,11 +32,11 @@ type goGen struct {
|
||||
}
|
||||
|
||||
const (
|
||||
goPreamble = `// Package gomobile_bind is an autogenerated binder stub for package %[1]s.
|
||||
goPreamble = `// Package main is an autogenerated binder stub for package %[1]s.
|
||||
// gobind -lang=go %[2]s
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
@ -315,8 +315,7 @@ func (g *ObjcWrapper) genCFuncDecl(prefix, name string, f *objc.Func) {
|
||||
|
||||
func (g *ObjcWrapper) GenGo() {
|
||||
g.Printf("// File is generated by gobind. Do not edit.\n\n")
|
||||
g.Printf("package gomobile_bind\n\n")
|
||||
g.Printf("// #cgo CFLAGS: -fobjc-arc -fmodules -fblocks\n")
|
||||
g.Printf("package main\n\n")
|
||||
g.Printf("// #include \"interfaces.h\"\n")
|
||||
g.Printf("import \"C\"\n\n")
|
||||
g.Printf("import \"ObjC\"\n")
|
||||
|
@ -3,7 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <jni.h>
|
||||
#include "seq.h"
|
||||
#include "seq_android.h"
|
||||
#include "_cgo_export.h"
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
@ -19,6 +19,10 @@
|
||||
|
||||
#define NULL_REFNUM 41
|
||||
|
||||
// initClasses are only exported from Go if reverse bindings are used.
|
||||
// If they're not, weakly define a no-op function.
|
||||
__attribute__((weak)) void initClasses(void) { }
|
||||
|
||||
static JavaVM *jvm;
|
||||
// jnienvs holds the per-thread JNIEnv* for Go threads where we called AttachCurrentThread.
|
||||
// A pthread key destructor is supplied to call DetachCurrentThread on exit. This trick is
|
||||
|
@ -2,18 +2,18 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
// Go support functions for bindings. This file is copied into the
|
||||
// generated gomobile_bind package and compiled along with the
|
||||
// generated binding files.
|
||||
// generated main package and compiled along with the generated binding
|
||||
// files.
|
||||
|
||||
//#cgo CFLAGS: -Werror
|
||||
//#cgo LDFLAGS: -llog
|
||||
//#include <jni.h>
|
||||
//#include <stdint.h>
|
||||
//#include <stdlib.h>
|
||||
//#include "seq.h"
|
||||
//#include "seq_android.h"
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef __GO_SEQ_HDR__
|
||||
#define __GO_SEQ_HDR__
|
||||
#ifndef __GO_SEQ_ANDROID_HDR__
|
||||
#define __GO_SEQ_ANDROID_HDR__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <android/log.h>
|
||||
@ -64,4 +64,4 @@ extern jmethodID go_seq_get_static_method_id(jclass clazz, const char *name, con
|
||||
extern jmethodID go_seq_get_method_id(jclass clazz, const char *name, const char *sig);
|
||||
extern int go_seq_isinstanceof(jint refnum, jclass clazz);
|
||||
|
||||
#endif // __GO_SEQ_HDR__
|
||||
#endif // __GO_SEQ_ANDROID_HDR__
|
@ -2,14 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
// Go support functions for Objective-C. Note that this
|
||||
// file is copied into and compiled with the generated
|
||||
// bindings.
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c -fobjc-arc -Werror
|
||||
#cgo CFLAGS: -x objective-c -fobjc-arc -fmodules -fblocks -Werror
|
||||
#cgo LDFLAGS: -framework Foundation
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef __GO_SEQ_HDR__
|
||||
#define __GO_SEQ_HDR__
|
||||
#ifndef __GO_SEQ_DARWIN_HDR__
|
||||
#define __GO_SEQ_DARWIN_HDR__
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include "ref.h"
|
||||
@ -60,4 +60,4 @@ extern nstring go_seq_from_objc_string(NSString *s);
|
||||
extern NSData *go_seq_to_objc_bytearray(nbyteslice, int copy);
|
||||
extern NSString *go_seq_to_objc_string(nstring str);
|
||||
|
||||
#endif // __GO_SEQ_HDR__
|
||||
#endif // __GO_SEQ_DARWIN_HDR__
|
@ -2,12 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
// Go support functions for generated Go bindings. This file is
|
||||
// copied into the generated package, gomobile_bind, and compiled
|
||||
// along with the bindings.
|
||||
// copied into the generated main package, and compiled along
|
||||
// with the bindings.
|
||||
|
||||
// #cgo android CFLAGS: -D__GOBIND_ANDROID__
|
||||
// #cgo darwin CFLAGS: -D__GOBIND_DARWIN__
|
||||
// #include <stdlib.h>
|
||||
// #include "seq.h"
|
||||
import "C"
|
||||
@ -18,6 +20,7 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
_ "golang.org/x/mobile/bind/java"
|
||||
_seq "golang.org/x/mobile/bind/seq"
|
||||
)
|
||||
|
||||
@ -45,3 +48,5 @@ func init() {
|
||||
func IncGoRef(refnum C.int32_t) {
|
||||
_seq.Inc(int32(refnum))
|
||||
}
|
||||
|
||||
func main() {}
|
||||
|
4
bind/testdata/basictypes.go.golden
vendored
4
bind/testdata/basictypes.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package basictypes.
|
||||
// Package main is an autogenerated binder stub for package basictypes.
|
||||
// gobind -lang=go basictypes
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
6
bind/testdata/classes.go.golden
vendored
6
bind/testdata/classes.go.golden
vendored
@ -544,7 +544,7 @@ type Java_io_Console interface {
|
||||
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h> // for free()
|
||||
@ -1865,11 +1865,11 @@ func (p *proxy_class_java_io_Console) ToString() string {
|
||||
return _res
|
||||
}
|
||||
|
||||
// Package gomobile_bind is an autogenerated binder stub for package java.
|
||||
// Package main is an autogenerated binder stub for package java.
|
||||
// gobind -lang=go classes
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/doc.go.golden
vendored
4
bind/testdata/doc.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package doc.
|
||||
// Package main is an autogenerated binder stub for package doc.
|
||||
// gobind -lang=go doc
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/ignore.go.golden
vendored
4
bind/testdata/ignore.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package ignore.
|
||||
// Package main is an autogenerated binder stub for package ignore.
|
||||
// gobind -lang=go ignore
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/interfaces.go.golden
vendored
4
bind/testdata/interfaces.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package interfaces.
|
||||
// Package main is an autogenerated binder stub for package interfaces.
|
||||
// gobind -lang=go interfaces
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/issue10788.go.golden
vendored
4
bind/testdata/issue10788.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package issue10788.
|
||||
// Package main is an autogenerated binder stub for package issue10788.
|
||||
// gobind -lang=go issue10788
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/issue12328.go.golden
vendored
4
bind/testdata/issue12328.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package issue12328.
|
||||
// Package main is an autogenerated binder stub for package issue12328.
|
||||
// gobind -lang=go issue12328
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/issue12403.go.golden
vendored
4
bind/testdata/issue12403.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package issue12403.
|
||||
// Package main is an autogenerated binder stub for package issue12403.
|
||||
// gobind -lang=go issue12403
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
6
bind/testdata/java.go.golden
vendored
6
bind/testdata/java.go.golden
vendored
@ -220,7 +220,7 @@ type Java_lang_Character_Subset interface {
|
||||
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h> // for free()
|
||||
@ -495,11 +495,11 @@ func (p *proxy_class_java_lang_Character_Subset) ToString() string {
|
||||
return _res
|
||||
}
|
||||
|
||||
// Package gomobile_bind is an autogenerated binder stub for package java.
|
||||
// Package main is an autogenerated binder stub for package java.
|
||||
// gobind -lang=go java
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/keywords.go.golden
vendored
4
bind/testdata/keywords.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package keywords.
|
||||
// Package main is an autogenerated binder stub for package keywords.
|
||||
// gobind -lang=go keywords
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
7
bind/testdata/objc.go.golden
vendored
7
bind/testdata/objc.go.golden
vendored
@ -16,9 +16,8 @@ type Foundation_NSObjectC interface {
|
||||
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
// #cgo CFLAGS: -fobjc-arc -fmodules -fblocks
|
||||
// #include "interfaces.h"
|
||||
import "C"
|
||||
|
||||
@ -53,11 +52,11 @@ type proxy_class_NSObjectC _seq.Ref
|
||||
|
||||
func (p *proxy_class_NSObjectC) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
|
||||
|
||||
// Package gomobile_bind is an autogenerated binder stub for package objc.
|
||||
// Package main is an autogenerated binder stub for package objc.
|
||||
// gobind -lang=go objc
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
7
bind/testdata/objcw.go.golden
vendored
7
bind/testdata/objcw.go.golden
vendored
@ -55,9 +55,8 @@ type Objc_GoUIResponder interface {
|
||||
|
||||
// File is generated by gobind. Do not edit.
|
||||
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
// #cgo CFLAGS: -fobjc-arc -fmodules -fblocks
|
||||
// #include "interfaces.h"
|
||||
import "C"
|
||||
|
||||
@ -296,11 +295,11 @@ func (p *super_GoUIResponder) Description() (string) {
|
||||
return _res
|
||||
}
|
||||
|
||||
// Package gomobile_bind is an autogenerated binder stub for package objc.
|
||||
// Package main is an autogenerated binder stub for package objc.
|
||||
// gobind -lang=go objcw
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/structs.go.golden
vendored
4
bind/testdata/structs.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package structs.
|
||||
// Package main is an autogenerated binder stub for package structs.
|
||||
// gobind -lang=go structs
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/try.go.golden
vendored
4
bind/testdata/try.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package try.
|
||||
// Package main is an autogenerated binder stub for package try.
|
||||
// gobind -lang=go try
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/universe.golden
vendored
4
bind/testdata/universe.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package universe.
|
||||
// Package main is an autogenerated binder stub for package universe.
|
||||
// gobind -lang=go
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
4
bind/testdata/vars.go.golden
vendored
4
bind/testdata/vars.go.golden
vendored
@ -1,8 +1,8 @@
|
||||
// Package gomobile_bind is an autogenerated binder stub for package vars.
|
||||
// Package main is an autogenerated binder stub for package vars.
|
||||
// gobind -lang=go vars
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package gomobile_bind
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
@ -22,16 +21,23 @@ import (
|
||||
"golang.org/x/mobile/bind"
|
||||
"golang.org/x/mobile/internal/importers"
|
||||
"golang.org/x/mobile/internal/importers/java"
|
||||
"golang.org/x/mobile/internal/importers/objc"
|
||||
)
|
||||
|
||||
func genPkg(p *types.Package, allPkg []*types.Package, classes []*java.Class) {
|
||||
fname := defaultFileName(*lang, p)
|
||||
func genPkg(lang string, p *types.Package, allPkg []*types.Package, classes []*java.Class, otypes []*objc.Named) {
|
||||
fname := defaultFileName(lang, p)
|
||||
conf := &bind.GeneratorConfig{
|
||||
Fset: fset,
|
||||
Pkg: p,
|
||||
AllPkg: allPkg,
|
||||
}
|
||||
switch *lang {
|
||||
var pname string
|
||||
if p != nil {
|
||||
pname = p.Name()
|
||||
} else {
|
||||
pname = "universe"
|
||||
}
|
||||
switch lang {
|
||||
case "java":
|
||||
var buf bytes.Buffer
|
||||
g := &bind.JavaGen{
|
||||
@ -48,30 +54,24 @@ func genPkg(p *types.Package, allPkg []*types.Package, classes []*java.Class) {
|
||||
pkgname := bind.JavaPkgName(*javaPkg, p)
|
||||
pkgDir := strings.Replace(pkgname, ".", "/", -1)
|
||||
buf.Reset()
|
||||
w, closer := writer(filepath.Join(pkgDir, fname))
|
||||
w, closer := writer(filepath.Join("java", pkgDir, fname))
|
||||
processErr(g.GenJava())
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
for i, name := range g.ClassNames() {
|
||||
buf.Reset()
|
||||
w, closer := writer(filepath.Join(pkgDir, name+".java"))
|
||||
w, closer := writer(filepath.Join("java", pkgDir, name+".java"))
|
||||
processErr(g.GenClass(i))
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
}
|
||||
buf.Reset()
|
||||
pn := "universe"
|
||||
if p != nil {
|
||||
pn = p.Name()
|
||||
}
|
||||
cname := "java_" + pn + ".c"
|
||||
w, closer = writer(cname)
|
||||
w, closer = writer(filepath.Join("src", "gobind", pname+"_android.c"))
|
||||
processErr(g.GenC())
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
buf.Reset()
|
||||
hname := pn + ".h"
|
||||
w, closer = writer(hname)
|
||||
w, closer = writer(filepath.Join("src", "gobind", pname+"_android.h"))
|
||||
processErr(g.GenH())
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
@ -90,41 +90,44 @@ func genPkg(p *types.Package, allPkg []*types.Package, classes []*java.Class) {
|
||||
errorf("failed to open Java support file: %v", err)
|
||||
}
|
||||
defer in.Close()
|
||||
w, closer := writer(filepath.Join("go", javaFile))
|
||||
w, closer := writer(filepath.Join("java", "go", javaFile))
|
||||
defer closer()
|
||||
if _, err := io.Copy(w, in); err != nil {
|
||||
errorf("failed to copy Java support file: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Copy support files
|
||||
javaPkg, err := build.Default.Import("golang.org/x/mobile/bind/java", "", build.FindOnly)
|
||||
if err != nil {
|
||||
errorf("unable to import bind/java: %v", err)
|
||||
return
|
||||
}
|
||||
copyFile(filepath.Join("src", "gobind", "seq_android.c"), filepath.Join(javaPkg.Dir, "seq_android.c.support"))
|
||||
copyFile(filepath.Join("src", "gobind", "seq_android.go"), filepath.Join(javaPkg.Dir, "seq_android.go.support"))
|
||||
copyFile(filepath.Join("src", "gobind", "seq_android.h"), filepath.Join(javaPkg.Dir, "seq_android.h"))
|
||||
}
|
||||
// Copy support files
|
||||
javaPkg, err := build.Default.Import("golang.org/x/mobile/bind/java", "", build.FindOnly)
|
||||
if err != nil {
|
||||
errorf("unable to import bind/java: %v", err)
|
||||
return
|
||||
}
|
||||
copyFile("seq_android.c", filepath.Join(javaPkg.Dir, "seq_android.c.support"))
|
||||
copyFile("seq_android.go", filepath.Join(javaPkg.Dir, "seq_android.go.support"))
|
||||
copyFile("seq.h", filepath.Join(javaPkg.Dir, "seq.h"))
|
||||
case "go":
|
||||
w, closer := writer(fname)
|
||||
w, closer := writer(filepath.Join("src", "gobind", fname))
|
||||
conf.Writer = w
|
||||
processErr(bind.GenGo(conf))
|
||||
closer()
|
||||
var buf bytes.Buffer
|
||||
w, closer = writer(filepath.Join("src", "gobind", pname+".h"))
|
||||
genPkgH(w, pname)
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
w, closer = writer(filepath.Join("src", "gobind", "seq.h"))
|
||||
genPkgH(w, "seq")
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
bindPkg, err := build.Default.Import("golang.org/x/mobile/bind", "", build.FindOnly)
|
||||
if err != nil {
|
||||
errorf("unable to import bind: %v", err)
|
||||
return
|
||||
}
|
||||
copyFile("seq.go", filepath.Join(bindPkg.Dir, "seq.go.support"))
|
||||
copyFile(filepath.Join("src", "gobind", "seq.go"), filepath.Join(bindPkg.Dir, "seq.go.support"))
|
||||
case "objc":
|
||||
var gohname string
|
||||
if p != nil {
|
||||
gohname = p.Name() + ".h"
|
||||
} else {
|
||||
gohname = "universe.h"
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
g := &bind.ObjcGen{
|
||||
Generator: &bind.Generator{
|
||||
@ -135,53 +138,65 @@ func genPkg(p *types.Package, allPkg []*types.Package, classes []*java.Class) {
|
||||
},
|
||||
Prefix: *prefix,
|
||||
}
|
||||
g.Init(nil)
|
||||
|
||||
w, closer := writer(gohname)
|
||||
g.Init(otypes)
|
||||
w, closer := writer(filepath.Join("src", "gobind", pname+"_darwin.h"))
|
||||
processErr(g.GenGoH())
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
hname := strings.Title(fname[:len(fname)-2]) + ".objc.h"
|
||||
w, closer = writer(hname)
|
||||
w, closer = writer(filepath.Join("src", "gobind", hname))
|
||||
processErr(g.GenH())
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
w, closer = writer(fname)
|
||||
mname := strings.Title(fname[:len(fname)-2]) + "_darwin.m"
|
||||
w, closer = writer(filepath.Join("src", "gobind", mname))
|
||||
conf.Writer = w
|
||||
processErr(g.GenM())
|
||||
io.Copy(w, &buf)
|
||||
closer()
|
||||
// Copy support files
|
||||
objcPkg, err := build.Default.Import("golang.org/x/mobile/bind/objc", "", build.FindOnly)
|
||||
if err != nil {
|
||||
errorf("unable to import bind/objc: %v", err)
|
||||
return
|
||||
if p == nil {
|
||||
// Copy support files
|
||||
objcPkg, err := build.Default.Import("golang.org/x/mobile/bind/objc", "", build.FindOnly)
|
||||
if err != nil {
|
||||
errorf("unable to import bind/objc: %v", err)
|
||||
return
|
||||
}
|
||||
copyFile(filepath.Join("src", "gobind", "seq_darwin.m"), filepath.Join(objcPkg.Dir, "seq_darwin.m.support"))
|
||||
copyFile(filepath.Join("src", "gobind", "seq_darwin.go"), filepath.Join(objcPkg.Dir, "seq_darwin.go.support"))
|
||||
copyFile(filepath.Join("src", "gobind", "ref.h"), filepath.Join(objcPkg.Dir, "ref.h"))
|
||||
copyFile(filepath.Join("src", "gobind", "seq_darwin.h"), filepath.Join(objcPkg.Dir, "seq_darwin.h"))
|
||||
}
|
||||
copyFile("seq_darwin.m", filepath.Join(objcPkg.Dir, "seq_darwin.m.support"))
|
||||
copyFile("seq_darwin.go", filepath.Join(objcPkg.Dir, "seq_darwin.go.support"))
|
||||
copyFile("ref.h", filepath.Join(objcPkg.Dir, "ref.h"))
|
||||
copyFile("seq.h", filepath.Join(objcPkg.Dir, "seq.h"))
|
||||
default:
|
||||
errorf("unknown target language: %q", *lang)
|
||||
errorf("unknown target language: %q", lang)
|
||||
}
|
||||
}
|
||||
|
||||
func genJavaPackages(ctx *build.Context, dir string, classes []*java.Class, embedders []importers.Struct) error {
|
||||
func genPkgH(w io.Writer, pname string) {
|
||||
fmt.Fprintf(w, `// Code generated by gobind. DO NOT EDIT.
|
||||
|
||||
#ifdef __GOBIND_ANDROID__
|
||||
#include "%[1]s_android.h"
|
||||
#endif
|
||||
#ifdef __GOBIND_DARWIN__
|
||||
#include "%[1]s_darwin.h"
|
||||
#endif`, pname)
|
||||
}
|
||||
|
||||
func genObjcPackages(dir string, types []*objc.Named, embedders []importers.Struct) error {
|
||||
var buf bytes.Buffer
|
||||
cg := &bind.ClassGen{
|
||||
JavaPkg: *javaPkg,
|
||||
cg := &bind.ObjcWrapper{
|
||||
Printer: &bind.Printer{
|
||||
IndentEach: []byte("\t"),
|
||||
Buf: &buf,
|
||||
},
|
||||
}
|
||||
cg.Init(classes, embedders)
|
||||
pkgBase := filepath.Join(dir, "src", "Java")
|
||||
if err := os.MkdirAll(pkgBase, 0700); err != nil {
|
||||
return err
|
||||
var genNames []string
|
||||
for _, emb := range embedders {
|
||||
genNames = append(genNames, emb.Name)
|
||||
}
|
||||
for i, jpkg := range cg.Packages() {
|
||||
pkgDir := filepath.Join(pkgBase, jpkg)
|
||||
cg.Init(types, genNames)
|
||||
for i, opkg := range cg.Packages() {
|
||||
pkgDir := filepath.Join(dir, "src", "ObjC", opkg)
|
||||
if err := os.MkdirAll(pkgDir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -194,21 +209,84 @@ func genJavaPackages(ctx *build.Context, dir string, classes []*java.Class, embe
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenInterfaces()
|
||||
clsFile := filepath.Join(pkgBase, "interfaces.go")
|
||||
if err := ioutil.WriteFile(clsFile, buf.Bytes(), 0600); err != nil {
|
||||
objcBase := filepath.Join(dir, "src", "ObjC")
|
||||
if err := os.MkdirAll(objcBase, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(objcBase, "interfaces.go"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
goBase := filepath.Join(dir, "src", "gobind")
|
||||
if err := os.MkdirAll(goBase, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenGo()
|
||||
if err := ioutil.WriteFile(filepath.Join(goBase, "interfaces_darwin.go"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenH()
|
||||
if err := ioutil.WriteFile(filepath.Join(goBase, "interfaces.h"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenM()
|
||||
if err := ioutil.WriteFile(filepath.Join(goBase, "interfaces_darwin.m"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"go",
|
||||
"install",
|
||||
"-pkgdir="+filepath.Join(dir, "pkg", ctx.GOOS+"_"+ctx.GOARCH),
|
||||
"Java/...",
|
||||
)
|
||||
cmd.Env = append(os.Environ(), "GOPATH="+dir)
|
||||
cmd.Env = append(cmd.Env, "GOROOT="+ctx.GOROOT)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to go install the generated Java wrappers: %v: %s", err, string(out))
|
||||
func genJavaPackages(dir string, classes []*java.Class, embedders []importers.Struct) error {
|
||||
var buf bytes.Buffer
|
||||
cg := &bind.ClassGen{
|
||||
JavaPkg: *javaPkg,
|
||||
Printer: &bind.Printer{
|
||||
IndentEach: []byte("\t"),
|
||||
Buf: &buf,
|
||||
},
|
||||
}
|
||||
cg.Init(classes, embedders)
|
||||
for i, jpkg := range cg.Packages() {
|
||||
pkgDir := filepath.Join(dir, "src", "Java", jpkg)
|
||||
if err := os.MkdirAll(pkgDir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
pkgFile := filepath.Join(pkgDir, "package.go")
|
||||
buf.Reset()
|
||||
cg.GenPackage(i)
|
||||
if err := ioutil.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenInterfaces()
|
||||
javaBase := filepath.Join(dir, "src", "Java")
|
||||
if err := os.MkdirAll(javaBase, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(javaBase, "interfaces.go"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
goBase := filepath.Join(dir, "src", "gobind")
|
||||
if err := os.MkdirAll(goBase, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenGo()
|
||||
if err := ioutil.WriteFile(filepath.Join(goBase, "classes_android.go"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenH()
|
||||
if err := ioutil.WriteFile(filepath.Join(goBase, "classes.h"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
cg.GenC()
|
||||
if err := ioutil.WriteFile(filepath.Join(goBase, "classes_android.c"), buf.Bytes(), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -7,11 +7,8 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@ -22,15 +19,17 @@ import (
|
||||
|
||||
"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", "java", "target language for bindings, either java, go, or objc (experimental).")
|
||||
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.
|
||||
@ -40,14 +39,22 @@ 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)
|
||||
}
|
||||
run()
|
||||
os.Exit(exitStatus)
|
||||
}
|
||||
|
||||
func run() {
|
||||
var langs []string
|
||||
if *lang != "" {
|
||||
langs = strings.Split(*lang, ",")
|
||||
} else {
|
||||
langs = []string{"go", "java", "objc"}
|
||||
}
|
||||
oldCtx := build.Default
|
||||
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)
|
||||
@ -56,80 +63,94 @@ func main() {
|
||||
}
|
||||
allPkg = append(allPkg, pkg)
|
||||
}
|
||||
var classes []*java.Class
|
||||
refs, err := importers.AnalyzePackages(allPkg, "Java/")
|
||||
jrefs, err := importers.AnalyzePackages(allPkg, "Java/")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(refs.Refs) > 0 {
|
||||
imp := &java.Importer{
|
||||
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 = imp.Import(refs)
|
||||
classes, err = jimp.Import(jrefs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(classes) > 0 {
|
||||
tmpGopath, err := ioutil.TempDir(os.TempDir(), "gobind-")
|
||||
}
|
||||
var otypes []*objc.Named
|
||||
if len(orefs.Refs) > 0 {
|
||||
otypes, err = objc.Import(orefs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
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(tmpGopath)
|
||||
if err := genJavaPackages(ctx, tmpGopath, classes, refs.Embedders); err != nil {
|
||||
defer os.RemoveAll(srcDir)
|
||||
} else {
|
||||
srcDir, err = filepath.Abs(srcDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
gopath := ctx.GOPATH
|
||||
if gopath != "" {
|
||||
gopath = string(filepath.ListSeparator)
|
||||
}
|
||||
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)
|
||||
}
|
||||
ctx.GOPATH = gopath + tmpGopath
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the export data for any imported packages are up to date.
|
||||
cmd := exec.Command("go", "install")
|
||||
cmd := exec.Command("go", "install", "-tags", strings.Join(ctx.BuildTags, " "))
|
||||
cmd.Args = append(cmd.Args, flag.Args()...)
|
||||
cmd.Env = append(os.Environ(), "GOPATH="+ctx.GOPATH)
|
||||
cmd.Env = append(cmd.Env, "GOROOT="+ctx.GOROOT)
|
||||
if err := cmd.Run(); err != nil {
|
||||
// Only report I/O errors. Errors from go install is expected for as-yet
|
||||
// undefined Java wrappers.
|
||||
if _, ok := err.(*exec.ExitError); !ok {
|
||||
fmt.Fprintf(os.Stderr, "%s failed: %v", strings.Join(cmd.Args, " "), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s", out)
|
||||
exitStatus = 1
|
||||
return
|
||||
}
|
||||
|
||||
typePkgs := make([]*types.Package, len(allPkg))
|
||||
fset := token.NewFileSet()
|
||||
conf := &types.Config{
|
||||
Importer: importer.Default(),
|
||||
}
|
||||
conf.Error = func(err error) {
|
||||
// Ignore errors. They're probably caused by as-yet undefined
|
||||
// Java wrappers.
|
||||
}
|
||||
imp := importer.Default()
|
||||
for i, pkg := range allPkg {
|
||||
var files []*ast.File
|
||||
for _, name := range pkg.GoFiles {
|
||||
f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse Go file %s: %v", name, err)
|
||||
}
|
||||
files = append(files, f)
|
||||
var err error
|
||||
typePkgs[i], err = imp.Import(pkg.ImportPath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return
|
||||
}
|
||||
tpkg, _ := conf.Check(pkg.ImportPath, fset, files, nil)
|
||||
typePkgs[i] = tpkg
|
||||
}
|
||||
build.Default = oldCtx
|
||||
for _, pkg := range typePkgs {
|
||||
genPkg(pkg, typePkgs, classes)
|
||||
for _, l := range langs {
|
||||
for _, pkg := range typePkgs {
|
||||
genPkg(l, pkg, typePkgs, classes, otypes)
|
||||
}
|
||||
// Generate the error package and support files
|
||||
genPkg(l, nil, typePkgs, classes, otypes)
|
||||
}
|
||||
// Generate the error package and support files
|
||||
genPkg(nil, typePkgs, classes)
|
||||
os.Exit(exitStatus)
|
||||
}
|
||||
|
||||
var exitStatus = 0
|
||||
|
@ -5,26 +5,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mobile/bind"
|
||||
"golang.org/x/mobile/internal/importers"
|
||||
"golang.org/x/mobile/internal/importers/java"
|
||||
"golang.org/x/mobile/internal/importers/objc"
|
||||
)
|
||||
|
||||
// ctx, pkg, tmpdir in build.go
|
||||
@ -167,135 +155,6 @@ func init() {
|
||||
cmdBind.flag.StringVar(&bindBootClasspath, "bootclasspath", "", "The bootstrap classpath for imported Java classes. Valid only with -target=android.")
|
||||
}
|
||||
|
||||
type binder struct {
|
||||
files []*ast.File
|
||||
fset *token.FileSet
|
||||
pkgs []*types.Package
|
||||
}
|
||||
|
||||
func (b *binder) GenGoSupport(outdir string) error {
|
||||
bindPkg, err := ctx.Import("golang.org/x/mobile/bind", "", build.FindOnly)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return copyFile(filepath.Join(outdir, "seq.go"), filepath.Join(bindPkg.Dir, "seq.go.support"))
|
||||
}
|
||||
|
||||
func (b *binder) GenObjcSupport(outdir string) error {
|
||||
objcPkg, err := ctx.Import("golang.org/x/mobile/bind/objc", "", build.FindOnly)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyFile(filepath.Join(outdir, "seq_darwin.m"), filepath.Join(objcPkg.Dir, "seq_darwin.m.support")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyFile(filepath.Join(outdir, "seq_darwin.go"), filepath.Join(objcPkg.Dir, "seq_darwin.go.support")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyFile(filepath.Join(outdir, "ref.h"), filepath.Join(objcPkg.Dir, "ref.h")); err != nil {
|
||||
return err
|
||||
}
|
||||
return copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(objcPkg.Dir, "seq.h"))
|
||||
}
|
||||
|
||||
func (b *binder) GenObjc(pkg *types.Package, files []*ast.File, allPkg []*types.Package, outdir string, wrappers []*objc.Named) (string, error) {
|
||||
if pkg == nil {
|
||||
bindPrefix = ""
|
||||
}
|
||||
pkgName := ""
|
||||
pkgPath := ""
|
||||
if pkg != nil {
|
||||
pkgName = pkg.Name()
|
||||
pkgPath = pkg.Path()
|
||||
} else {
|
||||
pkgName = "universe"
|
||||
}
|
||||
bindOption := "-lang=objc"
|
||||
if bindPrefix != "" {
|
||||
bindOption += fmt.Sprintf(" -prefix=%q", bindPrefix)
|
||||
}
|
||||
|
||||
fileBase := bindPrefix + strings.Title(pkgName)
|
||||
mfile := filepath.Join(outdir, fileBase+".m")
|
||||
hfile := filepath.Join(outdir, fileBase+".objc.h")
|
||||
gohfile := filepath.Join(outdir, pkgName+".h")
|
||||
|
||||
var buf bytes.Buffer
|
||||
g := &bind.ObjcGen{
|
||||
Generator: &bind.Generator{
|
||||
Printer: &bind.Printer{Buf: &buf, IndentEach: []byte("\t")},
|
||||
Fset: b.fset,
|
||||
AllPkg: allPkg,
|
||||
Pkg: pkg,
|
||||
Files: files,
|
||||
},
|
||||
Prefix: bindPrefix,
|
||||
}
|
||||
g.Init(wrappers)
|
||||
|
||||
generate := func(w io.Writer) error {
|
||||
if buildX {
|
||||
printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkgPath)
|
||||
}
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenM(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(mfile, generate); err != nil {
|
||||
return "", err
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenH(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(hfile, generate); err != nil {
|
||||
return "", err
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenGoH(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(gohfile, generate); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fileBase, nil
|
||||
}
|
||||
|
||||
func (b *binder) GenJavaSupport(outdir string) error {
|
||||
javaPkg, err := ctx.Import("golang.org/x/mobile/bind/java", "", build.FindOnly)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyFile(filepath.Join(outdir, "seq_android.go"), filepath.Join(javaPkg.Dir, "seq_android.go.support")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyFile(filepath.Join(outdir, "seq_android.c"), filepath.Join(javaPkg.Dir, "seq_android.c.support")); err != nil {
|
||||
return err
|
||||
}
|
||||
return copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(javaPkg.Dir, "seq.h"))
|
||||
}
|
||||
|
||||
func bootClasspath() (string, error) {
|
||||
if bindBootClasspath != "" {
|
||||
return bindBootClasspath, nil
|
||||
@ -307,321 +166,6 @@ func bootClasspath() (string, error) {
|
||||
return filepath.Join(apiPath, "android.jar"), nil
|
||||
}
|
||||
|
||||
func GenObjcWrappers(pkgs []*build.Package, srcDir, pkgGen string) ([]*objc.Named, error) {
|
||||
refs, err := importers.AnalyzePackages(pkgs, "ObjC/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
types, err := objc.Import(refs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
g := &bind.ObjcWrapper{
|
||||
Printer: &bind.Printer{
|
||||
IndentEach: []byte("\t"),
|
||||
Buf: &buf,
|
||||
},
|
||||
}
|
||||
var genNames []string
|
||||
for _, emb := range refs.Embedders {
|
||||
genNames = append(genNames, emb.Name)
|
||||
}
|
||||
g.Init(types, genNames)
|
||||
for i, name := range g.Packages() {
|
||||
pkgDir := filepath.Join(pkgGen, "src", "ObjC", name)
|
||||
if err := os.MkdirAll(pkgDir, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgFile := filepath.Join(pkgDir, "package.go")
|
||||
generate := func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenPackage(i)
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(pkgFile, generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the ObjC wrapper package %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
generate := func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenGo()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(srcDir, "interfaces.go"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the ObjC wrapper Go file: %v", err)
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenInterfaces()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(pkgGen, "src", "ObjC", "interfaces.go"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the ObjC wrapper Go file: %v", err)
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenH()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(srcDir, "interfaces.h"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the ObjC wrapper header file: %v", err)
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenM()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(srcDir, "interfaces.m"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the Java classes ObjC file: %v", err)
|
||||
}
|
||||
return types, nil
|
||||
}
|
||||
|
||||
func GenClasses(pkgs []*build.Package, srcDir, jpkgSrc string) ([]*java.Class, error) {
|
||||
refs, err := importers.AnalyzePackages(pkgs, "Java/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bClspath, err := bootClasspath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imp := &java.Importer{
|
||||
Bootclasspath: bClspath,
|
||||
Classpath: bindClasspath,
|
||||
JavaPkg: bindJavaPkg,
|
||||
}
|
||||
classes, err := imp.Import(refs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
g := &bind.ClassGen{
|
||||
JavaPkg: bindJavaPkg,
|
||||
Printer: &bind.Printer{
|
||||
IndentEach: []byte("\t"),
|
||||
Buf: &buf,
|
||||
},
|
||||
}
|
||||
g.Init(classes, refs.Embedders)
|
||||
for i, jpkg := range g.Packages() {
|
||||
pkgDir := filepath.Join(jpkgSrc, "src", "Java", jpkg)
|
||||
if err := os.MkdirAll(pkgDir, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgFile := filepath.Join(pkgDir, "package.go")
|
||||
generate := func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenPackage(i)
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(pkgFile, generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the Java wrapper package %s: %v", jpkg, err)
|
||||
}
|
||||
}
|
||||
generate := func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenGo()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(srcDir, "classes.go"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the Java classes Go file: %v", err)
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenH()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(srcDir, "classes.h"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the Java classes header file: %v", err)
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenC()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(srcDir, "classes.c"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the Java classes C file: %v", err)
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
g.GenInterfaces()
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(filepath.Join(jpkgSrc, "src", "Java", "interfaces.go"), generate); err != nil {
|
||||
return nil, fmt.Errorf("failed to create the Java classes interfaces file: %v", err)
|
||||
}
|
||||
return classes, nil
|
||||
}
|
||||
|
||||
func (b *binder) GenJava(pkg *types.Package, files []*ast.File, allPkg []*types.Package, classes []*java.Class, outdir, androidDir string) error {
|
||||
jpkgname := bind.JavaPkgName(bindJavaPkg, pkg)
|
||||
javadir := filepath.Join(androidDir, strings.Replace(jpkgname, ".", "/", -1))
|
||||
var className string
|
||||
pkgName := ""
|
||||
pkgPath := ""
|
||||
if pkg != nil {
|
||||
className = strings.Title(pkg.Name())
|
||||
pkgName = pkg.Name()
|
||||
pkgPath = pkg.Path()
|
||||
} else {
|
||||
pkgName = "universe"
|
||||
className = "Universe"
|
||||
}
|
||||
javaFile := filepath.Join(javadir, className+".java")
|
||||
cFile := filepath.Join(outdir, "java_"+pkgName+".c")
|
||||
hFile := filepath.Join(outdir, pkgName+".h")
|
||||
bindOption := "-lang=java"
|
||||
if bindJavaPkg != "" {
|
||||
bindOption += " -javapkg=" + bindJavaPkg
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
g := &bind.JavaGen{
|
||||
JavaPkg: bindJavaPkg,
|
||||
Generator: &bind.Generator{
|
||||
Printer: &bind.Printer{Buf: &buf, IndentEach: []byte(" ")},
|
||||
Fset: b.fset,
|
||||
AllPkg: allPkg,
|
||||
Pkg: pkg,
|
||||
Files: files,
|
||||
},
|
||||
}
|
||||
g.Init(classes)
|
||||
|
||||
generate := func(w io.Writer) error {
|
||||
if buildX {
|
||||
printcmd("gobind %s -outdir=%s %s", bindOption, javadir, pkgPath)
|
||||
}
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenJava(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(javaFile, generate); err != nil {
|
||||
return err
|
||||
}
|
||||
for i, name := range g.ClassNames() {
|
||||
generate := func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenClass(i); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
classFile := filepath.Join(javadir, name+".java")
|
||||
if err := writeFile(classFile, generate); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenC(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
if err := writeFile(cFile, generate); err != nil {
|
||||
return err
|
||||
}
|
||||
generate = func(w io.Writer) error {
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
buf.Reset()
|
||||
if err := g.GenH(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, &buf)
|
||||
return err
|
||||
}
|
||||
return writeFile(hFile, generate)
|
||||
}
|
||||
|
||||
func (b *binder) GenGo(pkg *types.Package, allPkg []*types.Package, outdir string) error {
|
||||
pkgName := "go_"
|
||||
pkgPath := ""
|
||||
if pkg != nil {
|
||||
pkgName += pkg.Name()
|
||||
pkgPath = pkg.Path()
|
||||
}
|
||||
goFile := filepath.Join(outdir, pkgName+"main.go")
|
||||
|
||||
generate := func(w io.Writer) error {
|
||||
if buildX {
|
||||
printcmd("gobind -lang=go -outdir=%s %s", outdir, pkgPath)
|
||||
}
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
conf := &bind.GeneratorConfig{
|
||||
Writer: w,
|
||||
Fset: b.fset,
|
||||
Pkg: pkg,
|
||||
AllPkg: allPkg,
|
||||
}
|
||||
return bind.GenGo(conf)
|
||||
}
|
||||
if err := writeFile(goFile, generate); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(dst, src string) error {
|
||||
if buildX {
|
||||
printcmd("cp %s %s", src, dst)
|
||||
@ -669,87 +213,3 @@ func writeFile(filename string, generate func(io.Writer) error) error {
|
||||
|
||||
return generate(f)
|
||||
}
|
||||
|
||||
func loadExportData(pkgs []*build.Package, env []string, args ...string) ([]*types.Package, error) {
|
||||
// Compile the package. This will produce good errors if the package
|
||||
// doesn't typecheck for some reason, and is a necessary step to
|
||||
// building the final output anyway.
|
||||
paths := make([]string, len(pkgs))
|
||||
for i, p := range pkgs {
|
||||
paths[i] = p.ImportPath
|
||||
}
|
||||
if err := goInstall(paths, env, args...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
goos, goarch := getenv(env, "GOOS"), getenv(env, "GOARCH")
|
||||
|
||||
// Assemble a fake GOPATH and trick go/importer into using it.
|
||||
// Ideally the importer package would let us provide this to
|
||||
// it somehow, but this works with what's in Go 1.5 today and
|
||||
// gives us access to the gcimporter package without us having
|
||||
// to make a copy of it.
|
||||
fakegopath := filepath.Join(tmpdir, "fakegopath")
|
||||
if err := removeAll(fakegopath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := mkdir(filepath.Join(fakegopath, "pkg")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typePkgs := make([]*types.Package, len(pkgs))
|
||||
imp := importer.Default()
|
||||
for i, p := range pkgs {
|
||||
importPath := p.ImportPath
|
||||
src := filepath.Join(pkgdir(env), importPath+".a")
|
||||
dst := filepath.Join(fakegopath, "pkg/"+goos+"_"+goarch+"/"+importPath+".a")
|
||||
if err := copyFile(dst, src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if buildN {
|
||||
typePkgs[i] = types.NewPackage(importPath, path.Base(importPath))
|
||||
continue
|
||||
}
|
||||
oldDefault := build.Default
|
||||
build.Default = ctx // copy
|
||||
build.Default.GOARCH = goarch
|
||||
build.Default.GOPATH = fakegopath
|
||||
p, err := imp.Import(importPath)
|
||||
build.Default = oldDefault
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typePkgs[i] = p
|
||||
}
|
||||
return typePkgs, nil
|
||||
}
|
||||
|
||||
func parse(pkgs []*build.Package) ([][]*ast.File, error) {
|
||||
fset := token.NewFileSet()
|
||||
var astPkgs [][]*ast.File
|
||||
for _, pkg := range pkgs {
|
||||
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)
|
||||
}
|
||||
astPkgs = append(astPkgs, files)
|
||||
}
|
||||
return astPkgs, nil
|
||||
}
|
||||
|
||||
func newBinder(pkgs []*types.Package) (*binder, error) {
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Name() == "main" {
|
||||
return nil, fmt.Errorf("package %q (%q): can only bind a library package", pkg.Name(), pkg.Path())
|
||||
}
|
||||
}
|
||||
b := &binder{
|
||||
fset: token.NewFileSet(),
|
||||
pkgs: pkgs,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
@ -21,114 +21,44 @@ func goAndroidBind(pkgs []*build.Package, androidArchs []string) error {
|
||||
if sdkDir := os.Getenv("ANDROID_HOME"); sdkDir == "" {
|
||||
return fmt.Errorf("this command requires ANDROID_HOME environment variable (path to the Android SDK)")
|
||||
}
|
||||
// Ideally this would be -buildmode=c-shared.
|
||||
// https://golang.org/issue/13234.
|
||||
androidArgs := []string{"-gcflags=-shared", "-ldflags=-shared"}
|
||||
|
||||
paths := make([]string, len(pkgs))
|
||||
for i, p := range pkgs {
|
||||
paths[i] = p.ImportPath
|
||||
// Run gobind to generate the bindings
|
||||
cmd := exec.Command(
|
||||
"gobind",
|
||||
"-lang=go,java",
|
||||
"-outdir="+tmpdir,
|
||||
)
|
||||
if len(ctx.BuildTags) > 0 {
|
||||
cmd.Args = append(cmd.Args, "-tags="+strings.Join(ctx.BuildTags, ","))
|
||||
}
|
||||
if bindJavaPkg != "" {
|
||||
cmd.Args = append(cmd.Args, "-javapkg="+bindJavaPkg)
|
||||
}
|
||||
if bindClasspath != "" {
|
||||
cmd.Args = append(cmd.Args, "-classpath="+bindClasspath)
|
||||
}
|
||||
if bindBootClasspath != "" {
|
||||
cmd.Args = append(cmd.Args, "-bootclasspath="+bindBootClasspath)
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
cmd.Args = append(cmd.Args, p.ImportPath)
|
||||
}
|
||||
if err := runCmd(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
androidDir := filepath.Join(tmpdir, "android")
|
||||
mainFile := filepath.Join(tmpdir, "androidlib/main.go")
|
||||
jpkgSrc := filepath.Join(tmpdir, "gen")
|
||||
|
||||
// Generate binding code and java source code only when processing the first package.
|
||||
first := true
|
||||
for _, arch := range androidArchs {
|
||||
env := androidEnv[arch]
|
||||
// Add the generated Java class wrapper packages to GOPATH
|
||||
gopath := fmt.Sprintf("GOPATH=%s%c%s", jpkgSrc, filepath.ListSeparator, os.Getenv("GOPATH"))
|
||||
// Add the generated packages to GOPATH
|
||||
gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, os.Getenv("GOPATH"))
|
||||
env = append(env, gopath)
|
||||
toolchain := ndk.Toolchain(arch)
|
||||
|
||||
if !first {
|
||||
err := goBuild(
|
||||
mainFile,
|
||||
env,
|
||||
"-buildmode=c-shared",
|
||||
"-o="+filepath.Join(androidDir, "src/main/jniLibs/"+toolchain.abi+"/libgojni.so"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
first = false
|
||||
|
||||
srcDir := filepath.Join(tmpdir, "gomobile_bind")
|
||||
if err := mkdir(srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
classes, err := GenClasses(pkgs, srcDir, jpkgSrc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typesPkgs, err := loadExportData(pkgs, env, androidArgs...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("loadExportData failed: %v", err)
|
||||
}
|
||||
|
||||
astPkgs, err := parse(pkgs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parseAST failed: %v", err)
|
||||
}
|
||||
|
||||
binder, err := newBinder(typesPkgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range binder.pkgs {
|
||||
if err := binder.GenGo(pkg, binder.pkgs, srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Generate the error type.
|
||||
if err := binder.GenGo(nil, binder.pkgs, srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeFile(mainFile, func(w io.Writer) error {
|
||||
_, err := w.Write(androidMainFile)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create the main package for android: %v", err)
|
||||
}
|
||||
|
||||
p, err := ctx.Import("golang.org/x/mobile/bind", cwd, build.ImportComment)
|
||||
if err != nil {
|
||||
return fmt.Errorf(`"golang.org/x/mobile/bind" is not found; run go get golang.org/x/mobile/bind`)
|
||||
}
|
||||
repo := filepath.Clean(filepath.Join(p.Dir, "..")) // golang.org/x/mobile directory.
|
||||
|
||||
jclsDir := filepath.Join(androidDir, "src", "main", "java")
|
||||
for i, pkg := range binder.pkgs {
|
||||
if err := binder.GenJava(pkg, astPkgs[i], binder.pkgs, classes, srcDir, jclsDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := binder.GenJava(nil, nil, binder.pkgs, classes, srcDir, jclsDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binder.GenJavaSupport(srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binder.GenGoSupport(srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
javaDir := filepath.Join(androidDir, "src/main/java/go")
|
||||
if err := mkdir(javaDir); err != nil {
|
||||
return err
|
||||
}
|
||||
err = goBuild(
|
||||
mainFile,
|
||||
err := goBuild(
|
||||
"gobind",
|
||||
env,
|
||||
"-buildmode=c-shared",
|
||||
"-o="+filepath.Join(androidDir, "src/main/jniLibs/"+toolchain.abi+"/libgojni.so"),
|
||||
@ -136,35 +66,16 @@ func goAndroidBind(pkgs []*build.Package, androidArchs []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, javaFile := range []string{"Seq.java", "LoadJNI.java"} {
|
||||
src := filepath.Join(repo, "bind/java/"+javaFile)
|
||||
dst := filepath.Join(javaDir, javaFile)
|
||||
rm(dst)
|
||||
if err := symlink(src, dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := buildAAR(androidDir, pkgs, androidArchs); err != nil {
|
||||
jsrc := filepath.Join(tmpdir, "java")
|
||||
if err := buildAAR(jsrc, androidDir, pkgs, androidArchs); err != nil {
|
||||
return err
|
||||
}
|
||||
return buildSrcJar(androidDir)
|
||||
return buildSrcJar(jsrc)
|
||||
}
|
||||
|
||||
var androidMainFile = []byte(`
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "golang.org/x/mobile/bind/java"
|
||||
_ "../gomobile_bind"
|
||||
)
|
||||
|
||||
func main() {}
|
||||
`)
|
||||
|
||||
func buildSrcJar(androidDir string) error {
|
||||
func buildSrcJar(src string) error {
|
||||
var out io.Writer = ioutil.Discard
|
||||
if !buildN {
|
||||
ext := filepath.Ext(buildO)
|
||||
@ -180,7 +91,6 @@ func buildSrcJar(androidDir string) error {
|
||||
out = f
|
||||
}
|
||||
|
||||
src := filepath.Join(androidDir, "src/main/java")
|
||||
return writeJar(out, src)
|
||||
}
|
||||
|
||||
@ -202,7 +112,7 @@ func buildSrcJar(androidDir string) error {
|
||||
// aidl (optional, not relevant)
|
||||
//
|
||||
// javac and jar commands are needed to build classes.jar.
|
||||
func buildAAR(androidDir string, pkgs []*build.Package, androidArchs []string) (err error) {
|
||||
func buildAAR(srcDir, androidDir string, pkgs []*build.Package, androidArchs []string) (err error) {
|
||||
var out io.Writer = ioutil.Discard
|
||||
if buildO == "" {
|
||||
buildO = pkgs[0].Name + ".aar"
|
||||
@ -248,8 +158,7 @@ func buildAAR(androidDir string, pkgs []*build.Package, androidArchs []string) (
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src := filepath.Join(androidDir, "src/main/java")
|
||||
if err := buildJar(w, src); err != nil {
|
||||
if err := buildJar(w, srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -17,30 +17,29 @@ import (
|
||||
)
|
||||
|
||||
func goIOSBind(pkgs []*build.Package) error {
|
||||
srcDir := filepath.Join(tmpdir, "src", "gomobile_bind")
|
||||
genDir := filepath.Join(tmpdir, "gen")
|
||||
wrappers, err := GenObjcWrappers(pkgs, srcDir, genDir)
|
||||
if err != nil {
|
||||
return err
|
||||
// Run gobind to generate the bindings
|
||||
cmd := exec.Command(
|
||||
"gobind",
|
||||
"-lang=go,objc",
|
||||
"-outdir="+tmpdir,
|
||||
)
|
||||
if len(ctx.BuildTags) > 0 {
|
||||
cmd.Args = append(cmd.Args, "-tags="+strings.Join(ctx.BuildTags, ","))
|
||||
}
|
||||
env := darwinArmEnv
|
||||
gopath := fmt.Sprintf("GOPATH=%s%c%s", genDir, filepath.ListSeparator, os.Getenv("GOPATH"))
|
||||
env = append(env, gopath)
|
||||
typesPkgs, err := loadExportData(pkgs, env)
|
||||
if err != nil {
|
||||
if bindPrefix != "" {
|
||||
cmd.Args = append(cmd.Args, "-prefix="+bindPrefix)
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
cmd.Args = append(cmd.Args, p.ImportPath)
|
||||
}
|
||||
if err := runCmd(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
astPkgs, err := parse(pkgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcDir := filepath.Join(tmpdir, "src", "gobind")
|
||||
gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, os.Getenv("GOPATH"))
|
||||
|
||||
binder, err := newBinder(typesPkgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := binder.pkgs[0].Name()
|
||||
name := pkgs[0].Name
|
||||
title := strings.Title(name)
|
||||
|
||||
if buildO != "" && !strings.HasSuffix(buildO, ".framework") {
|
||||
@ -50,46 +49,18 @@ func goIOSBind(pkgs []*build.Package) error {
|
||||
buildO = title + ".framework"
|
||||
}
|
||||
|
||||
for _, pkg := range binder.pkgs {
|
||||
if err := binder.GenGo(pkg, binder.pkgs, srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Generate the error type.
|
||||
if err := binder.GenGo(nil, binder.pkgs, srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
mainFile := filepath.Join(tmpdir, "src/iosbin/main.go")
|
||||
err = writeFile(mainFile, func(w io.Writer) error {
|
||||
_, err := w.Write(iosBindFile)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create the binding package for iOS: %v", err)
|
||||
fileBases := make([]string, len(pkgs)+1)
|
||||
for i, pkg := range pkgs {
|
||||
fileBases[i] = bindPrefix + strings.Title(pkg.Name)
|
||||
}
|
||||
fileBases[len(fileBases)-1] = "universe"
|
||||
|
||||
fileBases := make([]string, len(typesPkgs)+1)
|
||||
for i, pkg := range binder.pkgs {
|
||||
if fileBases[i], err = binder.GenObjc(pkg, astPkgs[i], binder.pkgs, srcDir, wrappers); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if fileBases[len(fileBases)-1], err = binder.GenObjc(nil, nil, binder.pkgs, srcDir, wrappers); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binder.GenObjcSupport(srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binder.GenGoSupport(srcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command("xcrun", "lipo", "-create")
|
||||
cmd = exec.Command("xcrun", "lipo", "-create")
|
||||
|
||||
for _, env := range [][]string{darwinArmEnv, darwinArm64Env, darwinAmd64Env} {
|
||||
env = append(env, gopath)
|
||||
arch := archClang(getenv(env, "GOARCH"))
|
||||
path, err := goIOSBindArchive(name, mainFile, env, fileBases)
|
||||
path, err := goIOSBindArchive(name, env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("darwin-%s: %v", arch, err)
|
||||
}
|
||||
@ -123,7 +94,7 @@ func goIOSBind(pkgs []*build.Package) error {
|
||||
headerFiles := make([]string, len(fileBases))
|
||||
if len(fileBases) == 1 {
|
||||
headerFiles[0] = title + ".h"
|
||||
err = copyFile(
|
||||
err := copyFile(
|
||||
headers+"/"+title+".h",
|
||||
srcDir+"/"+bindPrefix+title+".objc.h",
|
||||
)
|
||||
@ -133,14 +104,14 @@ func goIOSBind(pkgs []*build.Package) error {
|
||||
} else {
|
||||
for i, fileBase := range fileBases {
|
||||
headerFiles[i] = fileBase + ".objc.h"
|
||||
err = copyFile(
|
||||
err := copyFile(
|
||||
headers+"/"+fileBase+".objc.h",
|
||||
srcDir+"/"+fileBase+".objc.h")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = copyFile(
|
||||
err := copyFile(
|
||||
headers+"/ref.h",
|
||||
srcDir+"/ref.h")
|
||||
if err != nil {
|
||||
@ -175,7 +146,7 @@ func goIOSBind(pkgs []*build.Package) error {
|
||||
Module: title,
|
||||
Headers: headerFiles,
|
||||
}
|
||||
err = writeFile(buildO+"/Versions/A/Modules/module.modulemap", func(w io.Writer) error {
|
||||
err := writeFile(buildO+"/Versions/A/Modules/module.modulemap", func(w io.Writer) error {
|
||||
return iosModuleMapTmpl.Execute(w, mmVals)
|
||||
})
|
||||
if err != nil {
|
||||
@ -199,10 +170,10 @@ var iosModuleMapTmpl = template.Must(template.New("iosmmap").Parse(`framework mo
|
||||
export *
|
||||
}`))
|
||||
|
||||
func goIOSBindArchive(name, path string, env, fileBases []string) (string, error) {
|
||||
func goIOSBindArchive(name string, env []string) (string, error) {
|
||||
arch := getenv(env, "GOARCH")
|
||||
archive := filepath.Join(tmpdir, name+"-"+arch+".a")
|
||||
err := goBuild(path, env, "-buildmode=c-archive", "-o", archive)
|
||||
err := goBuild("gobind", env, "-buildmode=c-archive", "-o", archive)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -210,18 +181,6 @@ func goIOSBindArchive(name, path string, env, fileBases []string) (string, error
|
||||
return archive, nil
|
||||
}
|
||||
|
||||
var iosBindFile = []byte(`
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "../gomobile_bind"
|
||||
)
|
||||
|
||||
import "C"
|
||||
|
||||
func main() {}
|
||||
`)
|
||||
|
||||
var iosBindHeaderTmpl = template.Must(template.New("ios.h").Parse(`
|
||||
// Objective-C API for talking to the following Go packages
|
||||
//
|
||||
|
@ -55,16 +55,13 @@ func TestBindAndroid(t *testing.T) {
|
||||
tests := []struct {
|
||||
javaPkg string
|
||||
wantGobind string
|
||||
wantPkgDir string
|
||||
}{
|
||||
{
|
||||
wantGobind: "gobind -lang=java",
|
||||
wantPkgDir: "asset",
|
||||
},
|
||||
{
|
||||
javaPkg: "com.example.foo",
|
||||
wantGobind: "gobind -lang=java -javapkg=com.example.foo",
|
||||
wantPkgDir: "com/example/foo/asset",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
@ -88,12 +85,12 @@ func TestBindAndroid(t *testing.T) {
|
||||
outputData
|
||||
AndroidPlatform string
|
||||
GobindJavaCmd string
|
||||
JavaPkgDir string
|
||||
JavaPkg string
|
||||
}{
|
||||
outputData: defaultOutputData(),
|
||||
AndroidPlatform: platform,
|
||||
GobindJavaCmd: tc.wantGobind,
|
||||
JavaPkgDir: tc.wantPkgDir,
|
||||
JavaPkg: tc.javaPkg,
|
||||
}
|
||||
|
||||
wantBuf := new(bytes.Buffer)
|
||||
@ -115,44 +112,8 @@ func TestBindAndroid(t *testing.T) {
|
||||
|
||||
var bindAndroidTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
|
||||
WORK=$WORK
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/gen/src/Java
|
||||
GOOS=android GOARCH=arm CC=/NDK/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=/NDK/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/sysroot -isystem /NDK/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_CPPFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/sysroot -isystem /NDK/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_LDFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/platforms/android-15/arch-arm -L$GOMOBILE/lib/arm CGO_ENABLED=1 GOARM=7 GOPATH=$WORK/gen:$GOPATH go install -pkgdir=$GOMOBILE/pkg_android_arm -x -gcflags=-shared -ldflags=-shared golang.org/x/mobile/asset
|
||||
rm -r -f "$WORK/fakegopath"
|
||||
mkdir -p $WORK/fakegopath/pkg
|
||||
cp $GOMOBILE/pkg_android_arm/golang.org/x/mobile/asset.a $WORK/fakegopath/pkg/android_arm/golang.org/x/mobile/asset.a
|
||||
mkdir -p $WORK/fakegopath/pkg/android_arm/golang.org/x/mobile
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
gobind -lang=go -outdir=$WORK/gomobile_bind golang.org/x/mobile/asset
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
gobind -lang=go -outdir=$WORK/gomobile_bind
|
||||
mkdir -p $WORK/androidlib
|
||||
mkdir -p $WORK/android/src/main/java/{{.JavaPkgDir}}
|
||||
{{.GobindJavaCmd}} -outdir=$WORK/android/src/main/java/{{.JavaPkgDir}} golang.org/x/mobile/asset
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/android/src/main/java/go
|
||||
{{.GobindJavaCmd}} -outdir=$WORK/android/src/main/java/go
|
||||
mkdir -p $WORK/android/src/main/java/go
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
cp $GOPATH/src/golang.org/x/mobile/bind/java/seq_android.go.support $WORK/gomobile_bind/seq_android.go
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
cp $GOPATH/src/golang.org/x/mobile/bind/java/seq_android.c.support $WORK/gomobile_bind/seq_android.c
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
cp $GOPATH/src/golang.org/x/mobile/bind/java/seq.h $WORK/gomobile_bind/seq.h
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
cp $GOPATH/src/golang.org/x/mobile/bind/seq.go.support $WORK/gomobile_bind/seq.go
|
||||
mkdir -p $WORK/gomobile_bind
|
||||
mkdir -p $WORK/android/src/main/java/go
|
||||
GOOS=android GOARCH=arm CC=/NDK/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=/NDK/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/sysroot -isystem /NDK/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_CPPFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/sysroot -isystem /NDK/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_LDFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/platforms/android-15/arch-arm -L$GOMOBILE/lib/arm CGO_ENABLED=1 GOARM=7 GOPATH=$WORK/gen:$GOPATH go build -pkgdir=$GOMOBILE/pkg_android_arm -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so $WORK/androidlib/main.go
|
||||
rm $WORK/android/src/main/java/go/Seq.java
|
||||
ln -s $GOPATH/src/golang.org/x/mobile/bind/java/Seq.java $WORK/android/src/main/java/go/Seq.java
|
||||
rm $WORK/android/src/main/java/go/LoadJNI.java
|
||||
ln -s $GOPATH/src/golang.org/x/mobile/bind/java/LoadJNI.java $WORK/android/src/main/java/go/LoadJNI.java
|
||||
PWD=$WORK/android/src/main/java javac -d $WORK/javac-output -source 1.7 -target 1.7 -bootclasspath {{.AndroidPlatform}}/android.jar *.java
|
||||
gobind -lang=go,java -outdir=$WORK{{if .JavaPkg}} -javapkg={{.JavaPkg}}{{end}} golang.org/x/mobile/asset
|
||||
GOOS=android GOARCH=arm CC=/NDK/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=/NDK/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/sysroot -isystem /NDK/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_CPPFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/sysroot -isystem /NDK/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_LDFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain /NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot /NDK/platforms/android-15/arch-arm -L$GOMOBILE/lib/arm CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH go build -pkgdir=$GOMOBILE/pkg_android_arm -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so gobind
|
||||
PWD=$WORK/java javac -d $WORK/javac-output -source 1.7 -target 1.7 -bootclasspath {{.AndroidPlatform}}/android.jar *.java
|
||||
jar c -C $WORK/javac-output .
|
||||
`))
|
||||
|
Loading…
x
Reference in New Issue
Block a user