Golang:在Mac上为Android编译“Hello World”

时间:2016-08-15 02:10:15

标签: android go cross-compiling cgo

我正在努力建立一个标准的“Hello,World!” Android的命令行可执行文件。可执行文件将通过adb shell运行。

0。 Go(Golang)来源

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, world!")
}

1A。构建命令

$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build .

1B。输出(换行重新排列以防止滚动条)

# 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)

1C。再次构建命令

以下命令给出了相同的结果:

$ env CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build .

2。构建命令(详细)

我尝试过如下所述使用"-v"

$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 go build \
      -x -ldflags "-extldflags -v" .

它给了我超过100行的消息,所以除非有必要,否则我不会在此发布。 go build命令似乎尝试使用clang捆绑的Xcode来编译源代码。

3A。构建命令(成功,但......)

鉴于提示找到了错误的编译器,我试图像这样设置$CC

$ CGO_ENABLED=0 GOOS=android GOARCH=arm GOARM=7 \
      CC=/path/to/arm-linux-androideabi/bin/clang go build .

arm-linux-androideabimake_standalone_toolchain.py(或make-standalone-toolchain.sh)的输出。

3B。输出

已成功构建可执行文件(名为cross),并显示以下消息:

# github.com/asukakenji/cross
warning: unable to find runtime/cgo.a

我尝试adb push并在Android上使用adb shell运行它,它运行正常。

我的问题

  1. 为什么需要C编译器?是不是开箱即用的交叉编译?
  2. 在为Linux(而不是Android)构建时,编译工作正常:

    $ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .
    

    为什么?

  3. go build命令一直在查找runtime/cgo.a,即使我在源代码中没有使用CGO,甚至在设置CGO_ENABLED=0时也是如此。我该如何摆脱警告?没有一个人怎么有害?
  4. 谢谢!

4 个答案:

答案 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下载:

enter image description here

然后您可以在以下路径中找到编译器链接:

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:

  1. 您要为其构建Android应用的架构,例如aarch64
  2. 您要为其编译的Android API,例如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() {}

enter image description here

如图所示,编译成功完成,并且lib-aarch64-android30.soib-aarch64-android30.h均已生成,没有任何错误。

快速说明,如果您返回一个字符串,请不要超出问题的范围,如果调用它,则必须在C代码中显式释放此函数 的返回值来自C代码,但是正如您从垃圾收集器环境Java / Kotlin中调用它那样,您不必担心。

如果释放分配的缓冲区不方便,则通常会填充调用方提供的缓冲区:

func GetKey(buff *C.char, n int) int

如果可以分配内存但不想处理C字符串,则可以将缓冲区插入指针并返回大小。

func GetKey(buff **C.char) int
相关问题