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>
diff --git a/bind/genclasses.go b/bind/genclasses.go
index 234bb4b..a606f10 100644
--- a/bind/genclasses.go
+++ b/bind/genclasses.go
@@ -930,7 +930,7 @@
 
 	classesGoHeader = `// File is generated by gobind. Do not edit.
 
-package gomobile_bind
+package main
 
 /*
 #include <stdlib.h> // for free()
diff --git a/bind/gengo.go b/bind/gengo.go
index 1d0ff9f..4b6a22e 100644
--- a/bind/gengo.go
+++ b/bind/gengo.go
@@ -32,11 +32,11 @@
 }
 
 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>
diff --git a/bind/genobjcw.go b/bind/genobjcw.go
index 6b4b0b0..94152c6 100644
--- a/bind/genobjcw.go
+++ b/bind/genobjcw.go
@@ -315,8 +315,7 @@
 
 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")
diff --git a/bind/java/context_android.c b/bind/java/context_android.c
index 1e3a59c..66ce569 100644
--- a/bind/java/context_android.c
+++ b/bind/java/context_android.c
@@ -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
diff --git a/bind/java/seq_android.c.support b/bind/java/seq_android.c.support
index 7c0f483..b3aafad 100644
--- a/bind/java/seq_android.c.support
+++ b/bind/java/seq_android.c.support
@@ -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
diff --git a/bind/java/seq_android.go.support b/bind/java/seq_android.go.support
index f586e86..a832292 100644
--- a/bind/java/seq_android.go.support
+++ b/bind/java/seq_android.go.support
@@ -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"
diff --git a/bind/java/seq.h b/bind/java/seq_android.h
similarity index 96%
rename from bind/java/seq.h
rename to bind/java/seq_android.h
index 84c1dbb..26e9025 100644
--- a/bind/java/seq.h
+++ b/bind/java/seq_android.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_ANDROID_HDR__
+#define __GO_SEQ_ANDROID_HDR__
 
 #include <stdint.h>
 #include <android/log.h>
@@ -64,4 +64,4 @@
 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__
diff --git a/bind/objc/seq_darwin.go.support b/bind/objc/seq_darwin.go.support
index 38d6406..0b4e5de 100644
--- a/bind/objc/seq_darwin.go.support
+++ b/bind/objc/seq_darwin.go.support
@@ -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>
diff --git a/bind/objc/seq.h b/bind/objc/seq_darwin.h
similarity index 95%
rename from bind/objc/seq.h
rename to bind/objc/seq_darwin.h
index 57e3665..1aeec4a 100644
--- a/bind/objc/seq.h
+++ b/bind/objc/seq_darwin.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 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__
diff --git a/bind/seq.go.support b/bind/seq.go.support
index 1167b6c..392ec09 100644
--- a/bind/seq.go.support
+++ b/bind/seq.go.support
@@ -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 @@
 	"os/signal"
 	"syscall"
 
+	_ "golang.org/x/mobile/bind/java"
 	_seq "golang.org/x/mobile/bind/seq"
 )
 
@@ -45,3 +48,5 @@
 func IncGoRef(refnum C.int32_t) {
 	_seq.Inc(int32(refnum))
 }
+
+func main() {}
diff --git a/bind/testdata/basictypes.go.golden b/bind/testdata/basictypes.go.golden
index 128aade..b96b9f4 100644
--- a/bind/testdata/basictypes.go.golden
+++ b/bind/testdata/basictypes.go.golden
@@ -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>
diff --git a/bind/testdata/classes.go.golden b/bind/testdata/classes.go.golden
index 9227ab6..c90663d 100644
--- a/bind/testdata/classes.go.golden
+++ b/bind/testdata/classes.go.golden
@@ -544,7 +544,7 @@
 
 // File is generated by gobind. Do not edit.
 
-package gomobile_bind
+package main
 
 /*
 #include <stdlib.h> // for free()
@@ -1865,11 +1865,11 @@
 	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>
diff --git a/bind/testdata/doc.go.golden b/bind/testdata/doc.go.golden
index 41da999..043122d 100644
--- a/bind/testdata/doc.go.golden
+++ b/bind/testdata/doc.go.golden
@@ -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>
diff --git a/bind/testdata/ignore.go.golden b/bind/testdata/ignore.go.golden
index 4299931..ed73288 100644
--- a/bind/testdata/ignore.go.golden
+++ b/bind/testdata/ignore.go.golden
@@ -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>
diff --git a/bind/testdata/interfaces.go.golden b/bind/testdata/interfaces.go.golden
index a4700d6..60cf2e4 100644
--- a/bind/testdata/interfaces.go.golden
+++ b/bind/testdata/interfaces.go.golden
@@ -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>
diff --git a/bind/testdata/issue10788.go.golden b/bind/testdata/issue10788.go.golden
index f8d1145..165bb70 100644
--- a/bind/testdata/issue10788.go.golden
+++ b/bind/testdata/issue10788.go.golden
@@ -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>
diff --git a/bind/testdata/issue12328.go.golden b/bind/testdata/issue12328.go.golden
index c4804f9..38f4ccd 100644
--- a/bind/testdata/issue12328.go.golden
+++ b/bind/testdata/issue12328.go.golden
@@ -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>
diff --git a/bind/testdata/issue12403.go.golden b/bind/testdata/issue12403.go.golden
index eb83831..2eecfa9 100644
--- a/bind/testdata/issue12403.go.golden
+++ b/bind/testdata/issue12403.go.golden
@@ -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>
diff --git a/bind/testdata/java.go.golden b/bind/testdata/java.go.golden
index 48eefad..1bcd9a8 100644
--- a/bind/testdata/java.go.golden
+++ b/bind/testdata/java.go.golden
@@ -220,7 +220,7 @@
 
 // File is generated by gobind. Do not edit.
 
-package gomobile_bind
+package main
 
 /*
 #include <stdlib.h> // for free()
@@ -495,11 +495,11 @@
 	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>
diff --git a/bind/testdata/keywords.go.golden b/bind/testdata/keywords.go.golden
index d9fba9b..4ad33bc 100644
--- a/bind/testdata/keywords.go.golden
+++ b/bind/testdata/keywords.go.golden
@@ -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>
diff --git a/bind/testdata/objc.go.golden b/bind/testdata/objc.go.golden
index c03ecf1..114aefc 100644
--- a/bind/testdata/objc.go.golden
+++ b/bind/testdata/objc.go.golden
@@ -16,9 +16,8 @@
 
 // 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 @@
 
 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>
diff --git a/bind/testdata/objcw.go.golden b/bind/testdata/objcw.go.golden
index f0f237b..dc5ba55 100644
--- a/bind/testdata/objcw.go.golden
+++ b/bind/testdata/objcw.go.golden
@@ -55,9 +55,8 @@
 
 // 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 @@
 	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>
diff --git a/bind/testdata/structs.go.golden b/bind/testdata/structs.go.golden
index 817ec5d..aab0a35 100644
--- a/bind/testdata/structs.go.golden
+++ b/bind/testdata/structs.go.golden
@@ -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>
diff --git a/bind/testdata/try.go.golden b/bind/testdata/try.go.golden
index 2dfe8e4..f9ef1e4 100644
--- a/bind/testdata/try.go.golden
+++ b/bind/testdata/try.go.golden
@@ -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>
diff --git a/bind/testdata/universe.golden b/bind/testdata/universe.golden
index 5c172ff..12c0507 100644
--- a/bind/testdata/universe.golden
+++ b/bind/testdata/universe.golden
@@ -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>
diff --git a/bind/testdata/vars.go.golden b/bind/testdata/vars.go.golden
index 6158e20..7098222 100644
--- a/bind/testdata/vars.go.golden
+++ b/bind/testdata/vars.go.golden
@@ -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>
diff --git a/cmd/gobind/gen.go b/cmd/gobind/gen.go
index ddfe76a..cb2d3cc 100644
--- a/cmd/gobind/gen.go
+++ b/cmd/gobind/gen.go
@@ -13,7 +13,6 @@
 	"io"
 	"io/ioutil"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"strings"
 	"unicode"
@@ -22,16 +21,23 @@
 	"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 @@
 		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 @@
 					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 @@
 			},
 			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 @@
 	}
 	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
 }
diff --git a/cmd/gobind/main.go b/cmd/gobind/main.go
index 7fe5b67..03f8059 100644
--- a/cmd/gobind/main.go
+++ b/cmd/gobind/main.go
@@ -7,11 +7,8 @@
 import (
 	"flag"
 	"fmt"
-	"go/ast"
 	"go/build"
 	"go/importer"
-	"go/parser"
-	"go/token"
 	"go/types"
 	"io/ioutil"
 	"log"
@@ -22,15 +19,17 @@
 
 	"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 @@
 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 @@
 		}
 		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)
 			}
-			ctx.GOPATH = gopath + tmpGopath
+		}
+		if len(otypes) > 0 {
+			if err := genObjcPackages(srcDir, otypes, orefs.Embedders); err != nil {
+				log.Fatal(err)
+			}
 		}
 	}
 
 	// 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
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index 1c47cda..6024a2e 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -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 @@
 	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 @@
 	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 @@
 
 	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
-}
diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go
index db37139..ee24c95 100644
--- a/cmd/gomobile/bind_androidapp.go
+++ b/cmd/gomobile/bind_androidapp.go
@@ -21,114 +21,44 @@
 	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 @@
 		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 @@
 		out = f
 	}
 
-	src := filepath.Join(androidDir, "src/main/java")
 	return writeJar(out, src)
 }
 
@@ -202,7 +112,7 @@
 //	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 @@
 	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
 	}
 
diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go
index a808fd3..c2b9499 100644
--- a/cmd/gomobile/bind_iosapp.go
+++ b/cmd/gomobile/bind_iosapp.go
@@ -17,30 +17,29 @@
 )
 
 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 @@
 		buildO = title + ".framework"
 	}
 
-	for _, pkg := range binder.pkgs {
-		if err := binder.GenGo(pkg, binder.pkgs, srcDir); err != nil {
-			return err
-		}
+	fileBases := make([]string, len(pkgs)+1)
+	for i, pkg := range pkgs {
+		fileBases[i] = bindPrefix + strings.Title(pkg.Name)
 	}
-	// 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[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 @@
 	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 @@
 	} 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 @@
 		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 @@
     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 @@
 	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
 //
diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go
index b1d1abf..38744c6 100644
--- a/cmd/gomobile/bind_test.go
+++ b/cmd/gomobile/bind_test.go
@@ -55,16 +55,13 @@
 	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 @@
 			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 @@
 
 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 .
 `))