--- /dev/null
+// Copyright 2015 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.
+
+#include <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+// Tests "main.main" is exported on android/arm,
+// which golang.org/x/mobile/app depends on.
+int main(int argc, char** argv) {
+ void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+ if (!handle) {
+ fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+ dlerror());
+ return 2;
+ }
+
+ uintptr_t main_fn = (uintptr_t)dlsym(handle, "main.main");
+ if (!main_fn) {
+ fprintf(stderr, "ERROR: missing main.main: %s\n", dlerror());
+ return 2;
+ }
+
+ // TODO(hyangah): check that main.main can run.
+
+ printf("PASS\n");
+ return 0;
+}
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+# For testing Android, this script requires adb to push and run compiled
+# binaries on a target device.
+
set -e
+if [ ! -f src/libgo/libgo.go ]; then
+ cwd=$(pwd)
+ echo 'misc/cgo/testcshared/test.bash is running in $cwd' 1>&2
+ exit 1
+fi
+
+goos=$(go env GOOS)
+
+# Temporary directory on the android device.
+androidpath=/data/local/tmp/testcshared-$$
+
function cleanup() {
- rm -f libgo.so libgo2.so testp testp2
+ rm -f libgo.so libgo2.so testp testp2 testp3
+
+ if [ "$(go env GOOS)" == "android" ]; then
+ adb shell rm -rf $androidpath
+ fi
}
trap cleanup EXIT
+if [ "$goos" == "android" ]; then
+ adb shell mkdir -p "$androidpath"
+fi
+
+function run() {
+ case "$goos" in
+ "android")
+ local args=$@
+ for ((i=0; i < ${#args}; i++)); do
+ args[$i]=${args[$i]//.\//${androidpath}\/}
+ args[$i]=${args[$i]//=./=${androidpath}}
+ done
+ echo $(adb shell ${args} | tr -d '\r')
+ ;;
+ *)
+ echo $(env $@)
+ ;;
+ esac
+}
+
+function binpush() {
+ bin=${1}
+ if [ "$goos" == "android" ]; then
+ adb push "$bin" "${androidpath}/${bin}" 2>/dev/null
+ fi
+}
+
GOPATH=$(pwd) go build -buildmode=c-shared -o libgo.so src/libgo/libgo.go
+binpush libgo.so
+# test0: exported symbols in shared lib are accessible.
$(go env CC) $(go env GOGCCFLAGS) -o testp main0.c libgo.so
-output=$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./testp)
-# testp prints PASS at the end of its execution.
+binpush testp
+output=$(run LD_LIBRARY_PATH=. ./testp)
if [ "$output" != "PASS" ]; then
- echo "FAIL: got $output"
+ echo "FAIL test0 got ${output}"
exit 1
fi
+# test1: .so can be dynamically loaded and exported symbols are accessible.
$(go env CC) $(go env GOGCCFLAGS) -o testp main1.c -ldl
-output=$(./testp ./libgo.so)
-# testp prints PASS at the end of its execution.
+binpush testp
+output=$(run ./testp ./libgo.so)
if [ "$output" != "PASS" ]; then
- echo "FAIL: got $output"
+ echo "FAIL test1 got ${output}"
exit 1
fi
+# test2: tests libgo2.so which does not export any functions.
GOPATH=$(pwd) go build -buildmode=c-shared -o libgo2.so src/libgo2/libgo2.go
-
+binpush libgo2.so
$(go env CC) $(go env GOGCCFLAGS) -o testp2 main2.c -Wl,--no-as-needed libgo2.so
-output=$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./testp2)
-# testp2 prints PASS at the end of its execution.
+binpush testp2
+output=$(run LD_LIBRARY_PATH=. ./testp2)
if [ "$output" != "PASS" ]; then
- echo "FAIL: got $output"
+ echo "FAIL test2 got ${output}"
exit 1
fi
+
+# test3: tests main.main is exported on android.
+if [ "$goos" == "android" ]; then
+ $(go env CC) $(go env GOGCCFLAGS) -o testp3 main3.c -ldl
+ binpush testp3
+ output=$(run ./testp ./libgo.so)
+ if [ "$output" != "PASS" ]; then
+ echo "FAIL test3 got ${output}"
+ exit 1
+ fi
+fi
+echo "ok"
}
func (t *tester) buildmode(mode string) bool {
+ pair := t.goos + "-" + t.goarch
switch mode {
case "c-archive":
- switch {
- case !t.extLink():
+ if !t.extLink() {
return false
- case t.goos == "darwin":
- switch t.goarch {
- case "amd64", "arm", "arm64":
- return true
- default:
- return false
- }
- case t.goos == "linux" && (t.goarch == "amd64" || t.goarch == "386"):
+ }
+ switch pair {
+ case "darwin-amd64", "darwin-arm", "darwin-arm64",
+ "linux-amd64", "linux-386":
return true
- default:
- return false
}
+ return false
case "c-shared":
- // TODO(hyangah): add linux/386.
- return t.goos == "linux" && t.goarch == "amd64"
+ // TODO(hyangah): add linux-386.
+ switch pair {
+ case "linux-amd64", "android-arm":
+ return true
+ }
+ return false
default:
log.Fatal("internal error: unknown buildmode %s", mode)
return false