cmd/gomobile,internal: add bootclasspath and classpath flags to gomobile

Add -bootclasspath and -classpath flags to the gomobile tool. In a
follow-up CL, the gobind gradle plugin will use them to support R and
databinding classes from Go.

Change-Id: Id33acf0c3fe1ec3908740b2a736ed241fa6391c2
Reviewed-on: https://go-review.googlesource.com/30092
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/bind/bind_test.go b/bind/bind_test.go
index df52cc1..c61f18c 100644
--- a/bind/bind_test.go
+++ b/bind/bind_test.go
@@ -208,7 +208,7 @@
 	}
 	for _, filename := range allTests {
 		refs := fileRefs(t, filename)
-		classes, err := java.Import("", refs)
+		classes, err := java.Import("", "", refs)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -301,7 +301,7 @@
 	for _, filename := range allTests {
 		var buf bytes.Buffer
 		refs := fileRefs(t, filename)
-		classes, err := java.Import("", refs)
+		classes, err := java.Import("", "", refs)
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index 4c09609..1659d8b 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -29,7 +29,7 @@
 var cmdBind = &command{
 	run:   runBind,
 	Name:  "bind",
-	Usage: "[-target android|ios] [-o output] [build flags] [package]",
+	Usage: "[-target android|ios] [-bootclasspath <path>] [-classpath <path>] [-o output] [build flags] [package]",
 	Short: "build a library for Android and iOS",
 	Long: `
 Bind generates language bindings for the package named by the import
@@ -62,6 +62,10 @@
 installed. Support is not complete. The generated Objective-C types
 are prefixed with 'Go' unless the -prefix flag is provided.
 
+For -target android, the -bootclasspath and -classpath flags are used to
+control the bootstrap classpath and the classpath for Go wrappers to Java
+classes.
+
 The -v flag provides verbose output, including the list of packages built.
 
 The build flags -a, -n, -x, -gcflags, -ldflags, -tags, and -work
@@ -135,8 +139,10 @@
 }
 
 var (
-	bindPrefix  string // -prefix
-	bindJavaPkg string // -javapkg
+	bindPrefix        string // -prefix
+	bindJavaPkg       string // -javapkg
+	bindClasspath     string // -classpath
+	bindBootClasspath string // -bootclasspath
 )
 
 func init() {
@@ -144,7 +150,9 @@
 	cmdBind.flag.StringVar(&bindJavaPkg, "javapkg", "",
 		"specifies custom Java package path prefix used instead of the default 'go'. Valid only with -target=android.")
 	cmdBind.flag.StringVar(&bindPrefix, "prefix", "",
-		"custom Objective-C name prefix used instead of the default 'Go'. Valid only with -lang=ios.")
+		"custom Objective-C name prefix used instead of the default 'Go'. Valid only with -target=ios.")
+	cmdBind.flag.StringVar(&bindClasspath, "classpath", "", "The classpath for imported Java classes. Valid only with -target=android.")
+	cmdBind.flag.StringVar(&bindBootClasspath, "bootclasspath", "", "The bootstrap classpath for imported Java classes. Valid only with -target=android.")
 }
 
 type binder struct {
@@ -254,16 +262,27 @@
 	return copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(javaPkg.Dir, "seq.h"))
 }
 
-func GenClasses(pkgs []*build.Package, srcDir, jpkgSrc string) ([]*java.Class, error) {
+func bootClasspath() (string, error) {
+	if bindBootClasspath != "" {
+		return bindBootClasspath, nil
+	}
 	apiPath, err := androidAPIPath()
 	if err != nil {
-		return nil, err
+		return "", err
 	}
+	return filepath.Join(apiPath, "android.jar"), nil
+}
+
+func GenClasses(pkgs []*build.Package, srcDir, jpkgSrc string) ([]*java.Class, error) {
 	refs, err := importers.AnalyzePackages(pkgs, "Java/")
 	if err != nil {
 		return nil, err
 	}
-	classes, err := java.Import(filepath.Join(apiPath, "android.jar"), refs)
+	bClspath, err := bootClasspath()
+	if err != nil {
+		return nil, err
+	}
+	classes, err := java.Import(bClspath, bindClasspath, refs)
 	if err != nil {
 		return nil, err
 	}
diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go
index b35c779..cad67c5 100644
--- a/cmd/gomobile/bind_androidapp.go
+++ b/cmd/gomobile/bind_androidapp.go
@@ -342,7 +342,8 @@
 		}
 	}
 
-	apiPath, err := androidAPIPath()
+	bClspath, err := bootClasspath()
+
 	if err != nil {
 		return err
 	}
@@ -351,8 +352,12 @@
 		"-d", dst,
 		"-source", javacTargetVer,
 		"-target", javacTargetVer,
-		"-bootclasspath", filepath.Join(apiPath, "android.jar"),
+		"-bootclasspath", bClspath,
 	}
+	if bindClasspath != "" {
+		args = append(args, "-classpath", bindClasspath)
+	}
+
 	args = append(args, srcFiles...)
 
 	javac := exec.Command("javac", args...)
diff --git a/internal/importers/java/java.go b/internal/importers/java/java.go
index 233a022..0eb4764 100644
--- a/internal/importers/java/java.go
+++ b/internal/importers/java/java.go
@@ -94,8 +94,9 @@
 type TypeKind int
 
 type importer struct {
-	clspath string
-	clsMap  map[string]*Class
+	bootclspath string
+	clspath     string
+	clsMap      map[string]*Class
 }
 
 const (
@@ -147,10 +148,11 @@
 //   ...
 //
 // }
-func Import(classpath string, refs *importers.References) ([]*Class, error) {
+func Import(bootclasspath, classpath string, refs *importers.References) ([]*Class, error) {
 	imp := &importer{
-		clspath: classpath,
-		clsMap:  make(map[string]*Class),
+		bootclspath: bootclasspath,
+		clspath:     classpath,
+		clsMap:      make(map[string]*Class),
 	}
 	clsSet := make(map[string]struct{})
 	var names []string
@@ -355,7 +357,10 @@
 	}
 	args := []string{"-s", "-protected", "-constants"}
 	if j.clspath != "" {
-		args = append(args, "-bootclasspath", j.clspath)
+		args = append(args, "-classpath", j.clspath)
+	}
+	if j.bootclspath != "" {
+		args = append(args, "-bootclasspath", j.bootclspath)
 	}
 	args = append(args, names...)
 	javapPath, err := javapPath()