为什么amd64架构的Go程序能在M1芯片的Mac上成功运行

985 阅读2分钟

为什么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 0 for a native process, 1 for a translated process, and -1 when 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