跨平台构建概览
本教程共 42 篇 · 第 32 篇 · 更新于 2026-08-03
32. 跨平台构建概览
本节目标
- 说清楚 Wails 应用在三个操作系统上分别编译出什么东西
- 理解「Go 能交叉编译,Wails 却不能随便交叉编译」这件事的根源
- 记住每个平台构建前必须准备好的依赖
- 会查
-platform支持的取值表,知道darwin/universal是什么 - 能搭一条 GitHub Actions 矩阵流水线,一次产出三平台产物
32-1 三个平台各自产出什么
先把结论摆出来。同一份 Wails 代码,在不同系统上执行 wails build,落到 build/bin/ 目录里的东西并不一样。
| 平台 | 默认产物 | 常见分发形式 |
|---|---|---|
| Windows | 应用名.exe | 直接发 exe,或再生成 NSIS 安装包 |
| macOS | 应用名.app(一个目录形态的应用包) | 打成 .dmg 或 .zip |
| Linux | 无扩展名的可执行文件 | 直接发二进制,或再做 deb / rpm / AppImage |
有一点三端是一致的:前端资源被编译进了那个可执行文件里。构建时 Wails 会先跑 frontend:build,把 Vite 打出来的 HTML、JS、CSS 通过 Go 的 embed 塞进二进制。所以你不需要在 exe 旁边额外放一个 dist 文件夹。
Note
wails dev时前端是从磁盘实时读取的,改一行 CSS 立刻生效;wails build之后前端已经固化在二进制里,改磁盘上的文件不会有任何反应。这两种加载方式的区别在第 6 章讲过,构建阶段会再一次撞上它。
macOS 的 .app 需要单独说一句。它在 Finder 里看着像一个文件,实际是一个目录,里面有 Contents/MacOS/ 放可执行文件、Contents/Info.plist 放元数据、Contents/Resources/ 放图标。Wails 会用项目里的 build/darwin/Info.plist 来生成这份元数据。
Linux 那边最朴素,就是一个 ELF 可执行文件。但它不是完全自足的——运行时依赖系统上的 GTK3 和 WebKit2GTK 动态库,这点第 36 章会展开。
32-2 为什么 Wails 不能随便交叉编译
Go 的交叉编译好用到什么程度?设个 GOOS=windows GOARCH=amd64 就能在 Mac 上编出 Windows 程序。很多人第一次用 Wails 时会顺手试一下,然后发现编不过。
原因是 Wails 不是纯 Go 项目。它要调用各个平台的原生 WebView:
- Windows 走 WebView2,底层是 COM 接口
- macOS 走 WKWebView,底层是 Objective-C
- Linux 走 WebKit2GTK,底层是 C 库
这些调用统统经过 CGO。一旦启用 CGO,交叉编译就需要目标平台的 C 工具链和头文件,成本陡增。所以官方的建议很直白:在哪个系统上分发,就在哪个系统上构建。
Warning网上能搜到一些「在 Linux 上交叉编译 Windows 版 Wails」的偏方,通常靠 mingw 或 Docker 镜像。它们在特定版本下可能跑通,但不在官方支持范围内,升级 Wails 或系统后很容易碎掉。生产项目别把发布流程压在这种方案上。
那 -platform 这个参数还有什么用?它的主要价值在同一个操作系统内切换架构。比如在 Apple Silicon 的 Mac 上编 Intel 版:
wails build -platform darwin/amd64
这条命令能跑通,因为 Xcode 命令行工具自带了两种架构的 SDK。但在这台 Mac 上写 -platform windows/amd64 就不行了。
32-3 各平台的构建前置条件
真正开始构建前,把依赖补齐。三个平台的清单如下。
Windows
- Go 1.20 及以上
- Node.js LTS(跑前端构建)
- WebView2 Runtime(Windows 11 自带,Windows 10 部分机器需要装)
- 如果要生成安装包,还需要 NSIS,见第 34 章
macOS
- Go 1.20 及以上、Node.js LTS
- Xcode 命令行工具,装法是
xcode-select --install - 要签名和公证的话,需要 Apple 开发者账号,见第 35 章
Linux
- Go 1.20 及以上、Node.js LTS
- gcc、pkg-config
- GTK3 和 WebKit2GTK 的开发包
Debian 系的安装命令长这样:
sudo apt update
sudo apt install -y build-essential pkg-config libgtk-3-dev libwebkit2gtk-4.1-dev
Tip拿不准环境齐不齐,跑一次
wails doctor。它会扫描系统、列出每个依赖的安装状态,缺什么直接告诉你安装命令。构建报错先看它,比对着报错信息瞎猜快得多。
32-4 platform 参数支持哪些取值
-platform 接受的值是「操作系统/架构」的组合,逗号分隔可以一次给多个。v2.13.0 支持的完整列表:
| 取值 | 含义 |
|---|---|
darwin | macOS,架构跟随构建机 |
darwin/amd64 | macOS 10.13+ Intel |
darwin/arm64 | macOS 11.0+ Apple Silicon |
darwin/universal | 同时包含两种架构的通用二进制 |
windows | Windows 10/11,架构跟随构建机 |
windows/amd64 | Windows 10/11 x64 |
windows/arm64 | Windows 10/11 ARM64 |
linux | Linux,架构跟随构建机 |
linux/amd64 | Linux x64 |
linux/arm64 | Linux ARM64 |
darwin/universal 值得单独讲。它编出来的 .app 里塞了 Intel 和 Apple Silicon 两套机器码,两种 Mac 都能原生跑,代价是体积翻倍。对外分发 macOS 版本时一般就用它,省得维护两个下载链接。
只写 -platform windows 不写架构时,架构取 runtime.GOARCH,也就是构建机自己的架构。完全不给 -platform,则平台和架构都取构建机的。
32-5 用 GitHub Actions 一次产出三平台
不能交叉编译,难道要自备三台机器?不用。GitHub Actions 提供了三个平台的 runner,用矩阵策略跑一遍就够了。
下面这份工作流在推送 tag 时触发,三个平台并行构建,产物上传成 artifact:
name: Wails build
on:
push:
tags:
- '*'
env:
NODE_OPTIONS: "--max-old-space-size=4096"
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux/amd64
- os: windows-latest
platform: windows/amd64
- os: macos-latest
platform: darwin/universal
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Linux deps
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt update
sudo apt install -y build-essential pkg-config libgtk-3-dev libwebkit2gtk-4.1-dev
- name: Install Wails CLI
run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.13.0
- name: Build
run: wails build -platform ${{ matrix.platform }} -clean
- uses: actions/upload-artifact@v4
with:
name: app-${{ matrix.os }}
path: build/bin/*
几个细节解释一下。
fail-fast: false 让三个平台互不牵连,Linux 编挂了不影响 Windows 那条线继续跑完。默认值是 true,一个失败会把其他任务全部取消,调试时特别烦人。
NODE_OPTIONS 那行是给 Node 提内存上限的。CI 环境内存紧,前端体积大一点就可能因为 OOM 挂掉,提前设好省事。
安装 CLI 时我固定写了 @v2.13.0 而不是 @latest。构建产物的可复现性比「永远用最新版」更重要,CLI 版本一漂,某天的构建结果就跟上周不一样了。
Note社区还维护了一个现成的 Action:
dAppServer/wails-build-action,把上面这些步骤打包好了。想少写点 YAML 可以直接用;想完全掌控每一步,就照上面这份自己写。
跑通基本流程后,通常还会往上加这些东西:依赖缓存(Go module 和 node_modules)、代码签名、把产物挂到 GitHub Release、从 tag 里抽版本号通过 -ldflags 注入程序。这些都是在同一份工作流上叠加,不用推倒重来。
常见误区
以为 -platform windows/amd64 能在 Mac 上用。 前面说过,它只在同系统内切架构有效。写了跨系统的值,构建会在 CGO 环节报错。
忘了 Linux runner 要装 WebKit 开发包。 GitHub 的 ubuntu-latest 镜像不预装 libwebkit2gtk-4.1-dev,少这一步必挂。
在 CI 里用 @latest 装 CLI。 短期没事,时间一长就会遇到「上周还好好的,今天 CI 红了」,排查起来毫无头绪。
以为 Linux 二进制能到处跑。 它依赖系统的 GTK3 和 WebKit2GTK,不同发行版的库名和 ABI 版本都不同。这块坑不小,第 36 章专门讲。
小结
Wails 的跨平台构建,核心约束就一条:目标系统上构建,别指望交叉编译。理解了这条,剩下的都是工程问题——本地补齐依赖,CI 上用矩阵覆盖三个平台。
产物形态三端各异:Windows 是 exe,macOS 是 app 包,Linux 是裸二进制。前端资源都嵌在里面,不用额外分发。
下一章把 wails build 的参数逐个拆开讲,包括本章反复出现的 -platform、-clean,以及压缩、调试、跳过前端构建这些实用开关。