cmd/gomobile,cmd/gobind: allow per-platform bindings again

CL 99316 changed gobind to be platform independent, so
standalone bindings could be generated without having the
Android and Xcode SDKs installed. However, bindings that does
depend on GOOS for its exported API, in particular go source
files that use Cgo now only works if the exported API is
extracted to platform independent files.

By switching to use the source importer, importer.For("source", nil),
gobind can type check the bound packages even in the presence of
Cgo.

The source importer in Go 1.9 and 1.10 has problems with relative
imports and imports from testdata directories (issues 23092 and 24392),
but works from Go 1.10.1 on.

Fixes golang/go#24856

Change-Id: Icb18dce15325b7d4e58cabc1181051bc6269fc1f
Reviewed-on: https://go-review.googlesource.com/99777
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/cmd/gobind/main.go b/cmd/gobind/main.go
index 73552c5..c1f9490 100644
--- a/cmd/gobind/main.go
+++ b/cmd/gobind/main.go
@@ -51,8 +51,7 @@
 	} else {
 		langs = []string{"go", "java", "objc"}
 	}
-	oldCtx := build.Default
-	ctx := &build.Default
+	ctx := build.Default
 	if *tags != "" {
 		ctx.BuildTags = append(ctx.BuildTags, strings.Split(*tags, ",")...)
 	}
@@ -130,19 +129,14 @@
 		}
 	}
 
-	// Make sure the export data for any imported packages are up to date.
-	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 out, err := cmd.CombinedOutput(); err != nil {
-		fmt.Fprintf(os.Stderr, "%s", out)
-		exitStatus = 1
-		return
-	}
-
 	typePkgs := make([]*types.Package, len(allPkg))
-	imp := importer.Default()
+	// The "source" go/importer package implicitly uses build.Default.
+	oldCtx := build.Default
+	build.Default = ctx
+	defer func() {
+		build.Default = oldCtx
+	}()
+	imp := importer.For("source", nil)
 	for i, pkg := range allPkg {
 		var err error
 		typePkgs[i], err = imp.Import(pkg.ImportPath)
@@ -151,7 +145,6 @@
 			return
 		}
 	}
-	build.Default = oldCtx
 	for _, l := range langs {
 		for _, pkg := range typePkgs {
 			genPkg(l, pkg, typePkgs, classes, otypes)
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index 0d22d7d..248db89 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -97,6 +97,10 @@
 		return errors.New("no Android NDK path is set. Please run gomobile init with the ndk-bundle installed through the Android SDK manager or with the -ndk flag set.")
 	}
 
+	if ctx.GOOS == "darwin" {
+		ctx.BuildTags = append(ctx.BuildTags, "ios")
+	}
+
 	var gobind string
 	if !buildN {
 		gobind, err = exec.LookPath("gobind")
diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go
index 145df64..2f65333 100644
--- a/cmd/gomobile/bind_androidapp.go
+++ b/cmd/gomobile/bind_androidapp.go
@@ -33,6 +33,7 @@
 		"-lang=go,java",
 		"-outdir="+tmpdir,
 	)
+	cmd.Env = append(cmd.Env, "GOOS=android")
 	if len(ctx.BuildTags) > 0 {
 		cmd.Args = append(cmd.Args, "-tags="+strings.Join(ctx.BuildTags, ","))
 	}
diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go
index f8c4fdf..97fc670 100644
--- a/cmd/gomobile/bind_iosapp.go
+++ b/cmd/gomobile/bind_iosapp.go
@@ -21,6 +21,7 @@
 		"-lang=go,objc",
 		"-outdir="+tmpdir,
 	)
+	cmd.Env = append(cmd.Env, "GOOS=darwin")
 	if len(ctx.BuildTags) > 0 {
 		cmd.Args = append(cmd.Args, "-tags="+strings.Join(ctx.BuildTags, ","))
 	}
@@ -34,8 +35,6 @@
 		return err
 	}
 
-	ctx.BuildTags = append(ctx.BuildTags, "ios")
-
 	srcDir := filepath.Join(tmpdir, "src", "gobind")
 	gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH"))
 
diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go
index 1825666..62adf38 100644
--- a/cmd/gomobile/bind_test.go
+++ b/cmd/gomobile/bind_test.go
@@ -175,7 +175,7 @@
 
 var bindAndroidTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
 WORK=$WORK
-gobind -lang=go,java -outdir=$WORK{{if .JavaPkg}} -javapkg={{.JavaPkg}}{{end}} golang.org/x/mobile/asset
+GOOS=android gobind -lang=go,java -outdir=$WORK{{if .JavaPkg}} -javapkg={{.JavaPkg}}{{end}} golang.org/x/mobile/asset
 GOOS=android GOARCH=arm CC=$GOMOBILE/ndk-toolchains/arm/bin/arm-linux-androideabi-clang CXX=$GOMOBILE/ndk-toolchains/arm/bin/arm-linux-androideabi-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH go build -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 .
@@ -183,7 +183,7 @@
 
 var bindIOSTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
 WORK=$WORK
-gobind -lang=go,objc -outdir=$WORK{{if .Prefix}} -prefix={{.Prefix}}{{end}} golang.org/x/mobile/asset
+GOOS=darwin gobind -lang=go,objc -outdir=$WORK{{if .Prefix}} -prefix={{.Prefix}}{{end}} golang.org/x/mobile/asset
 GOARM=7 GOOS=darwin GOARCH=arm CC=clang-iphoneos CXX=clang-iphoneos CGO_CFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch armv7 CGO_LDFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch armv7 CGO_ENABLED=1 GOPATH=$WORK:$GOPATH go build -tags ios -x -buildmode=c-archive -o $WORK/asset-arm.a gobind
 rm -r -f "Asset.framework"
 mkdir -p Asset.framework/Versions/A/Headers