我正在努力建立一个标准的“Hello,World!” Android的命令行可执行文件。可执行文件将通过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)
以下命令给出了相同的结果:
$ env CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build .
我尝试过如下所述使用"-v"
:
$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build \
-x -ldflags "-extldflags -v" .
它给了我超过100行的消息,所以除非有必要,否则我不会在此发布。 go build
命令似乎尝试使用clang
捆绑的Xcode
来编译源代码。
鉴于提示找到了错误的编译器,我试图像这样设置$CC
:
$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 \
CC=/path/to/arm-linux-androideabi/bin/clang go build .
arm-linux-androideabi
是make_standalone_toolchain.py
(或make-standalone-toolchain.sh
)的输出。
已成功构建可执行文件(名为cross
),并显示以下消息:
# github.com/asukakenji/cross
warning: unable to find runtime/cgo.a
我尝试adb push
并在Android上使用adb shell
运行它,它运行正常。
在为Linux(而不是Android)构建时,编译工作正常:
$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .
为什么?
go build
命令一直在查找runtime/cgo.a
,即使我在源代码中没有使用CGO,甚至在设置CGO_ENABLED=0
时也是如此。我该如何摆脱警告?没有一个人怎么有害?谢谢!
答案 0 :(得分:2)
Android不是交叉编译的官方目标平台。如果您只需要命令行可执行文件,那么您可以设置GOOS = linux,因为android是一个linux下的linux,否则请查看https://github.com/golang/go/wiki/Mobile
答案 1 :(得分:2)
cgo要求可能是因为go需要libc才能在Android上进行DNS查找:https://github.com/golang/go/issues/8877
答案 2 :(得分:1)
如果您运行该代码,则会发现android是官方目标平台 列为GOOS / GOARCH
$go tool dist list
答案 3 :(得分:0)
您需要使用Android NDK进行android编译,可以从链接或从Android Studio下载:
然后您可以在以下路径中找到编译器链接:
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
然后您可以使用一个反射g:
aarch64
Android 30
您可以在此处看到availbe选项的完整列表,并且可以选择想要的aarch64-linux-android30-clang
如果您位于Windows 10
,则会在以下位置找到它:
"C:\Users\${user}\AppData\Local\Android\Sdk\ndk\${NKD_version}\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android30-clang"
有4个可用的链接器:
//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
在那之后,您只能进行交叉扫描,如下所示:
$ 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
一个简单的cgo
文件lib.go
可能是:
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() {}
如图所示,编译成功完成,并且lib-aarch64-android30.so
和ib-aarch64-android30.h
均已生成,没有任何错误。
快速说明,如果您返回一个字符串,请不要超出问题的范围,如果调用它,则必须在C代码中显式释放此函数 的返回值来自C
代码,但是正如您从垃圾收集器环境Java / Kotlin中调用它那样,您不必担心。
如果释放分配的缓冲区不方便,则通常会填充调用方提供的缓冲区:
func GetKey(buff *C.char, n int) int
如果可以分配内存但不想处理C字符串,则可以将缓冲区插入指针并返回大小。
func GetKey(buff **C.char) int