为什么amd64架构的Go程序能在M1芯片的Mac上成功运行
熟悉Go语言的同学都知道,Go语言支持跨平台编译,在任何系统(OS, Operating System)及处理器架构(Architecture)下编写代码,你都可以编译出可在其他任何操作系统和CPU架构的机器上独立运行的二进制可执行文件,体现出了Go语言强大的可迁移性。
如果要编译出在Mac系统下可执行的Go语言程序,那么需要设置Go环境变量后进行编译
- 目标机器是M1芯片(arm64指令集):
GOOS=darwin GOARCH=arm64 - 目标机器是Intel芯片(x86_64指令集):
GOOS=darwin GOARCH=amd64
但是其实编译出的两个二进制文件在M1芯片的Mac上都可以成功运行,这是由于 Apple M系列芯片(Apple Silicon)的MacOS默认集成了Rosetta环境,当你的程序是x86_64 指令集的情况下,Rosetta会自动转译你的App然后执行,这个过程用户是无感知的,所以M系列的芯片才能够运行Intel时代的Mac软件。
详情请阅读apple开发社区的rosetta转译文档:developer.apple.com/documentati…
我们通过一个简单的Go APP 来举例说明
根据官网的说明,我们可以获取系统调用sysctl.proc_translated的返回值来判断程序是否经历了translation 过程
The example function returns the value
0for a native process,1for a translated process, and-1when an error occurs.
新建一个临时目录hello, 里面创建一个hello.go,代码如下
package main
import (
"fmt"
"syscall"
)
// translated returns a string whether an app is translated
func translated() uint32 {
ret, err := syscall.SysctlUint32("sysctl.proc_translated")
if err != nil {
return uint32(0)
}
return ret
}
func main() {
ret := translated()
if ret == 1 {
fmt.Printf("Hello! The App runs after being translated by rosetta\n")
} else {
fmt.Printf("Hello! The App runs natively on apple silicon\n")
}
}
在命令行运行arm64 架构的编译命令
GOOS=darwin GOARCH=arm64 go build hello.go并执行生成的hello, 结果如下
$./hello
Hello! The App runs natively on apple silicon
在命令行运行amd64 架构的编译命令,
GOOS=darwin GOARCH=amd64 go build hello.go并执行生成的hello, 结果如下, 结果表明程序经过了rosetta转译然后执行的。
$./hello
Hello! The App runs after being translated by rosetta