From ca80213619811c2fbed3ff8345accbd4ba924d45 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 22 Feb 2019 11:41:06 +0100 Subject: [PATCH] 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 --- cmd/gomobile/bind.go | 6 ++- cmd/gomobile/bind_androidapp.go | 5 -- cmd/gomobile/bind_test.go | 2 +- cmd/gomobile/build_androidapp.go | 7 +-- cmd/gomobile/build_test.go | 2 +- cmd/gomobile/env.go | 84 +++++++++++++++++++------------- cmd/gomobile/init.go | 77 ++++------------------------- cmd/gomobile/init_test.go | 34 ++++--------- 8 files changed, 77 insertions(+), 140 deletions(-) diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index 248db89..ef9a5b3 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -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" { diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go index 9897fbd..149fab4 100644 --- a/cmd/gomobile/bind_androidapp.go +++ b/cmd/gomobile/bind_androidapp.go @@ -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, diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go index 5129590..88c2aef 100644 --- a/cmd/gomobile/bind_test.go +++ b/cmd/gomobile/bind_test.go @@ -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 . `)) diff --git a/cmd/gomobile/build_androidapp.go b/cmd/gomobile/build_androidapp.go index 06b2571..7b5e06f 100644 --- a/cmd/gomobile/build_androidapp.go +++ b/cmd/gomobile/build_androidapp.go @@ -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 } diff --git a/cmd/gomobile/build_test.go b/cmd/gomobile/build_test.go index eb6ef58..1bce42f 100644 --- a/cmd/gomobile/build_test.go +++ b/cmd/gomobile/build_test.go @@ -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) { diff --git a/cmd/gomobile/env.go b/cmd/gomobile/env.go index 471b009..5a523fe 100644 --- a/cmd/gomobile/env.go +++ b/cmd/gomobile/env.go @@ -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", }, } diff --git a/cmd/gomobile/init.go b/cmd/gomobile/init.go index fba9308..ed40230 100644 --- a/cmd/gomobile/init.go +++ b/cmd/gomobile/init.go @@ -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} diff --git a/cmd/gomobile/init_test.go b/cmd/gomobile/init_test.go index c0180ce..a1d8f39 100644 --- a/cmd/gomobile/init_test.go +++ b/cmd/gomobile/init_test.go @@ -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"