cmd/gomobile: use standalone NDK toolchains

Issue golang/go#24058 demonstrates a Go package that fails to build with
gomobile but builds successfully with a manually using the standalone NDK
toolchain. I haven't been able to figure out a set of CPPFLAGS/LDFLAGS
that fixes the build for 24058 so instead rework gomobile to use
standalone NDK toolchains.

Standalone toolchains fixes the 24058 build and is the official way
to build Android programs. So gomobile should be less affected by
future changes in the NDK toolchain internals.

Create the standalone toolchains with gomobile init.

With the new Go 1.10 build cache, the prebuild work by the gomobile
init command is useless. Use the opportunity to simplify init to
only creating NDK toolchains and, optionally, building OpenAL for
Android. With that, it is no longer necessary to use gomobile init
to build iOS apps and frameworks.

Fixes golang/go#24058

Change-Id: I4692fcaa927e7076a6387d080ebc1726905afd72
Reviewed-on: https://go-review.googlesource.com/99875
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/bind/objc/seq_test.go b/bind/objc/seq_test.go
index 941d6e4..d5afa34 100644
--- a/bind/objc/seq_test.go
+++ b/bind/objc/seq_test.go
@@ -14,7 +14,6 @@
 	"path/filepath"
 	"strings"
 	"testing"
-	"time"
 )
 
 // Use the Xcode XCTestCase framework to run the SeqTest.m tests and the SeqBench.m benchmarks.
@@ -69,12 +68,6 @@
 		if _, err := run("go install golang.org/x/mobile/cmd/gomobile"); err != nil {
 			t.Fatalf("gomobile install failed: %v", err)
 		}
-		t.Log("gomobile init")
-		start := time.Now()
-		if _, err := run("gomobile init"); err != nil {
-			t.Fatalf("gomobile init failed: %v", err)
-		}
-		t.Logf("gomobile init took %v", time.Since(start))
 	}
 
 	cwd, err := os.Getwd()
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index 6024a2e..410fc4e 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -92,7 +92,7 @@
 		return fmt.Errorf("-prefix is supported only for ios target")
 	}
 
-	if ctx.GOOS == "android" && ndkRoot == "" {
+	if ctx.GOOS == "android" && !hasNDK() {
 		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.")
 	}
 
diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go
index 38744c6..729fda1 100644
--- a/cmd/gomobile/bind_test.go
+++ b/cmd/gomobile/bind_test.go
@@ -50,7 +50,6 @@
 	buildX = true
 	buildO = "asset.aar"
 	buildTarget = "android/arm"
-	ndkRoot = "/NDK"
 
 	tests := []struct {
 		javaPkg    string
@@ -113,7 +112,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 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
+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 .
 `))
diff --git a/cmd/gomobile/build.go b/cmd/gomobile/build.go
index 2fa32d7..6ee55f2 100644
--- a/cmd/gomobile/build.go
+++ b/cmd/gomobile/build.go
@@ -272,7 +272,6 @@
 	cmd := exec.Command(
 		"go",
 		subcmd,
-		"-pkgdir="+pkgdir(env),
 	)
 	if len(ctx.BuildTags) > 0 {
 		cmd.Args = append(cmd.Args, "-tags", strings.Join(ctx.BuildTags, " "))
diff --git a/cmd/gomobile/build_androidapp.go b/cmd/gomobile/build_androidapp.go
index a1f07cb..d0d7955 100644
--- a/cmd/gomobile/build_androidapp.go
+++ b/cmd/gomobile/build_androidapp.go
@@ -25,7 +25,7 @@
 )
 
 func goAndroidBuild(pkg *build.Package, androidArchs []string) (map[string]bool, error) {
-	if ndkRoot == "" {
+	if !hasNDK() {
 		return nil, 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.")
 	}
 	appName := path.Base(pkg.ImportPath)
diff --git a/cmd/gomobile/build_darwin_test.go b/cmd/gomobile/build_darwin_test.go
index 00097a0..3bc8ef4 100644
--- a/cmd/gomobile/build_darwin_test.go
+++ b/cmd/gomobile/build_darwin_test.go
@@ -72,8 +72,8 @@
 echo "{{template "infoplist" .Xinfo}}" > $WORK/main/Info.plist
 mkdir -p $WORK/main/Images.xcassets/AppIcon.appiconset
 echo "{{.Xcontents}}" > $WORK/main/Images.xcassets/AppIcon.appiconset/Contents.json
-GOOS=darwin GOARCH=arm GOARM=7 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 go build -pkgdir=$GOMOBILE/pkg_darwin_arm -tags tag1 ios -x -o=$WORK/arm golang.org/x/mobile/example/basic
-GOOS=darwin GOARCH=arm64 CC=clang-iphoneos CXX=clang-iphoneos CGO_CFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch arm64 CGO_LDFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch arm64 CGO_ENABLED=1 go build -pkgdir=$GOMOBILE/pkg_darwin_arm64 -tags tag1 ios -x -o=$WORK/arm64 golang.org/x/mobile/example/basic
+GOOS=darwin GOARCH=arm GOARM=7 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 go build -tags tag1 ios -x -o=$WORK/arm golang.org/x/mobile/example/basic
+GOOS=darwin GOARCH=arm64 CC=clang-iphoneos CXX=clang-iphoneos CGO_CFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch arm64 CGO_LDFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch arm64 CGO_ENABLED=1 go build -tags tag1 ios -x -o=$WORK/arm64 golang.org/x/mobile/example/basic
 xcrun lipo -create $WORK/arm $WORK/arm64 -o $WORK/main/main
 mkdir -p $WORK/main/assets
 xcrun xcodebuild -configuration Release -project $WORK/main.xcodeproj -allowProvisioningUpdates DEVELOPMENT_TEAM={{.TeamID}}
diff --git a/cmd/gomobile/build_test.go b/cmd/gomobile/build_test.go
index b09a167..9bd8ff4 100644
--- a/cmd/gomobile/build_test.go
+++ b/cmd/gomobile/build_test.go
@@ -76,7 +76,6 @@
 	buildX = true
 	buildO = "basic.apk"
 	buildTarget = "android/arm"
-	ndkRoot = "/NDK"
 	gopath = filepath.ToSlash(filepath.SplitList(os.Getenv("GOPATH"))[0])
 	if goos == "windows" {
 		os.Setenv("HOMEDRIVE", "C:")
@@ -101,7 +100,7 @@
 var androidBuildTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
 WORK=$WORK
 mkdir -p $WORK/lib/armeabi-v7a
-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 go build -pkgdir=$GOMOBILE/pkg_android_arm -tags tag1 -x -buildmode=c-shared -o $WORK/lib/armeabi-v7a/libbasic.so golang.org/x/mobile/example/basic
+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 go build -tags tag1 -x -buildmode=c-shared -o $WORK/lib/armeabi-v7a/libbasic.so golang.org/x/mobile/example/basic
 `))
 
 func TestParseBuildTargetFlag(t *testing.T) {
diff --git a/cmd/gomobile/env.go b/cmd/gomobile/env.go
index a87c332..45bd9a1 100644
--- a/cmd/gomobile/env.go
+++ b/cmd/gomobile/env.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"bytes"
 	"errors"
 	"fmt"
 	"io/ioutil"
@@ -27,8 +26,6 @@
 	androidArmNM string
 	darwinArmNM  string
 
-	ndkRoot string
-
 	archs = []string{"arm", "arm64", "386", "amd64"}
 )
 
@@ -52,22 +49,6 @@
 		return nil, errors.New("toolchain not installed, run `gomobile init`")
 	}
 
-	// Read the NDK root path stored by gomobile init -ndk, if any.
-	if !buildN {
-		root, err := ioutil.ReadFile(filepath.Join(gomobilepath, "android_ndk_root"))
-		if err != nil && !os.IsNotExist(err) {
-			return nil, err
-		}
-		ndkRoot = string(root)
-		if ndkRoot != "" {
-			if _, err := os.Stat(filepath.Join(ndkRoot, "toolchains")); err != nil {
-				if os.IsNotExist(err) {
-					return nil, fmt.Errorf("The ndk path %q doesn't exist. Please re-run gomobile with the ndk-bundle install through the Android SDK manager or with the -ndk flag set.", ndkRoot)
-				}
-				return nil, err
-			}
-		}
-	}
 	if err := envInit(); err != nil {
 		return nil, err
 	}
@@ -83,15 +64,6 @@
 		tmpdir = "$WORK"
 		cleanupFn = func() {}
 	} else {
-		verpath := filepath.Join(gomobilepath, "version")
-		installedVersion, err := ioutil.ReadFile(verpath)
-		if err != nil {
-			return nil, errors.New("toolchain partially installed, run `gomobile init`")
-		}
-		if !bytes.Equal(installedVersion, goVersionOut) {
-			return nil, errors.New("toolchain out of date, run `gomobile init`")
-		}
-
 		tmpdir, err = ioutil.TempDir("", "gomobile-work-")
 		if err != nil {
 			return nil, err
@@ -112,31 +84,14 @@
 	}
 
 	// Setup the cross-compiler environments.
-
-	if ndkRoot != "" {
+	if hasNDK() {
 		androidEnv = make(map[string][]string)
 		for arch, toolchain := range ndk {
-			// Emulate the flags in the clang wrapper scripts generated
-			// by make_standalone_toolchain.py
-			s := strings.SplitN(toolchain.toolPrefix, "-", 3)
-			a, os, env := s[0], s[1], s[2]
-			if a == "arm" {
-				a = "armv7a"
-			}
-			androidApi := strings.TrimPrefix(toolchain.platform, "android-")
-			target := strings.Join([]string{a, "none", os, env}, "-")
-			gcctoolchain := filepath.Join(ndkRoot, "toolchains", toolchain.gcc, "prebuilt", archNDK())
-			flags := fmt.Sprintf("-target %s -gcc-toolchain %s", target, gcctoolchain)
-			cflags := fmt.Sprintf("%s --sysroot %s/sysroot -isystem %s/sysroot/usr/include/%s -D__ANDROID_API__=%s -I%s/include", flags, ndkRoot, ndkRoot, toolchain.toolPrefix, androidApi, gomobilepath)
-			ldflags := fmt.Sprintf("%s --sysroot %s/platforms/%s/arch-%s -L%s/lib/%s", flags, ndkRoot, toolchain.platform, toolchain.arch, gomobilepath, arch)
 			androidEnv[arch] = []string{
 				"GOOS=android",
 				"GOARCH=" + arch,
 				"CC=" + toolchain.Path("clang"),
 				"CXX=" + toolchain.Path("clang++"),
-				"CGO_CFLAGS=" + cflags,
-				"CGO_CPPFLAGS=" + cflags,
-				"CGO_LDFLAGS=" + ldflags,
 				"CGO_ENABLED=1",
 			}
 			if arch == "arm" {
@@ -200,6 +155,15 @@
 	return nil
 }
 
+func hasNDK() bool {
+	if buildN {
+		return true
+	}
+	tcPath := filepath.Join(gomobilepath, "ndk-toolchains")
+	_, err := os.Stat(tcPath)
+	return err == nil
+}
+
 func envClang(sdkName string) (clang, cflags string, err error) {
 	if buildN {
 		return "clang-" + sdkName, "-isysroot=" + sdkName, nil
@@ -282,10 +246,6 @@
 	return ""
 }
 
-func pkgdir(env []string) string {
-	return gomobilepath + "/pkg_" + getenv(env, "GOOS") + "_" + getenv(env, "GOARCH")
-}
-
 func archNDK() string {
 	if runtime.GOOS == "windows" && runtime.GOARCH == "386" {
 		return "windows"
@@ -312,20 +272,7 @@
 }
 
 func (tc *ndkToolchain) Path(toolName string) string {
-	// The nm tool is located in the GCC directory structure.
-	isUtil := toolName == "nm"
-	if goos == "windows" {
-		toolName += ".exe"
-	}
-	path := filepath.Join(ndkRoot, "toolchains")
-	if isUtil {
-		toolName = tc.toolPrefix + "-" + toolName
-		path = filepath.Join(path, tc.gcc)
-	} else {
-		path = filepath.Join(path, "llvm")
-	}
-	path = filepath.Join(path, "prebuilt")
-	return filepath.Join(path, archNDK(), "bin", toolName)
+	return filepath.Join(gomobilepath, "ndk-toolchains", tc.arch, "bin", tc.toolPrefix+"-"+toolName)
 }
 
 type ndkConfig map[string]ndkToolchain // map: GOOS->androidConfig.
diff --git a/cmd/gomobile/init.go b/cmd/gomobile/init.go
index 67ae251..ba040cd 100644
--- a/cmd/gomobile/init.go
+++ b/cmd/gomobile/init.go
@@ -19,34 +19,22 @@
 )
 
 var (
-	goos    = runtime.GOOS
-	goarch  = runtime.GOARCH
-	ndkarch string
+	goos   = runtime.GOOS
+	goarch = runtime.GOARCH
 )
 
-func init() {
-	switch runtime.GOARCH {
-	case "amd64":
-		ndkarch = "x86_64"
-	case "386":
-		ndkarch = "x86"
-	default:
-		ndkarch = runtime.GOARCH
-	}
-}
-
 var cmdInit = &command{
 	run:   runInit,
 	Name:  "init",
-	Usage: "[-u]",
-	Short: "install mobile compiler toolchain",
+	Usage: "[-ndk dir] [-openal dir]",
+	Short: "install NDK toolchains and build OpenAL for Android",
 	Long: `
-Init builds copies of the Go standard library for mobile devices.
-It uses Xcode, if available, to build for iOS and uses the Android
-NDK from the ndk-bundle SDK package or from the -ndk flag, to build
-for Android.
+If the -ndk flag is specified or the Android NDK is installed at
+$ANDROID_HOME/ndk-bundle, init will create NDK standalone toolchains
+for Android targets.
+
 If a OpenAL source directory is specified with -openal, init will
-also build an Android version of OpenAL for use with gomobile build
+build an Android version of OpenAL for use with gomobile build
 and gomobile install.
 `,
 }
@@ -68,7 +56,6 @@
 	}
 	gomobilepath = filepath.Join(gopaths[0], "pkg/gomobile")
 
-	verpath := filepath.Join(gomobilepath, "version")
 	if buildX || buildN {
 		fmt.Fprintln(xout, "GOMOBILE="+gomobilepath)
 	}
@@ -124,10 +111,6 @@
 				}
 				return err
 			}
-			ndkFile := filepath.Join(gomobilepath, "android_ndk_root")
-			if err := ioutil.WriteFile(ndkFile, []byte(initNDK), 0644); err != nil {
-				return err
-			}
 		}
 		if initOpenAL != "" {
 			var err error
@@ -136,41 +119,13 @@
 			}
 		}
 	}
-	ndkRoot = initNDK
 	if err := envInit(); err != nil {
 		return err
 	}
 
-	if runtime.GOOS == "darwin" {
-		// Install common x/mobile packages for local development.
-		// These are often slow to compile (due to cgo) and easy to forget.
-		//
-		// Limited to darwin for now as it is common for linux to
-		// not have GLES installed.
-		//
-		// TODO: consider testing GLES installation and suggesting it here
-		for _, pkg := range commonPkgs {
-			if err := installPkg(pkg, nil); err != nil {
-				return err
-			}
-		}
-	}
-
-	// Install standard libraries for cross compilers.
 	start := time.Now()
-	if ndkRoot != "" {
-		// Ideally this would be -buildmode=c-shared.
-		// https://golang.org/issue/13234.
-		androidArgs := []string{"-gcflags=-shared", "-ldflags=-shared"}
-		for _, arch := range archs {
-			env := androidEnv[arch]
-			if err := installStd(env, androidArgs...); err != nil {
-				return err
-			}
-		}
-	}
 
-	if err := installDarwin(); err != nil {
+	if err := installNDKToolchains(gomobilepath); err != nil {
 		return err
 	}
 
@@ -178,14 +133,6 @@
 		return err
 	}
 
-	if buildX || buildN {
-		printcmd("go version > %s", verpath)
-	}
-	if !buildN {
-		if err := ioutil.WriteFile(verpath, goVersionOut, 0644); err != nil {
-			return err
-		}
-	}
 	if buildV {
 		took := time.Since(start) / time.Second * time.Second
 		fmt.Fprintf(os.Stderr, "\nDone, build took %s.\n", took)
@@ -193,8 +140,32 @@
 	return nil
 }
 
+func installNDKToolchains(gomobilepath string) error {
+	if initNDK == "" {
+		return nil
+	}
+	toolsDir := filepath.Join(initNDK, "prebuilt", archNDK(), "bin")
+	py27 := filepath.Join(toolsDir, "python2.7")
+	for _, arch := range archs {
+		t := ndk[arch]
+		// Split android-XX to get the api version.
+		platform := strings.SplitN(t.platform, "-", 2)
+		api := platform[1]
+		cmd := exec.Command(py27,
+			"build/tools/make_standalone_toolchain.py",
+			"--arch="+t.arch,
+			"--api="+api,
+			"--install-dir="+filepath.Join(gomobilepath, "ndk-toolchains", t.arch))
+		cmd.Dir = initNDK
+		if err := runCmd(cmd); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 func installOpenAL(gomobilepath string) error {
-	if ndkRoot == "" || initOpenAL == "" {
+	if initNDK == "" || initOpenAL == "" {
 		return nil
 	}
 	var cmake string
@@ -246,48 +217,27 @@
 		}
 	}
 
-	toolsDir := filepath.Join(ndkRoot, "prebuilt", archNDK(), "bin")
-	py27 := filepath.Join(toolsDir, "python2.7")
-	var make string
-	if !buildN && runtime.GOOS == "windows" {
-		var err error
-		make, err = exec.LookPath("nmake")
-		if err != nil {
-			return nil
-		}
-	} else {
-		make = filepath.Join(toolsDir, "make")
-	}
 	for _, arch := range archs {
 		t := ndk[arch]
 		abi := t.arch
 		if abi == "arm" {
 			abi = "armeabi"
 		}
+		tcPath := filepath.Join(gomobilepath, "ndk-toolchains", t.arch, "bin")
+		make := filepath.Join(tcPath, "make")
 		// Split android-XX to get the api version.
-		platform := strings.SplitN(t.platform, "-", 2)
-		api := platform[1]
 		buildDir := alTmpDir + "/build/" + abi
-		toolchain := buildDir + "/toolchain"
-		// standalone ndk toolchains make openal-soft's build config easier.
-		cmd := exec.Command(py27,
-			"build/tools/make_standalone_toolchain.py",
-			"--arch="+t.arch,
-			"--api="+api,
-			"--install-dir="+toolchain)
-		cmd.Dir = ndkRoot
-		if err := runCmd(cmd); err != nil {
+		if err := mkdir(buildDir); err != nil {
 			return err
 		}
-
-		cmd = exec.Command(cmake,
+		cmd := exec.Command(cmake,
 			initOpenAL,
 			"-DCMAKE_TOOLCHAIN_FILE="+initOpenAL+"/XCompile-Android.txt",
 			"-DHOST="+t.toolPrefix)
 		cmd.Dir = buildDir
-		orgPath := os.Getenv("PATH")
 		if !buildN {
-			cmd.Env = []string{"PATH=" + toolchain + "/bin" + string(os.PathListSeparator) + orgPath}
+			orgPath := os.Getenv("PATH")
+			cmd.Env = []string{"PATH=" + tcPath + string(os.PathListSeparator) + orgPath}
 		}
 		if err := runCmd(cmd); err != nil {
 			return err
@@ -314,56 +264,6 @@
 	"golang.org/x/mobile/exp/app/debug",
 }
 
-func installDarwin() error {
-	if !xcodeAvailable() {
-		return nil
-	}
-	if err := installStd(darwinArmEnv); err != nil {
-		return err
-	}
-	if err := installStd(darwinArm64Env); err != nil {
-		return err
-	}
-	// TODO(crawshaw): darwin/386 for the iOS simulator?
-	if err := installStd(darwinAmd64Env, "-tags=ios"); err != nil {
-		return err
-	}
-	return nil
-}
-
-func installStd(env []string, args ...string) error {
-	return installPkg("std", env, args...)
-}
-
-func installPkg(pkg string, env []string, args ...string) error {
-	tOS, tArch, pd := getenv(env, "GOOS"), getenv(env, "GOARCH"), pkgdir(env)
-	if tOS != "" && tArch != "" {
-		if buildV {
-			fmt.Fprintf(os.Stderr, "\n# Installing %s for %s/%s.\n", pkg, tOS, tArch)
-		}
-		args = append(args, "-pkgdir="+pd)
-	} else {
-		if buildV {
-			fmt.Fprintf(os.Stderr, "\n# Installing %s.\n", pkg)
-		}
-	}
-
-	cmd := exec.Command("go", "install")
-	cmd.Args = append(cmd.Args, args...)
-	if buildV {
-		cmd.Args = append(cmd.Args, "-v")
-	}
-	if buildX {
-		cmd.Args = append(cmd.Args, "-x")
-	}
-	if buildWork {
-		cmd.Args = append(cmd.Args, "-work")
-	}
-	cmd.Args = append(cmd.Args, pkg)
-	cmd.Env = append([]string{}, env...)
-	return runCmd(cmd)
-}
-
 func mkdir(dir string) error {
 	if buildX || buildN {
 		printcmd("mkdir -p %s", dir)
diff --git a/cmd/gomobile/init_test.go b/cmd/gomobile/init_test.go
index 05aca04..d8488e1 100644
--- a/cmd/gomobile/init_test.go
+++ b/cmd/gomobile/init_test.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"os"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"testing"
 	"text/template"
@@ -41,7 +42,6 @@
 		os.Setenv("HOMEDRIVE", "C:")
 	}
 
-	// TODO(hyangah): test with go1_6.
 	err := runInit(cmdInit)
 	if err != nil {
 		t.Log(buf.String())
@@ -88,7 +88,7 @@
 		GOOS:      goos,
 		GOARCH:    goarch,
 		GOPATH:    gopath,
-		NDKARCH:   ndkarch,
+		NDKARCH:   ndkarch(),
 		Xproj:     projPbxproj,
 		Xcontents: contentsJSON,
 		Xinfo:     infoplistTmplData{BundleID: "org.golang.todo.basic", Name: "Basic"},
@@ -99,44 +99,48 @@
 	return data
 }
 
+func ndkarch() string {
+	switch runtime.GOARCH {
+	case "amd64":
+		return "x86_64"
+	case "386":
+		return "x86"
+	default:
+		return runtime.GOARCH
+	}
+}
+
 var initTmpl = template.Must(template.New("output").Parse(`GOMOBILE={{.GOPATH}}/pkg/gomobile
 rm -r -f "$GOMOBILE"
 mkdir -p $GOMOBILE
-WORK={{.GOPATH}}/pkg/gomobile/work{{if eq .GOOS "darwin"}}
-go install -x golang.org/x/mobile/gl
-go install -x golang.org/x/mobile/app
-go install -x golang.org/x/mobile/exp/app/debug{{end}}
-GOOS=android GOARCH=arm CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain $NDK_PATH/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_CPPFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain $NDK_PATH/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_LDFLAGS=-target armv7a-none-linux-androideabi -gcc-toolchain $NDK_PATH/toolchains/arm-linux-androideabi-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/platforms/android-15/arch-arm -L$GOMOBILE/lib/arm CGO_ENABLED=1 GOARM=7 go install -gcflags=-shared -ldflags=-shared -pkgdir=$GOMOBILE/pkg_android_arm -x std
-GOOS=android GOARCH=arm64 CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target aarch64-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/aarch64-linux-android-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -I$GOMOBILE/include CGO_CPPFLAGS=-target aarch64-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/aarch64-linux-android-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -I$GOMOBILE/include CGO_LDFLAGS=-target aarch64-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/aarch64-linux-android-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/platforms/android-21/arch-arm64 -L$GOMOBILE/lib/arm64 CGO_ENABLED=1 go install -gcflags=-shared -ldflags=-shared -pkgdir=$GOMOBILE/pkg_android_arm64 -x std
-GOOS=android GOARCH=386 CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target i686-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/x86-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_CPPFLAGS=-target i686-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/x86-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 -I$GOMOBILE/include CGO_LDFLAGS=-target i686-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/x86-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/platforms/android-15/arch-x86 -L$GOMOBILE/lib/386 CGO_ENABLED=1 go install -gcflags=-shared -ldflags=-shared -pkgdir=$GOMOBILE/pkg_android_386 -x std
-GOOS=android GOARCH=amd64 CC=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang{{.EXE}} CXX=$NDK_PATH/toolchains/llvm/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/clang++{{.EXE}} CGO_CFLAGS=-target x86_64-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/x86_64-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -I$GOMOBILE/include CGO_CPPFLAGS=-target x86_64-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/x86_64-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/sysroot -isystem $NDK_PATH/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -I$GOMOBILE/include CGO_LDFLAGS=-target x86_64-none-linux-android -gcc-toolchain $NDK_PATH/toolchains/x86_64-4.9/prebuilt/{{.GOOS}}-{{.NDKARCH}} --sysroot $NDK_PATH/platforms/android-21/arch-x86_64 -L$GOMOBILE/lib/amd64 CGO_ENABLED=1 go install -gcflags=-shared -ldflags=-shared -pkgdir=$GOMOBILE/pkg_android_amd64 -x std
-{{if eq .GOOS "darwin"}}GOOS=darwin GOARCH=arm GOARM=7 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 go install -pkgdir=$GOMOBILE/pkg_darwin_arm -x std
-GOOS=darwin GOARCH=arm64 CC=clang-iphoneos CXX=clang-iphoneos CGO_CFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch arm64 CGO_LDFLAGS=-isysroot=iphoneos -miphoneos-version-min=6.1 -arch arm64 CGO_ENABLED=1 go install -pkgdir=$GOMOBILE/pkg_darwin_arm64 -x std
-GOOS=darwin GOARCH=amd64 CC=clang-iphonesimulator CXX=clang-iphonesimulator CGO_CFLAGS=-isysroot=iphonesimulator -mios-simulator-version-min=6.1 -arch x86_64 CGO_LDFLAGS=-isysroot=iphonesimulator -mios-simulator-version-min=6.1 -arch x86_64 CGO_ENABLED=1 go install -tags=ios -pkgdir=$GOMOBILE/pkg_darwin_amd64 -x std
-{{end}}cp $OPENAL_PATH/include/AL/al.h $GOMOBILE/include/AL/al.h
+WORK={{.GOPATH}}/pkg/gomobile/work
+PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=arm --api=15 --install-dir=$GOMOBILE/ndk-toolchains/arm
+PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=arm64 --api=21 --install-dir=$GOMOBILE/ndk-toolchains/arm64
+PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=x86 --api=15 --install-dir=$GOMOBILE/ndk-toolchains/x86
+PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=x86_64 --api=21 --install-dir=$GOMOBILE/ndk-toolchains/x86_64
+cp $OPENAL_PATH/include/AL/al.h $GOMOBILE/include/AL/al.h
 mkdir -p $GOMOBILE/include/AL
 cp $OPENAL_PATH/include/AL/alc.h $GOMOBILE/include/AL/alc.h
 mkdir -p $GOMOBILE/include/AL
-PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=arm --api=15 --install-dir=$WORK/build/armeabi/toolchain
+mkdir -p $WORK/build/armeabi
 PWD=$WORK/build/armeabi cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=arm-linux-androideabi
-PWD=$WORK/build/armeabi $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/make
+PWD=$WORK/build/armeabi $GOMOBILE/ndk-toolchains/arm/bin/make
 cp $WORK/build/armeabi/libopenal.so $GOMOBILE/lib/armeabi-v7a/libopenal.so
 mkdir -p $GOMOBILE/lib/armeabi-v7a
-PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=arm64 --api=21 --install-dir=$WORK/build/arm64/toolchain
+mkdir -p $WORK/build/arm64
 PWD=$WORK/build/arm64 cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=aarch64-linux-android
-PWD=$WORK/build/arm64 $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/make
+PWD=$WORK/build/arm64 $GOMOBILE/ndk-toolchains/arm64/bin/make
 cp $WORK/build/arm64/libopenal.so $GOMOBILE/lib/arm64-v8a/libopenal.so
 mkdir -p $GOMOBILE/lib/arm64-v8a
-PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=x86 --api=15 --install-dir=$WORK/build/x86/toolchain
+mkdir -p $WORK/build/x86
 PWD=$WORK/build/x86 cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=i686-linux-android
-PWD=$WORK/build/x86 $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/make
+PWD=$WORK/build/x86 $GOMOBILE/ndk-toolchains/x86/bin/make
 cp $WORK/build/x86/libopenal.so $GOMOBILE/lib/x86/libopenal.so
 mkdir -p $GOMOBILE/lib/x86
-PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=x86_64 --api=21 --install-dir=$WORK/build/x86_64/toolchain
+mkdir -p $WORK/build/x86_64
 PWD=$WORK/build/x86_64 cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=x86_64-linux-android
-PWD=$WORK/build/x86_64 $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/make
+PWD=$WORK/build/x86_64 $GOMOBILE/ndk-toolchains/x86_64/bin/make
 cp $WORK/build/x86_64/libopenal.so $GOMOBILE/lib/x86_64/libopenal.so
 mkdir -p $GOMOBILE/lib/x86_64
-go version > $GOMOBILE/version
 rm -r -f "$WORK"
 `))