cmd/gomobile: change the working directory to $WORK/src/gobind when go-building

This is a preparation to enable Go modules for gomobile commands.

When Go modules is used, $GOPATH is not available. To build a
local package with Go modules, changing the working directory and
specifying the package by a relative path begining with `./` is
required. Changing the working directory is necessary because
building outside of modules is forbidden.

Specifying $GOPATH is still needed for reverse bindings (i.e.
special packages begining with `Java/` or `ObjC/`). Note that
gomobile with Go modules cannot support reverse bindings so far.

Updates golang/go#27234

Change-Id: Ib19300e1b8a973e76e06d24472c63a98605d65f7
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/209137
Run-TryBot: Hajime Hoshi <hajimehoshi@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go
index f2f36b4..0ccb079 100644
--- a/cmd/gomobile/bind_androidapp.go
+++ b/cmd/gomobile/bind_androidapp.go
@@ -55,13 +55,14 @@
 	// Generate binding code and java source code only when processing the first package.
 	for _, arch := range androidArchs {
 		env := androidEnv[arch]
-		// Add the generated packages to GOPATH
+		// Add the generated packages to GOPATH for reverse bindings.
 		gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH"))
 		env = append(env, gopath)
 		toolchain := ndk.Toolchain(arch)
 
-		err := goBuild(
-			"gobind",
+		err := goBuildAt(
+			filepath.Join(tmpdir, "src"),
+			"./gobind",
 			env,
 			"-buildmode=c-shared",
 			"-o="+filepath.Join(androidDir, "src/main/jniLibs/"+toolchain.abi+"/libgojni.so"),
diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go
index 53b5591..4140731 100644
--- a/cmd/gomobile/bind_iosapp.go
+++ b/cmd/gomobile/bind_iosapp.go
@@ -37,7 +37,6 @@
 	}
 
 	srcDir := filepath.Join(tmpdir, "src", "gobind")
-	gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH"))
 
 	name := pkgs[0].Name
 	title := strings.Title(name)
@@ -59,8 +58,10 @@
 
 	for _, arch := range archs {
 		env := darwinEnv[arch]
+		// Add the generated packages to GOPATH for reverse bindings.
+		gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH"))
 		env = append(env, gopath)
-		path, err := goIOSBindArchive(name, env)
+		path, err := goIOSBindArchive(name, env, filepath.Join(tmpdir, "src"))
 		if err != nil {
 			return fmt.Errorf("darwin-%s: %v", arch, err)
 		}
@@ -174,14 +175,13 @@
     export *
 }`))
 
-func goIOSBindArchive(name string, env []string) (string, error) {
+func goIOSBindArchive(name string, env []string, gosrc string) (string, error) {
 	arch := getenv(env, "GOARCH")
 	archive := filepath.Join(tmpdir, name+"-"+arch+".a")
-	err := goBuild("gobind", env, "-buildmode=c-archive", "-o", archive)
+	err := goBuildAt(gosrc, "./gobind", env, "-buildmode=c-archive", "-o", archive)
 	if err != nil {
 		return "", err
 	}
-
 	return archive, nil
 }
 
diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go
index bb3e20c..d31c4fd 100644
--- a/cmd/gomobile/bind_test.go
+++ b/cmd/gomobile/bind_test.go
@@ -179,7 +179,7 @@
 var bindAndroidTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
 WORK=$WORK
 GOOS=android CGO_ENABLED=1 gobind -lang=go,java -outdir=$WORK{{if .JavaPkg}} -javapkg={{.JavaPkg}}{{end}} golang.org/x/mobile/asset
-GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH GO111MODULE=off go build -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so gobind
+PWD=$WORK/src GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.NDKARCH}}/bin/armv7a-linux-androideabi16-clang++ CGO_ENABLED=1 GOARM=7 GOPATH=$WORK:$GOPATH GO111MODULE=off 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 .
 `))
@@ -187,7 +187,7 @@
 var bindIOSTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
 WORK=$WORK
 GOOS=darwin CGO_ENABLED=1 gobind -lang=go,objc -outdir=$WORK -tags=ios{{if .Prefix}} -prefix={{.Prefix}}{{end}} golang.org/x/mobile/asset
-GOARM=7 GOOS=darwin GOARCH=arm CC=iphoneos-clang CXX=iphoneos-clang++ CGO_CFLAGS=-isysroot=iphoneos -miphoneos-version-min=7.0 -fembed-bitcode -arch armv7 CGO_CXXFLAGS=-isysroot=iphoneos -miphoneos-version-min=7.0 -fembed-bitcode -arch armv7 CGO_LDFLAGS=-isysroot=iphoneos -miphoneos-version-min=7.0 -fembed-bitcode -arch armv7 CGO_ENABLED=1 GOPATH=$WORK:$GOPATH GO111MODULE=off go build -tags ios -x -buildmode=c-archive -o $WORK/asset-arm.a gobind
+PWD=$WORK/src GOARM=7 GOOS=darwin GOARCH=arm CC=iphoneos-clang CXX=iphoneos-clang++ CGO_CFLAGS=-isysroot=iphoneos -miphoneos-version-min=7.0 -fembed-bitcode -arch armv7 CGO_CXXFLAGS=-isysroot=iphoneos -miphoneos-version-min=7.0 -fembed-bitcode -arch armv7 CGO_LDFLAGS=-isysroot=iphoneos -miphoneos-version-min=7.0 -fembed-bitcode -arch armv7 CGO_ENABLED=1 GOPATH=$WORK:$GOPATH GO111MODULE=off 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
 ln -s A Asset.framework/Versions/Current
diff --git a/cmd/gomobile/build.go b/cmd/gomobile/build.go
index 208a174..f4b8c09 100644
--- a/cmd/gomobile/build.go
+++ b/cmd/gomobile/build.go
@@ -279,11 +279,19 @@
 	return goCmd("build", []string{src}, env, args...)
 }
 
+func goBuildAt(at string, src string, env []string, args ...string) error {
+	return goCmdAt(at, "build", []string{src}, env, args...)
+}
+
 func goInstall(srcs []string, env []string, args ...string) error {
 	return goCmd("install", srcs, env, args...)
 }
 
 func goCmd(subcmd string, srcs []string, env []string, args ...string) error {
+	return goCmdAt("", subcmd, srcs, env, args...)
+}
+
+func goCmdAt(at string, subcmd string, srcs []string, env []string, args ...string) error {
 	cmd := exec.Command(
 		goBin(),
 		subcmd,
@@ -325,6 +333,7 @@
 	cmd.Env = append([]string{}, env...)
 	// gomobile does not support modules yet.
 	cmd.Env = append(cmd.Env, "GO111MODULE=off")
+	cmd.Dir = at
 	return runCmd(cmd)
 }