使用Golang编译Android应用的完整指南
使用Golang编译Android应用的完整指南
我编写了下面的 build.go 来自动化交叉编译过程,但在 Android 上失败了,可能是什么原因:
package main
import (
"os"
"os/exec"
)
type compiles struct {
sys string
arch string
}
func main() {
var output string
// go tool dist list
systems := []compiles{
compiles{
sys: "darwin",
arch: "amd64",
},
compiles{
sys: "android",
arch: "amd64",
},
compiles{
sys: "linux",
arch: "amd64",
},
}
for _, s := range systems {
os.Setenv("GOOS", s.sys)
os.Setenv("GOARCH", s.arch)
switch println(s.sys); s.sys {
case "darwin":
output = "output.dmg"
case "android", "linux":
output = "output"
default:
println("Undefined")
}
cmd := exec.Command("go", "build", "-o", output, "main.go")
err := cmd.Run()
if err != nil {
println("cmd.Run() failed with %s\n", err)
}
}
}
我得到了以下输出:
C:\Users\hasan\Documents\GoPlay\Env>go run build.go
darwin
android
cmd.Run() failed with %s
(0xd9d6e0,0xc0000960e0)
linux
更多关于使用Golang编译Android应用的完整指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
内置的 println 函数已被弃用,不应再使用。应改用 fmt.Println。在你的例子中,由于使用了格式化指令,请使用 fmt.Printf 将:
println("cmd.Run() failed with %s\n", err)
改为:
fmt.Printf("cmd.Run() failed with %v\n", err)
在我的电脑上,这给了我以下信息:
> go run .\main.go
darwin
android
cmd.Run() failed with exit status 2
linux
要获取更多信息,请检查命令的 stdout 和 stderr:
cmd := exec.Command("go", "build", "-o", output, "main.go")
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("cmd.Run() failed with %v:\n\noutput:\n\n%s\n", err, out)
}
这给了我以下输出:
> go run .\main.go
darwin
android
cmd.Run() failed with exit status 2:
output:
# command-line-arguments
c:\go\pkg\tool\windows_amd64\link.exe: running gcc failed: exec: "gcc": executable file not found in %PATH%
linux
也许你遇到了类似的错误。
更多关于使用Golang编译Android应用的完整指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
非常感谢您详细的解答。在我的情况下,我遇到了这个错误:
C:\Users\hasan\Documents\GoPlay\Env>go run build.go
darwin
android
cmd.Run() failed with exit status 2:
output:
# command-line-arguments
c:\go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
gcc: error: unrecognized command line option '-rdynamic'
我在 macOS 上尝试了同样的操作,得到了:
cmd.Run() failed with exit status 2:
output:
# command-line-arguments
/usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1
ld: unknown option: -z
clang: error: linker command failed with exit code 1 (use -v to see invocation)
然后我在 Linux(Win10 上的 Ubuntu WSL)上尝试,得到了:
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/tmp/go-link-178415548/go.o:(.data+0x0): undefined reference to `x_cgo_callers'
/tmp/go-link-178415548/go.o:(.data+0x8): undefined reference to `x_cgo_init'
/tmp/go-link-178415548/go.o:(.data+0x10): undefined reference to `x_cgo_mmap'
/tmp/go-link-178415548/go.o:(.data+0x18): undefined reference to `x_cgo_munmap'
/tmp/go-link-178415548/go.o:(.data+0x20): undefined reference to `x_cgo_notify_runtime_init_done'
/tmp/go-link-178415548/go.o:(.data+0x28): undefined reference to `x_cgo_sigaction'
/tmp/go-link-178415548/go.o:(.data+0x30): undefined reference to `x_cgo_thread_start'
/tmp/go-link-178415548/go.o:(.data+0x38): undefined reference to `x_cgo_setenv'
/tmp/go-link-178415548/go.o:(.data+0x40): undefined reference to `x_cgo_unsetenv'
/tmp/go-link-178415548/go.o:(.data+0x48): undefined reference to `_cgo_yield'
collect2: error: ld returned 1 exit status
你的 build.go 脚本在编译 Android 时失败,主要原因是 Android 平台需要特定的 C 编译器和链接器。以下是关键问题和解决方案:
问题分析
- 缺少 Android NDK 工具链:Android 编译需要 NDK 中的 C 编译器
- 环境变量设置不完整:需要设置
CC和CXX指向 Android 工具链 - Android/amd64 目标不常见:通常 Android 使用 ARM 架构
修正后的代码示例
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
)
type compiles struct {
sys string
arch string
cc string // C 编译器路径
cxx string // C++ 编译器路径
flags string // 额外编译标志
}
func main() {
// 设置 Android NDK 路径(根据你的实际路径修改)
ndkPath := "/path/to/android-ndk"
systems := []compiles{
{
sys: "darwin",
arch: "amd64",
},
{
sys: "android",
arch: "arm64",
cc: filepath.Join(ndkPath, "toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang"),
cxx: filepath.Join(ndkPath, "toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++"),
flags: "-ldflags=-extldflags=-pie",
},
{
sys: "linux",
arch: "amd64",
},
}
for _, s := range systems {
fmt.Printf("编译 %s/%s...\n", s.sys, s.arch)
// 设置环境变量
os.Setenv("GOOS", s.sys)
os.Setenv("GOARCH", s.arch)
// 设置 C 编译器(Android 需要)
if s.cc != "" {
os.Setenv("CC", s.cc)
}
if s.cxx != "" {
os.Setenv("CXX", s.cxx)
}
// 构建输出文件名
output := fmt.Sprintf("output-%s-%s", s.sys, s.arch)
if s.sys == "darwin" {
output += ".dmg"
}
// 构建命令
args := []string{"build", "-o", output}
if s.flags != "" {
args = append(args, s.flags)
}
args = append(args, "main.go")
cmd := exec.Command("go", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Printf("编译 %s/%s 失败: %v\n", s.sys, s.arch, err)
} else {
fmt.Printf("编译 %s/%s 成功\n", s.sys, s.arch)
}
}
}
完整的 Android 编译示例
// 专门编译 Android 的示例
func buildAndroid() error {
// 设置 Android 编译环境
os.Setenv("GOOS", "android")
os.Setenv("GOARCH", "arm64")
os.Setenv("GOARM", "7")
// 设置 NDK 工具链(路径需要根据实际情况调整)
ndkPath := os.Getenv("ANDROID_NDK_HOME")
if ndkPath == "" {
ndkPath = "/usr/local/android-ndk"
}
// 设置 C 编译器
ccPath := filepath.Join(ndkPath, "toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang")
os.Setenv("CC", ccPath)
os.Setenv("CXX", ccPath+"++")
// 构建命令
cmd := exec.Command("go", "build",
"-o", "app-android-arm64",
"-ldflags", "-s -w",
"-buildmode=pie", // Android 需要 PIE
"main.go")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
使用 gomobile 的替代方案
// 使用 gomobile 编译 Android APK
func buildWithGomobile() error {
// 安装 gomobile
exec.Command("go", "install", "golang.org/x/mobile/cmd/gomobile@latest").Run()
exec.Command("gomobile", "init").Run()
// 编译为 Android 库
cmd := exec.Command("gomobile", "build",
"-target", "android",
"-androidapi", "21",
"-o", "app.apk",
".")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
关键注意事项
- 安装 Android NDK:
# 下载并设置 NDK
export ANDROID_NDK_HOME=/path/to/android-ndk
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
- 验证工具链:
func checkAndroidToolchain() error {
cc := os.Getenv("CC")
if cc == "" {
return fmt.Errorf("CC 环境变量未设置")
}
// 检查编译器是否存在
if _, err := os.Stat(cc); os.IsNotExist(err) {
return fmt.Errorf("Android 编译器不存在: %s", cc)
}
return nil
}
- 交叉编译标志:
// 完整的 Android 编译命令
cmd := exec.Command("go", "build",
"-o", "android-app",
"-ldflags", "-s -w -extldflags=-pie",
"-buildmode=pie",
"-tags", "android",
"main.go")
主要问题是缺少 Android NDK 工具链和正确的环境变量配置。Android 编译需要特定的 C 编译器,并且建议使用 ARM 架构而非 amd64。

