cmd/gomobile: use the NDK r19b prebuilt toolchains

To use the NDK before version r19b standalone toolchains had to be
generated. Version r19b added prebuilt standalone toolchains.

Use the prebuilt for gomobile build and gomobile bind and
stop generating toolchains during gomobile init.

gomobile init is now only necessary for building OpenAL for
gomobile build programs.

This change is not compatible with NDK versions < r19b, but the
user is instructed how to upgrade when running gomobile build or
gomobile bind.

Change-Id: I96953298ecce42402459a9dd15169c09fe6b6f8b
Reviewed-on: https://go-review.googlesource.com/c/163378
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
Elias Naur
2019-02-22 14:21:12 +00:00
parent 8b05ea26b5
commit ca80213619
8 changed files with 77 additions and 140 deletions
+4 -2
View File
@@ -93,8 +93,10 @@ func runBind(cmd *command) error {
return fmt.Errorf("-prefix is supported only for ios target")
}
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.")
if ctx.GOOS == "android" {
if _, err := ndkRoot(); err != nil {
return err
}
}
if ctx.GOOS == "darwin" {
-5
View File
@@ -6,7 +6,6 @@ package main
import (
"archive/zip"
"errors"
"fmt"
"go/build"
"io"
@@ -23,10 +22,6 @@ func goAndroidBind(gobind string, pkgs []*build.Package, androidArchs []string)
return fmt.Errorf("this command requires ANDROID_HOME environment variable (path to the Android SDK)")
}
if !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.")
}
// Run gobind to generate the bindings
cmd := exec.Command(
gobind,
+1 -1
View File
@@ -176,7 +176,7 @@ func TestBindIOS(t *testing.T) {
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=$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
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 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 .
`))
+4 -3
View File
@@ -25,8 +25,9 @@ import (
)
func goAndroidBuild(pkg *build.Package, androidArchs []string) (map[string]bool, error) {
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.")
ndkRoot, err := ndkRoot()
if err != nil {
return nil, err
}
appName := path.Base(pkg.ImportPath)
libName := androidPkgName(appName)
@@ -79,7 +80,7 @@ func goAndroidBuild(pkg *build.Package, androidArchs []string) (map[string]bool,
if err != nil {
return nil, err
}
nmpkgs[arch], err = extractPkgs(toolchain.Path("nm"), libAbsPath)
nmpkgs[arch], err = extractPkgs(toolchain.Path(ndkRoot, "nm"), libAbsPath)
if err != nil {
return nil, err
}
+1 -1
View File
@@ -105,7 +105,7 @@ func TestAndroidBuild(t *testing.T) {
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=$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
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 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) {
+49 -35
View File
@@ -81,14 +81,14 @@ func envInit() (err error) {
}
// Setup the cross-compiler environments.
if hasNDK() {
if ndkRoot, err := ndkRoot(); err == nil {
androidEnv = make(map[string][]string)
for arch, toolchain := range ndk {
androidEnv[arch] = []string{
"GOOS=android",
"GOARCH=" + arch,
"CC=" + toolchain.Path("clang"),
"CXX=" + toolchain.Path("clang++"),
"CC=" + toolchain.Path(ndkRoot, "clang"),
"CXX=" + toolchain.Path(ndkRoot, "clang++"),
"CGO_ENABLED=1",
}
if arch == "arm" {
@@ -139,13 +139,25 @@ func envInit() (err error) {
return nil
}
func hasNDK() bool {
func ndkRoot() (string, error) {
if buildN {
return true
return "$NDK_PATH", nil
}
tcPath := filepath.Join(gomobilepath, "ndk-toolchains")
_, err := os.Stat(tcPath)
return err == nil
androidHome := os.Getenv("ANDROID_HOME")
if androidHome == "" {
return "", errors.New("The Android SDK was not found. Please set ANDROID_HOME to the root of the Android SDK.")
}
ndkRoot := filepath.Join(androidHome, "ndk-bundle")
_, err := os.Stat(ndkRoot)
if err != nil {
return "", fmt.Errorf("The NDK was not found in $ANDROID_HOME/ndk-bundle (%q). Install the NDK with `sdkmanager 'ndk-bundle'`", ndkRoot)
}
prebuiltPath := filepath.Join(androidHome, "ndk-bundle", "toolchains", "llvm", "prebuilt")
_, err = os.Stat(prebuiltPath)
if err != nil {
return "", fmt.Errorf("No prebuilt toolchains found in $ANDROID_HOME/ndk-bundle/toolchains/llvm/prebuilt (%q). Make sure your NDK version is >= r19b. Use `sdkmanager --update` to update it.", prebuiltPath)
}
return ndkRoot, nil
}
func envClang(sdkName string) (clang, cflags string, err error) {
@@ -247,15 +259,21 @@ func archNDK() string {
}
type ndkToolchain struct {
arch string
abi string
platform string
gcc string
toolPrefix string
arch string
abi string
toolPrefix string
clangPrefix string
}
func (tc *ndkToolchain) Path(toolName string) string {
return filepath.Join(gomobilepath, "ndk-toolchains", tc.arch, "bin", tc.toolPrefix+"-"+toolName)
func (tc *ndkToolchain) Path(ndkRoot, toolName string) string {
var pref string
switch toolName {
case "clang", "clang++":
pref = tc.clangPrefix
default:
pref = tc.toolPrefix
}
return filepath.Join(ndkRoot, "toolchains", "llvm", "prebuilt", archNDK(), "bin", pref+"-"+toolName)
}
type ndkConfig map[string]ndkToolchain // map: GOOS->androidConfig.
@@ -270,33 +288,29 @@ func (nc ndkConfig) Toolchain(arch string) ndkToolchain {
var ndk = ndkConfig{
"arm": {
arch: "arm",
abi: "armeabi-v7a",
platform: "android-16",
gcc: "arm-linux-androideabi-4.9",
toolPrefix: "arm-linux-androideabi",
arch: "arm",
abi: "armeabi-v7a",
toolPrefix: "arm-linux-androideabi",
clangPrefix: "armv7a-linux-androideabi16",
},
"arm64": {
arch: "arm64",
abi: "arm64-v8a",
platform: "android-21",
gcc: "aarch64-linux-android-4.9",
toolPrefix: "aarch64-linux-android",
arch: "arm64",
abi: "arm64-v8a",
toolPrefix: "aarch64-linux-android",
clangPrefix: "aarch64-linux-android21",
},
"386": {
arch: "x86",
abi: "x86",
platform: "android-16",
gcc: "x86-4.9",
toolPrefix: "i686-linux-android",
arch: "x86",
abi: "x86",
toolPrefix: "i686-linux-android",
clangPrefix: "i686-linux-android16",
},
"amd64": {
arch: "x86_64",
abi: "x86_64",
platform: "android-21",
gcc: "x86_64-4.9",
toolPrefix: "x86_64-linux-android",
arch: "x86_64",
abi: "x86_64",
toolPrefix: "x86_64-linux-android",
clangPrefix: "x86_64-linux-android21",
},
}
+9 -68
View File
@@ -26,26 +26,18 @@ var (
var cmdInit = &command{
run: runInit,
Name: "init",
Usage: "[-ndk dir] [-openal dir]",
Short: "install NDK toolchains and build OpenAL for Android",
Usage: "[-openal dir]",
Short: "build OpenAL for Android",
Long: `
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
build an Android version of OpenAL for use with gomobile build
and gomobile install.
`,
}
var (
initNDK string // -ndk
initOpenAL string // -openal
)
var initOpenAL string // -openal
func init() {
cmdInit.flag.StringVar(&initNDK, "ndk", "", "Android NDK path")
cmdInit.flag.StringVar(&initOpenAL, "openal", "", "OpenAL source path")
}
@@ -91,32 +83,8 @@ func runInit(cmd *command) error {
}
if buildN {
initNDK = "$NDK_PATH"
initOpenAL = "$OPENAL_PATH"
} else {
toolsDir := filepath.Join("prebuilt", archNDK(), "bin")
// Try the ndk-bundle SDK package package, if installed.
if initNDK == "" {
if sdkHome := os.Getenv("ANDROID_HOME"); sdkHome != "" {
path := filepath.Join(sdkHome, "ndk-bundle")
if st, err := os.Stat(filepath.Join(path, toolsDir)); err == nil && st.IsDir() {
initNDK = path
}
}
}
if initNDK != "" {
var err error
if initNDK, err = filepath.Abs(initNDK); err != nil {
return err
}
// Check if the platform directory contains a known subdirectory.
if _, err := os.Stat(filepath.Join(initNDK, toolsDir)); err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("%q does not point to an Android NDK.", initNDK)
}
return err
}
}
if initOpenAL != "" {
var err error
if initOpenAL, err = filepath.Abs(initOpenAL); err != nil {
@@ -130,10 +98,6 @@ func runInit(cmd *command) error {
start := time.Now()
if err := installNDKToolchains(gomobilepath); err != nil {
return err
}
if err := installOpenAL(gomobilepath); err != nil {
return err
}
@@ -145,36 +109,13 @@ func runInit(cmd *command) error {
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 allArchs {
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 initOpenAL == "" {
return nil
}
if !hasNDK() {
return errors.New("The Android NDK is needed to build OpenAL but it was not found. Please run gomobile init with the ndk-bundle installed through the Android SDK manager or with the -ndk flag set.")
ndkRoot, err := ndkRoot()
if err != nil {
return err
}
var cmake string
@@ -232,8 +173,7 @@ func installOpenAL(gomobilepath string) error {
if abi == "arm" {
abi = "armeabi"
}
tcPath := filepath.Join(gomobilepath, "ndk-toolchains", t.arch, "bin")
make := filepath.Join(tcPath, "make")
make := filepath.Join(ndkRoot, "prebuilt", archNDK(), "bin", "make")
// Split android-XX to get the api version.
buildDir := alTmpDir + "/build/" + abi
if err := mkdir(buildDir); err != nil {
@@ -242,8 +182,9 @@ func installOpenAL(gomobilepath string) error {
cmd := exec.Command(cmake,
initOpenAL,
"-DCMAKE_TOOLCHAIN_FILE="+initOpenAL+"/XCompile-Android.txt",
"-DHOST="+t.toolPrefix)
"-DHOST="+t.clangPrefix)
cmd.Dir = buildDir
tcPath := filepath.Join(ndkRoot, "toolchains", "llvm", "prebuilt", archNDK(), "bin")
if !buildN {
orgPath := os.Getenv("PATH")
cmd.Env = []string{"PATH=" + tcPath + string(os.PathListSeparator) + orgPath}
+9 -25
View File
@@ -8,7 +8,6 @@ import (
"bytes"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"text/template"
@@ -88,7 +87,7 @@ func defaultOutputData() outputData {
GOOS: goos,
GOARCH: goarch,
GOPATH: gopath,
NDKARCH: ndkarch(),
NDKARCH: archNDK(),
Xproj: projPbxproj,
Xcontents: contentsJSON,
Xinfo: infoplistTmplData{BundleID: "org.golang.todo.basic", Name: "Basic"},
@@ -99,48 +98,33 @@ func defaultOutputData() outputData {
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
go install -x golang.org/x/mobile/cmd/gobind
PWD=$NDK_PATH $NDK_PATH/prebuilt/{{.GOOS}}-{{.NDKARCH}}/bin/python2.7 build/tools/make_standalone_toolchain.py --arch=arm --api=16 --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=16 --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
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 $GOMOBILE/ndk-toolchains/arm/bin/make
PWD=$WORK/build/armeabi cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=armv7a-linux-androideabi16
PWD=$WORK/build/armeabi $NDK_PATH/prebuilt/{{.NDKARCH}}/bin/make
cp $WORK/build/armeabi/libopenal.so $GOMOBILE/lib/armeabi-v7a/libopenal.so
mkdir -p $GOMOBILE/lib/armeabi-v7a
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 $GOMOBILE/ndk-toolchains/arm64/bin/make
PWD=$WORK/build/arm64 cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=aarch64-linux-android21
PWD=$WORK/build/arm64 $NDK_PATH/prebuilt/{{.NDKARCH}}/bin/make
cp $WORK/build/arm64/libopenal.so $GOMOBILE/lib/arm64-v8a/libopenal.so
mkdir -p $GOMOBILE/lib/arm64-v8a
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 $GOMOBILE/ndk-toolchains/x86/bin/make
PWD=$WORK/build/x86 cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=i686-linux-android16
PWD=$WORK/build/x86 $NDK_PATH/prebuilt/{{.NDKARCH}}/bin/make
cp $WORK/build/x86/libopenal.so $GOMOBILE/lib/x86/libopenal.so
mkdir -p $GOMOBILE/lib/x86
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 $GOMOBILE/ndk-toolchains/x86_64/bin/make
PWD=$WORK/build/x86_64 cmake $OPENAL_PATH -DCMAKE_TOOLCHAIN_FILE=$OPENAL_PATH/XCompile-Android.txt -DHOST=x86_64-linux-android21
PWD=$WORK/build/x86_64 $NDK_PATH/prebuilt/{{.NDKARCH}}/bin/make
cp $WORK/build/x86_64/libopenal.so $GOMOBILE/lib/x86_64/libopenal.so
mkdir -p $GOMOBILE/lib/x86_64
rm -r -f "$WORK"