1. 从“Madeira”这个名字说起:它到底想解决什么问题
第一次看到“Madeira”这个项目名,很多人会以为是某个葡萄酒产区或者旅游地。但在我们这圈折腾跨平台兼容层的人眼里,它指向的是一类非常具体的东西:在非 x86 架构的设备上,把 x86-64 的 Windows 程序跑起来。结合热搜词里的 FEX-Emu、Wine、DXMT、iOS、x86-64,基本可以锁定它的技术坐标——这是一套围绕 ARM 设备(尤其是移动端和国产化桌面端)构建的 Windows 应用兼容方案。
我先把结论摆前面:Madeira 这类项目的核心价值,不是“再造一个 Wine”,而是把FEX-Emu(x86-64 指令翻译)+ Wine(Windows API 实现)+ DXMT(Direct3D 到 Metal 的转换)这三层拼成一条完整的链路,让一个原本只能在 x86 Windows 上跑的 exe,能在 ARM 芯片的设备上启动、渲染、交互。它解决的是“架构不通”和“系统不通”这两个叠加的鸿沟。
适合谁看?三类人。第一类是在国产化平台(麒麟、统信 UOS、deepin)上做应用适配的工程师,你们大概率已经被“wine 乱码”“wine 栏是乱码”“统信 wine windows 兼容组件下载”这些问题折磨过。第二类是在 iOS 侧做自动化、模拟器、WebView 相关开发的同学,热搜里“ios 设备模拟”“ios 自动化”“抖音 ios webview 不能自动播放”都是你们的日常。第三类是对指令翻译、图形 API 转换感兴趣,想自己动手搭一套兼容层玩玩的折腾党。
我下面会按“整体设计思路 → 核心组件拆解 → 实操搭建 → 问题排查”这条线走,尽量把每一步的“为什么”讲清楚,而不是只丢一堆命令让你抄。踩过的坑我也会标出来,省得你重复交学费。
2. 整体架构设计:为什么是 FEX-Emu + Wine + DXMT 这个组合
2.1 三层翻译链路的分工逻辑
要理解 Madeira 的设计,得先明白一个 x86-64 Windows 程序在 ARM 设备上运行,中间要跨过几道坎。
第一道坎是指令集。ARM 和 x86-64 的机器码完全不兼容,一个 exe 里的二进制指令,ARM 芯片根本不认识。这就需要指令翻译层,FEX-Emu 干的就是这件事——它把 x86-64 指令动态翻译成 ARM64 指令。为什么选 FEX-Emu 而不是 QEMU?因为 QEMU 是重量级的全系统模拟,性能损耗大;FEX-Emu 是用户态的、针对游戏和桌面应用优化的翻译器,它甚至能利用 ARM 的一些特性做寄存器映射,实测在同类方案里帧率和启动速度都更占优。
第二道坎是系统 API。就算指令翻译过去了,程序调用的CreateFileW、RegOpenKeyEx这些 Windows API,Linux 或 iOS 上根本没有。Wine 就是来填这个坑的,它把 Windows API 翻译成 POSIX 调用。注意 Wine 不是模拟器,它是“兼容层”,这也是为什么它比虚拟机轻量得多。
第三道坎是图形 API。Windows 程序大量用 Direct3D 9/11/12 渲染,而 ARM 设备上主流是 Vulkan 或 Metal。DXMT 的作用就是把 D3D 调用转成 Metal(在 Apple 平台)或配合 DXVK 转成 Vulkan(在 Linux 平台)。热搜里出现 DXMT 而不是 DXVK,说明 Madeira 很可能重点面向 Apple 生态,因为 DXMT 是专门为 Metal 写的。
提示:这三层是串联的,任何一层出问题,程序都跑不起来。排查时一定要先确认是哪一层挂了,别一上来就瞎改配置。
2.2 为什么不用“一个大而全”的方案
有人会问,为什么不直接用一个虚拟机把整个 Windows 跑起来?答案很简单:性能和资源。在移动设备或者国产化终端上,虚拟机的开销是灾难性的,内存、电量、发热都扛不住。而 Madeira 这种分层方案,每一层只做自己该做的事,指令翻译只翻译真正执行的代码,API 转换只处理被调用的接口,图形转换只处理渲染指令,整体开销小得多。
另一个原因是可维护性。FEX-Emu、Wine、DXMT 都是独立演进的开源项目,Madeira 把它们编排在一起,任何一层升级都能单独替换。如果做成一个大单体,升级一次就得整体回归测试,维护成本高到离谱。
2.3 目标场景与设备画像
从热搜词能反推出 Madeira 的目标场景相当广。一边是“麒麟 wine 助手”“统信 wine windows 兼容组件下载”“wine deepin 无法下载”,说明国产 Linux 桌面是主战场之一;另一边是“ios 设备模拟”“ios 游戏”“ios 自动化”,说明 Apple 移动端也在射程内。这两类场景的共同点是:芯片是 ARM,系统不是 Windows,但用户有强烈的 Windows 应用需求。
设备画像大致是这样:CPU 是 ARM64(比如 Apple Silicon 或国产 ARM 芯片),内存 8GB 起步(16GB 更稳),系统是 Linux 发行版或 iOS/iPadOS。低于这个配置,跑轻量程序还行,稍微重一点的就会卡。
3. 核心组件深度拆解:每一层都在干什么
3.1 FEX-Emu:x86-64 到 ARM64 的翻译引擎
FEX-Emu 的工作方式,可以类比成“同声传译”。程序执行到哪条 x86 指令,它就实时翻译成 ARM64 指令再执行,翻译结果还会缓存起来,下次遇到同样的代码块直接复用,这就是所谓的 JIT(即时编译)缓存。
它的关键配置项有几个必须搞清楚。FEX_APP_CONFIG用来指定配置文件路径,FEX_ROOTFS指向一个 x86-64 的根文件系统(因为很多程序需要 x86 的库文件),FEX_TSOENABLED控制是否开启 x86 的内存序模拟——这个开关很关键,开了兼容性好但慢,关了快但可能出诡异 bug。我的经验是,先开着跑通,再逐个程序尝试关闭。
还有一个容易忽略的点:FEX-Emu 对 CPU 特性有要求。ARM 芯片必须支持某些指令集扩展,否则翻译出来的代码会崩。实测在较老的 ARM 芯片上,某些 SSE/AVX 指令翻译会失败,表现为程序启动到一半直接退出,日志里能看到 “unhandled instruction” 之类的字样。
3.2 Wine:Windows API 的“翻译字典”
Wine 的复杂度在于,Windows API 有成千上万个函数,每个函数的行为细节都要尽量对齐。热搜里“wine 乱码”“wine 栏是乱码”就是典型问题——本质是字符编码和字体缺失。Windows 程序默认用 GBK 或 UTF-16,而 Linux 环境默认 UTF-8,中间转换没做好就乱码。
解决乱码的标准动作是三步。第一,确认LANG和LC_ALL环境变量设置正确,一般设成zh_CN.UTF-8。第二,安装中文字体,把 Windows 的字体(比如 simsun.ttc、msyh.ttf)拷到 Wine 的字体目录,或者用winetricks装corefonts和cjkfonts。第三,检查 Wine 的注册表里字体替换项有没有配对。
Wine 的版本选择也有讲究。稳定版(stable)适合生产环境,开发版(devel)新功能多但可能引入回归,staging 版带一些实验性补丁。Madeira 这种项目一般会锁定一个经过验证的版本,你自己折腾时别盲目追新。
3.3 DXMT:Direct3D 到 Metal 的桥梁
DXMT 是这三层里最“年轻”的组件,它的任务是把 D3D 的绘制调用翻译成 Metal 的绘制调用。为什么 Apple 平台需要它?因为 macOS 和 iOS 上根本没有 Direct3D,只有 Metal。没有 DXMT,Windows 游戏和图形程序就是黑屏。
DXMT 目前对 D3D11 的支持比较成熟,D3D12 还在完善中。配置上主要关注DXMT_DEVICE(指定用哪个 GPU)和DXMT_MAX_FRAME_LATENCY(控制帧延迟,影响输入手感)。实测下来,帧延迟设成 1 或 2 比较跟手,设太高会有明显的操作延迟。
注意:DXMT 和 DXVK 不要同时启用,两者会抢图形后端,导致崩溃。在 Apple 平台用 DXMT,在 Linux 平台用 DXVK,二选一。
3.4 组件之间的依赖关系表
| 组件 | 作用 | 依赖 | 常见问题 |
|---|---|---|---|
| FEX-Emu | x86-64 指令翻译 | ARM64 CPU、x86 rootfs | 指令不支持、性能低 |
| Wine | Windows API 实现 | 字体、注册表、DLL | 乱码、缺 DLL、崩溃 |
| DXMT | D3D 转 Metal | Metal 驱动、GPU | 黑屏、花屏、帧延迟高 |
这张表建议存下来,排查问题时按行对照,能快速定位是哪一层的事。
4. 实操搭建:从零把 Madeira 跑起来
4.1 环境准备与依赖安装
先说 Linux 侧(以国产化平台为例)。你需要一个 ARM64 的 Linux 系统,内核版本别太老,建议 5.10 以上。基础依赖包括build-essential、cmake、ninja-build、python3、libgl1-mesa-dev、libvulkan-dev等。如果系统自带包管理器,直接装;如果没有,手动编译。
sudo apt update sudo apt install -y build-essential cmake ninja-build python3 python3-pip \ libgl1-mesa-dev libvulkan-dev libsdl2-dev libfontconfig1-dev然后是 x86-64 的 rootfs。这个不能省,因为很多 Windows 程序依赖 x86 的库。可以用 debootstrap 构建一个最小 x86-64 系统,或者直接下载现成的 rootfs 镜像。构建命令大致如下:
sudo debootstrap --arch=amd64 bullseye /opt/fex-rootfs http://deb.debian.org/debian构建完记得把/opt/fex-rootfs路径写进 FEX 的配置,否则 FEX 找不到库文件。
4.2 FEX-Emu 的编译与配置
FEX-Emu 官方推荐用源码编译,因为预编译包不一定匹配你的系统。克隆仓库后,用 CMake 配置:
git clone https://github.com/FEX-Emu/FEX.git cd FEX git submodule update --init --recursive mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_ASSERTIONS=OFF .. make -j$(nproc) sudo make install编译参数里ENABLE_ASSERTIONS=OFF很重要,开着断言会拖慢性能。装完后配置环境变量:
export FEX_ROOTFS=/opt/fex-rootfs export FEX_APP_CONFIG=/etc/fex/config.json export FEX_TSOENABLED=1FEX_TSOENABLED=1是保守选择,先保证兼容性。等程序跑通了,再试着设成 0 看性能有没有提升。
4.3 Wine 的安装与中文字体修复
Wine 的安装方式取决于系统。国产化平台一般有自带的 wine 包,但版本可能偏旧。我建议用 WineHQ 的官方源装 staging 版,功能全一些。
sudo dpkg --add-architecture amd64 sudo apt update sudo apt install -y winehq-staging装完先跑winecfg,把 Windows 版本设成 Win10 或 Win11,然后把字体问题解决掉。把 Windows 的字体文件拷到~/.wine/drive_c/windows/Fonts/,再在注册表里做替换:
wine reg add "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes" \ /v "MS Shell Dlg" /t REG_SZ /d "SimSun" /f这一步做完,大部分“wine 乱码”问题就消失了。如果还有个别程序乱码,检查它是不是用了自定义字体,单独处理。
4.4 DXMT 的部署与图形后端选择
DXMT 需要从源码编译,依赖 Metal 框架(Apple 平台)或 Vulkan(Linux 平台)。在 Apple 平台上:
git clone https://github.com/3Shain/dxmt.git cd dxmt mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. make -j$(nproc)编译产物是几个 dll 文件,把它们放到 Wine 的system32目录,然后在 Wine 配置里把 D3D 的 dll 覆盖项设成 native。这样程序调用 D3D 时就会走 DXMT。
提示:DXMT 的 dll 覆盖一定要在
winecfg的 Libraries 标签页里设置,直接拷文件不生效。
4.5 完整启动流程与验证
所有组件就位后,启动一个 Windows 程序的流程是这样的:
- 确认 FEX 环境变量已设置。
- 用
FEXBash进入 x86-64 环境(或者直接用 FEX 的 loader)。 - 在 Wine 前缀里运行 exe:
wine your_app.exe。 - 观察日志,确认 FEX 翻译正常、Wine 没报缺 DLL、DXMT 初始化成功。
验证是否成功,最简单的办法是跑一个带界面的小程序,看窗口能不能出来、文字是不是正常、有没有花屏。如果窗口出来了但黑屏,八成是 DXMT 的问题;如果窗口都没出来,先查 Wine 和 FEX。
5. 常见问题与排查技巧实录
5.1 乱码问题的系统化排查
“wine 乱码”是最高频的问题,我把它拆成一张速查表:
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| 菜单栏全是方块 | 缺中文字体 | 装 cjkfonts,拷 simsun |
| 部分文字乱码 | 编码不匹配 | 检查 LANG/LC_ALL |
| 输入框乱码 | 输入法未配置 | 配 fcitx/ibus 的 Wine 桥接 |
| 标题栏乱码 | 字体替换未生效 | 改注册表 FontSubstitutes |
排查顺序建议从字体开始,再到编码,最后到输入法。别一上来就改编码,很多时候就是字体没装。
5.2 程序启动崩溃的定位方法
程序启动就崩,日志是关键。FEX 的日志用FEX_LOG_LEVEL=debug打开,Wine 的日志用WINEDEBUG=+all打开(注意这个日志量巨大,建议重定向到文件)。看日志时重点找这几类信息:
unhandled instruction:FEX 翻译失败,说明遇到了不支持的 x86 指令。err:module:import_dll:Wine 缺 DLL,需要补。DXMT: failed to create device:DXMT 初始化失败,检查 Metal/Vulkan 驱动。
我踩过的一个坑是:某个程序在 FEX 里跑,日志显示翻译正常,但 Wine 报缺msvcp140.dll。补上这个 DLL 后还是崩,最后发现是 FEX 的 rootfs 里缺 x86 的 libc,导致 DLL 加载失败。所以 rootfs 一定要完整。
5.3 性能调优的几个关键开关
跑通之后,下一步是调性能。几个实测有效的开关:
FEX_TSOENABLED=0:关掉内存序模拟,性能提升明显,但个别程序会崩,需要逐个测试。DXMT_MAX_FRAME_LATENCY=1:降低帧延迟,操作更跟手。- Wine 的
WINEDLLOVERRIDES:把不必要的内置 DLL 设成 builtin,减少 native 调用开销。 - 关闭 FEX 的调试符号和断言,编译时就用 Release。
性能调优没有万能配置,得针对具体程序试。我的做法是准备两套配置,一套兼容优先,一套性能优先,按程序切换。
5.4 iOS 侧的特殊注意事项
如果 Madeira 涉及 iOS 侧(从热搜词看有这个可能),有几个点必须注意。iOS 的沙盒机制比 Linux 严格得多,Wine 那种直接读写文件系统的做法在 iOS 上要改。另外 iOS 的 Metal 版本和 macOS 不完全一样,DXMT 在 iOS 上可能需要额外适配。还有“ios 开发者模式”“ios 26.3.1 怎么开发者模式”这类问题,说明调试环境本身就要先搞定。
注意:iOS 上的自动化、模拟器相关操作,务必遵守平台规则和开发者协议,不要做越界的事。
6. 我在实际折腾中的几点体会
这套东西我从头搭过不止一次,最大的感受是:别指望一次成功,要把它当成一个排查游戏。每一层都有独立的日志和验证方法,先把 FEX 单独跑通(跑个 x86 的 hello world),再叠 Wine(跑个记事本),最后叠 DXMT(跑个 3D demo)。分层验证能省掉大量瞎猜的时间。
另一个体会是版本管理。FEX、Wine、DXMT 三个项目的版本组合很敏感,某个组合能跑,换个版本就崩。我建议用 git tag 锁定版本,把能跑通的组合记下来,别随便升级。国产化平台上“统信 wine windows 兼容组件下载”“麒麟 wine 助手下载”这些需求,本质就是用户想要一个开箱即用的版本组合,而不是自己编译。
最后分享一个小技巧:遇到诡异问题时,先清空 Wine 前缀重来。rm -rf ~/.wine然后重新winecfg,能解决相当一部分“配置污染”导致的玄学问题。这个操作成本低,但经常有奇效。