From: David Crawshaw Date: Wed, 9 Jul 2014 10:56:49 +0000 (-0400) Subject: androidtest.bash, misc/android: build scripts for android X-Git-Tag: go1.4beta1~1134 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=a5f8e8f99cbac0cfecd3baa869d111bacfbaeac4;p=gostls13.git androidtest.bash, misc/android: build scripts for android LGTM=minux R=minux CC=golang-codereviews https://golang.org/cl/107640044 --- diff --git a/misc/android/README b/misc/android/README new file mode 100644 index 0000000000..5f24fafc7c --- /dev/null +++ b/misc/android/README @@ -0,0 +1,11 @@ +Android +======= + +For details on developing Go for Android, see the documentation in the +go.mobile subrepository: + + https://code.google.com/p/go/source/browse/README?repo=mobile + +To run the standard library tests, see androidtest.bash. Run it as + + CC_FOR_TARGET=.../ndk-gcc GOARCH=arm GOARM=7 ./androidtest.bash diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go new file mode 100644 index 0000000000..065b624376 --- /dev/null +++ b/misc/android/go_android_exec.go @@ -0,0 +1,96 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This program can be used as go_android_GOARCH_exec by the Go tool. +// It executes binaries on an android device using adb. +package main + +import ( + "bytes" + "fmt" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" +) + +func run(args ...string) string { + buf := new(bytes.Buffer) + cmd := exec.Command("adb", args...) + cmd.Stdout = io.MultiWriter(os.Stdout, buf) + cmd.Stderr = os.Stderr + log.Printf("adb %s", strings.Join(args, " ")) + err := cmd.Run() + if err != nil { + log.Fatalf("adb %s: %v", strings.Join(args, " "), err) + } + return buf.String() +} + +func main() { + log.SetFlags(0) + log.SetPrefix("go_android_exec: ") + + // Determine thepackage by examining the current working + // directory, which will look something like + // "$GOROOT/src/pkg/mime/multipart". We extract everything + // after the $GOROOT to run on the same relative directory + // on the target device. + // + // TODO(crawshaw): Pick useful subdir when we are not + // inside a GOROOT, e.g. we are in a GOPATH. + cwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + subdir, err := filepath.Rel(runtime.GOROOT(), cwd) + if err != nil { + log.Fatal(err) + } + subdir = filepath.ToSlash(subdir) + + // Binary names can conflict. + // E.g. template.test from the {html,text}/template packages. + binName := filepath.Base(os.Args[1]) + deviceGoroot := "/data/local/tmp/goroot" + deviceBin := fmt.Sprintf("%s/%s-%d", deviceGoroot, binName, os.Getpid()) + + // The push of the binary happens in parallel with other tests. + // Unfortunately, a simultaneous call to adb shell hold open + // file descriptors, so it is necessary to push then move to + // avoid a "text file busy" error on execution. + // https://code.google.com/p/android/issues/detail?id=65857 + run("push", os.Args[1], deviceBin+"-tmp") + run("shell", "cp '"+deviceBin+"-tmp' '"+deviceBin+"'") + run("shell", "rm '"+deviceBin+"-tmp'") + + // The adb shell command will return an exit code of 0 regardless + // of the command run. E.g. + // $ adb shell false + // $ echo $? + // 0 + // https://code.google.com/p/android/issues/detail?id=3254 + // So we append the exitcode to the output and parse it from there. + const exitstr = "exitcode=" + cmd := `export TMPDIR="/data/local/tmp"` + + `; export GOROOT="` + deviceGoroot + `"` + + `; cd "$GOROOT/` + subdir + `"` + + "; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") + + "; echo -n " + exitstr + "$?" + output := run("shell", cmd) + run("shell", "rm '"+deviceBin+"'") // cleanup + output = output[strings.LastIndex(output, "\n")+1:] + if !strings.HasPrefix(output, exitstr) { + log.Fatalf("no exit code: %q", output) + } + code, err := strconv.Atoi(output[len(exitstr):]) + if err != nil { + log.Fatalf("bad exit code: %v", err) + } + os.Exit(code) +} diff --git a/src/androidtest.bash b/src/androidtest.bash new file mode 100755 index 0000000000..ede085ef83 --- /dev/null +++ b/src/androidtest.bash @@ -0,0 +1,54 @@ +#/usr/bin/env bash +# Copyright 2014 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# For testing Android. +# The compiler runs locally, then a copy of the GOROOT is pushed to a +# target device using adb, and the tests are run there. + +set -e +ulimit -c 0 # no core files + +if [ ! -f make.bash ]; then + echo 'nacl.bash must be run from $GOROOT/src' 1>&2 + exit 1 +fi + +if [ -z $GOOS ]; then + export GOOS=android +fi +if [ "$GOOS" != "android" ]; then + echo "androidtest.bash requires GOOS=android, got GOOS=$GOOS" 1>&2 + exit 1 +fi + +export CGO_ENABLED=1 + +# Run the build for the host bootstrap, so we can build go_android_exec. +# Also lets us fail early before the (slow) adb push if the build is broken. +./make.bash +export GOROOT=$(dirname $(pwd)) +export PATH=$GOROOT/bin:$PATH +GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \ + -o ../bin/go_android_${GOARCH}_exec \ + ../misc/android/go_android_exec.go + +# Push GOROOT to target device. +# +# The adb sync command will sync either the /system or /data +# directories of an android device from a similar directory +# on the host. So we fake one with symlinks to push the GOROOT +# into a subdirectory of /data. +export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$ +FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot +mkdir -p $FAKE_GOROOT/src +ln -s $GOROOT/src/cmd $FAKE_GOROOT/src/cmd +ln -s $GOROOT/src/pkg $FAKE_GOROOT/src/pkg +ln -s $GOROOT/test $FAKE_GOROOT/test +ln -s $GOROOT/lib $FAKE_GOROOT/lib +adb sync data +rm -rf "$ANDROID_PRODUCT_OUT" + +# Run standard build and tests. +./all.bash --no-clean