Reputation: 8213
I'm trying to build a standard "Hello, World!" command-line executable for Android. The executable is to be run via adb shell
.
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, world!")
}
$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build .
# github.com/asukakenji/cross
warning: unable to find runtime/cgo.a
/usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1
ld: warning: ignoring file
/var/folders/dd/6k6vkzbd6d5803xj9zkjdhmh0000gn/T/go-link-150305609/go.o,
file was built for unsupported file format
( 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 )
which is not the architecture being linked (x86_64):
/var/folders/dd/6k6vkzbd6d5803xj9zkjdhmh0000gn/T/go-link-150305609/go.o
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The following command gives the same result:
$ env CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build .
I've tried using "-v"
as mentioned like this:
$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build \
-x -ldflags "-extldflags -v" .
It gives me more than 100 lines of messages, so I don't post it here unless it's necessary. The go build
command seems to try compiling the source with the clang
bundled with Xcode
.
Given the hint that the wrong compiler is found, I tried to set $CC
like this:
$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 \
CC=/path/to/arm-linux-androideabi/bin/clang go build .
arm-linux-androideabi
is the output from make_standalone_toolchain.py
(or make-standalone-toolchain.sh
).
The executable (named cross
) is successfully built, with the following messages:
# github.com/asukakenji/cross
warning: unable to find runtime/cgo.a
I tried adb push
it and run it with adb shell
on Android, it worked fine.
When building for Linux (instead of Android), the compilation works fine:
$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .
Why?
go build
command keeps looking for runtime/cgo.a
, even when I didn't use CGO in the source code, and even when I set CGO_ENABLED=0
. How can I get rid of the warning? How is it harmful not having one?Upvotes: 11
Views: 10837
Reputation: 25008
You need to use Android NDK to compile for android, you can download it from the link, or from Android Studio:
Then you can find the compilerlink in the route as below:
Last login: Fri Sep 4 09:25:16 on console
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
Hasans-Air:~ hajsf$ pwd
/Users/hajsf
Hasans-Air:~ hajsf$ cd Library
Hasans-Air:Library hajsf$ cd android
Hasans-Air:android hajsf$ cd sdk
Hasans-Air:sdk hajsf$ cd ndk
Hasans-Air:ndk hajsf$ ls
21.3.6528147
Hasans-Air:ndk hajsf$ cd 21.3.6528147
Hasans-Air:21.3.6528147 hajsf$ cd toolchains
Hasans-Air:toolchains hajsf$ cd llvm
Hasans-Air:llvm hajsf$ cd prebuilt
Hasans-Air:prebuilt hajsf$ ls
darwin-x86_64
Hasans-Air:prebuilt hajsf$ cd darwin-x86_64
Hasans-Air:darwin-x86_64 hajsf$ cd bin
Hasans-Air:bin hajsf$ pwd
/Users/hajsf/Library/android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin
Then you can use the one reflection:
aarch64
Android 30
You can see full list of available options there, and you can select the one you want like aarch64-linux-android30-clang
If you are at Windows 10
you'll find it at:
"C:\Users\${user}\AppData\Local\Android\Sdk\ndk\${NKD_version}\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android30-clang"
There are 4 available linkers which are:
//CC_FOR_TARGET=/Users/hajsf/Library/android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android30-clang
//CC_FOR_TARGET=/Users/hajsf/Library/android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/i686-linux-android30-clang
//CC_FOR_TARGET=/Users/hajsf/Library/android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android30-clang
//CC_FOR_TARGET=/Users/hajsf/Library/android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi30-clang
After that only you can do cross-compiling, as:
$ CGO_ENABLED=1
$ GOOS=android
$ GOARCH=arm64
$ CC_FOR_TARGET=/Users/hajsf/Library/android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android30-clang
$ go build -buildmode=c-shared -o lib-aarch64-android30.so lib.go
And a simple cgo
file lib.go
could be:
package main
import "C"
import "fmt"
//export HelloWorld
func HelloWorld() {
fmt.Printf("hello world from GO\n")
}
//export GetKey
func GetKey() *C.char {
theKey := "123-456-789"
return C.CString(theKey)
}
func main() {}
As shown compilation completed successfully, and both lib-aarch64-android30.so
and ib-aarch64-android30.h
had been generated without any error.
Quick note, not to go far from the scope of the question, if you return a string, then the return value from this function must be explicitly freed in the C code if if you call it from C
code, but as you call it from garbage collector environment, Java/Kotlin you do not want to worry about it.
If freeing the allocated buffer isn't convenient, its common to fill a buffer provided by the caller:
func GetKey(buff *C.char, n int) int
If you can allocate the memory but don't want to handle C strings, you can insert the buffer into a pointer and return the size.
func GetKey(buff **C.char) int
Upvotes: 1
Reputation: 61
if you run that code you find the android as an official target platform listed as GOOS/GOARCH
$go tool dist list
Upvotes: 6
Reputation: 2125
The cgo requirement might be because go requires libc for DNS lookups on Android: https://github.com/golang/go/issues/8877
Upvotes: 2
Reputation: 8490
Android isn't official target platform for cross-compilation. If all you need are command-line executables then you can set GOOS=linux because android is a linux under the hood, else take a look at https://github.com/golang/go/wiki/Mobile
Upvotes: 4