Madeira 实战:在 ARM 设备上通过 Wine、FEX-Emu 和 DXMT 运行 Windows 应用

发布时间:2026/10/1 5:45:35
Madeira 实战:在 ARM 设备上通过 Wine、FEX-Emu 和 DXMT 运行 Windows 应用 1. 从“Madeira”这个名字说起它到底想解决什么问题第一次看到“Madeira”这个项目名很多人会以为是某个葡萄酒品牌或者旅游项目但结合热搜词里的 Wine、FEX-Emu、DXMT、iOS、x86-64 这几个关键词方向就很清楚了——这是一个围绕在非 x86 平台尤其是 ARM 架构的移动设备上运行 Windows 应用与游戏的兼容层项目。Madeira 这个名字本身取自一种葡萄酒的产区和 Wine 的命名传统一脉相承属于这个圈子里约定俗成的“酒系命名法”。它要解决的问题非常具体你手上有一台 ARM 架构的设备比如搭载 Apple Silicon 的 Mac、iPad或者高通骁龙平台的安卓手机、平板你想在上面跑一个只有 Windows x86-64 版本的程序或者游戏。原生肯定跑不了指令集都不一样。传统的做法是虚拟机加完整 Windows 系统资源开销大、启动慢、图形性能差。Madeira 这类项目的思路是走翻译层路线把 x86-64 指令实时翻译成 ARM64 指令把 Windows 的图形 API 调用翻译成目标平台能理解的图形接口中间不经过完整的 Windows 内核从而把开销压到最低。适合谁来参考这篇文章三类人。第一类是移动端游戏玩家想在手机上跑一些经典的 PC 游戏或者 Windows 独占的小工具第二类是跨平台开发者需要在自己的 ARM 设备上验证 Windows 程序的兼容性第三类是对二进制翻译、图形 API 转换感兴趣的技术爱好者想搞清楚 Wine、FEX-Emu、DXMT 这套组合拳是怎么打出来的。不管你属于哪一类下面这些内容都是从实际折腾中攒出来的不是照搬文档。2. 核心组件拆解Wine、FEX-Emu、DXMT 各自扮演什么角色2.1 Wine不是模拟器是 API 翻译层很多人第一次接触 Wine 会误以为它是虚拟机或者模拟器其实都不是。Wine 的全称是 Wine Is Not an Emulator它做的事情是把 Windows 程序的系统调用翻译成宿主操作系统的对应调用。比如一个 Windows 程序调用CreateFileWine 会把它转换成 Linux 或 macOS 上的open系统调用。它不翻译 CPU 指令所以 Wine 本身只能在同架构下工作——x86 的 Windows 程序需要 x86 的宿主ARM 的 Windows 程序需要 ARM 的宿主。这就引出了一个问题如果我的设备是 ARM64但我想跑的 Windows 程序是 x86-64 编译的Wine 单独搞不定。这时候就需要 FEX-Emu 出场了。2.2 FEX-Emux86-64 到 ARM64 的指令翻译引擎FEX-Emu 是一个开源的 x86-64 到 ARM64 的二进制翻译器它的工作方式是指令块级别的动态翻译。程序运行时FEX-Emu 把 x86-64 的指令块翻译成 ARM64 指令块翻译结果会被缓存起来下次执行到同一块代码时直接走缓存不用重复翻译。这个缓存机制是性能的关键第一次运行会慢一些后面就快起来了。FEX-Emu 支持 x86-64 的大部分指令集包括 SSE4.2、AVX、AVX2 等常见扩展。但要注意AVX-512 的支持并不完整如果你要跑的程序重度依赖 AVX-512可能会遇到问题。另外FEX-Emu 对 32 位 x86 的支持是通过独立的 thunk 机制处理的配置起来比 64 位麻烦一些。2.3 DXMT把 Direct3D 调用翻译成 MetalDXMT 是“DirectX Metal Translation”的缩写顾名思义它把 Windows 上的 Direct3D 11 和部分 Direct3D 12 调用翻译成 Apple Metal 图形 API。为什么是 Metal 而不是 Vulkan因为在 Apple 生态里Metal 是官方主推的图形接口驱动层面的优化最好延迟最低。DXMT 通过 Wine 的图形驱动接口接入把 D3D 的着色器、纹理、渲染状态等转换成 Metal 对应的概念。DXMT 目前对 D3D11 的支持比较成熟D3D12 还在逐步完善中。如果你要跑的游戏是 D3D9 时代的DXMT 也能处理但更推荐用 DXVK 配合 MoltenVK 的路线兼容性更好。DXMT 的优势在于它直接对接 Metal省去了 Vulkan 这一层在 Apple Silicon 设备上通常能拿到更低的 CPU 开销。2.4 三者如何协同工作把这三个组件串起来看整个链路是这样的你启动一个 Windows 的 exe 文件Wine 负责加载 PE 格式的可执行文件解析导入表提供 Windows API 的实现。当程序执行到 x86-64 指令时FEX-Emu 接管把指令翻译成 ARM64 并执行。当程序调用 Direct3D 创建纹理、绘制三角形时DXMT 把这些调用转换成 Metal 命令提交给 GPU。这个链路里Wine 是“操作系统接口翻译”FEX-Emu 是“CPU 指令翻译”DXMT 是“图形接口翻译”。三者各司其职缺一不可。任何一个环节出问题程序都跑不起来或者跑不顺。3. 实际部署从零把 Madeira 跑起来的完整流程3.1 环境准备与依赖安装假设你在一台 Apple Silicon 的 Mac 上操作系统版本建议 macOS 14 以上Xcode Command Line Tools 必须装好。先装 Homebrew然后用它安装基础依赖brew install cmake ninja pkg-config python3 brew install molten-vk vulkan-loaderMoltenVK 是把 Vulkan 调用翻译成 Metal 的库虽然 DXMT 直接走 Metal但 Wine 的某些组件和部分游戏会用到 Vulkan所以还是装上比较稳妥。接下来克隆 FEX-Emu 的源码并编译。FEX-Emu 对编译器版本有要求建议用 LLVM 17 以上git clone https://github.com/FEX-Emu/FEX.git cd FEX git submodule update --init --recursive cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPERelease -DCMAKE_C_COMPILERclang -DCMAKE_CXX_COMPILERclang ninja -C build编译过程大概需要十几分钟取决于机器性能。编译完成后把build/Bin目录加到 PATH 里。3.2 Wine 的编译与配置Wine 的编译相对复杂一些因为要打上 FEX-Emu 和 DXMT 的补丁。建议直接用社区维护的 wine-crossover 或者 wine-staging 分支这些分支已经集成了不少 ARM64 相关的修复。git clone https://github.com/wine-mirror/wine.git cd wine ./configure --enable-win64 --disable-win16 --with-coreaudio --with-metal make -j$(sysctl -n hw.ncpu)编译完成后用wine64命令来运行 64 位 Windows 程序。注意在 ARM64 上编译 Wine 时--enable-win64是必须的因为 FEX-Emu 只处理 64 位指令翻译32 位程序需要额外的 thunk 层配置起来更麻烦。3.3 DXMT 的集成DXMT 通常以 DLL 的形式提供你需要把编译好的d3d11.dll、dxgi.dll、d3d10core.dll等文件放到 Wine 的lib/wine/x86_64-windows目录下覆盖原有的 DLL。然后在 Wine 的注册表里设置 DLL 覆盖wine reg add HKEY_CURRENT_USER\Software\Wine\DllOverrides /v d3d11 /t REG_SZ /d native /f wine reg add HKEY_CURRENT_USER\Software\Wine\DllOverrides /v dxgi /t REG_SZ /d native /f这样 Wine 就会优先加载 DXMT 提供的原生 DLL而不是内置的实现。3.4 首次运行与验证找一个简单的 Windows 程序测试比如 Notepad 的安装包。用 FEX-Emu 加载 Wine 来运行FEXBash wine64 notepad_installer.exe如果一切正常安装界面应该能弹出来。这时候你可以打开活动监视器看看进程的 CPU 占用。FEX-Emu 在翻译指令时会有额外的 CPU 开销通常在 20% 到 50% 之间具体取决于程序的指令密度。图形程序的开销会更高因为 DXMT 的翻译也有成本。4. 性能调优让 Madeira 跑得更顺的几个关键参数4.1 FEX-Emu 的缓存配置FEX-Emu 的指令翻译缓存默认放在~/.fex-emu/目录下。如果你的 SSD 空间充足可以把缓存目录设到更快的盘上减少翻译结果的读写延迟。在~/.fex-emu/Config.json里可以调整{ CachePath: /path/to/fast/ssd/fex-cache, Multiblock: true, SMCChecks: MTrack }Multiblock开启后FEX-Emu 会把多个基本块合并翻译减少翻译次数对循环密集的程序提升明显。SMCChecks设为MTrack可以更精确地跟踪自修改代码避免不必要的缓存失效。4.2 DXMT 的着色器缓存DXMT 会把翻译后的 Metal 着色器缓存到磁盘上下次运行同一游戏时直接加载省去翻译时间。缓存目录默认在~/Library/Caches/DXMT/下。如果你经常切换游戏可以定期清理这个目录避免缓存文件过多导致加载变慢。另外DXMT 支持异步着色器编译在配置里开启后游戏加载时不会因为编译着色器而卡顿[DXMT] AsyncShaderCompilation True MaxShaderCacheSize 4096MaxShaderCacheSize单位是 MB根据你的硬盘空间调整。4.3 Wine 的注册表优化Wine 的默认配置偏向兼容性性能上比较保守。可以调整几个注册表项来提升响应速度wine reg add HKEY_CURRENT_USER\Software\Wine\Direct3D /v MaxVersionGL /t REG_DWORD /d 4 /f wine reg add HKEY_CURRENT_USER\Software\Wine\Direct3D /v VideoMemorySize /t REG_SZ /d 4096 /fMaxVersionGL设为 4 是告诉 Wine 可以用 OpenGL 4.x 的特性虽然 DXMT 走 Metal但某些辅助功能会用到 OpenGL。VideoMemorySize根据你的 GPU 显存来设Apple Silicon 是统一内存架构设成系统内存的一半左右比较合理。5. 常见问题与排查技巧实录5.1 Wine 中文乱码怎么处理这是被问得最多的问题。Wine 默认的字体配置里没有包含中文字体所以中文程序显示出来全是方块或者乱码。解决办法是把系统中文字体链接到 Wine 的字体目录ln -s /System/Library/Fonts/PingFang.ttc ~/.wine/drive_c/windows/Fonts/然后在 Wine 的注册表里把默认字体替换成中文字体wine reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes /v MS Shell Dlg /t REG_SZ /d PingFang SC /f wine reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes /v MS Shell Dlg 2 /t REG_SZ /d PingFang SC /f如果还是乱码检查一下~/.wine/system.reg里的FontSubstitutes段确保没有冲突的条目。5.2 游戏启动黑屏或者闪退黑屏通常和图形接口有关。先确认 DXMT 的 DLL 是否正确加载可以在启动时加上WINEDEBUGd3d11环境变量看日志里有没有 DXMT 的初始化信息。如果日志显示d3d11.dll加载的是 Wine 内置版本而不是 DXMT说明 DLL 覆盖没生效检查注册表里的DllOverrides设置。闪退的话先看 FEX-Emu 的日志。在~/.fex-emu/Config.json里把LogLevel调到Info或者Debug重新运行程序看日志里有没有Unhandled instruction或者SIGILL之类的错误。如果有说明程序用到了 FEX-Emu 不支持的指令这种情况只能等 FEX-Emu 更新或者找替代方案。5.3 性能不如预期怎么排查先确认 FEX-Emu 的缓存是否生效。第一次运行程序时CPU 占用会很高因为要翻译指令。第二次运行同一程序如果 CPU 占用明显下降说明缓存起作用了。如果第二次还是很高检查缓存目录的权限和磁盘空间。图形性能方面用 Metal System Trace 工具抓一下 GPU 的时间线看看瓶颈在 DXMT 的翻译层还是 GPU 本身。如果 DXMT 的翻译占用了大量 CPU 时间可以尝试降低游戏的分辨率或者关闭一些特效减少需要翻译的 D3D 调用数量。5.4 常见问题速查表问题现象可能原因排查方法解决方向中文显示为方块缺少中文字体检查 Wine 字体目录链接系统中文字体并设置替换启动黑屏DXMT 未加载查看 d3d11 调试日志检查 DLL 覆盖注册表闪退不支持的指令查看 FEX-Emu 日志等待更新或换程序版本性能低下缓存未生效对比两次运行的 CPU 占用检查缓存目录权限音频卡顿音频后端延迟高检查 Wine 音频设置切换音频后端或调整缓冲区6. 移动端场景iOS 上的 Madeira 能做什么6.1 iOS 平台的限制与可能性iOS 是一个封闭系统普通应用不能直接执行外部下载的可执行文件也不能动态加载未经签名的代码。这意味着在 iOS 上跑 Wine 和 FEX-Emu必须通过特定的开发者工具或者企业签名的方式把整个运行环境打包成一个 IPA 安装包。热搜词里出现的“iOS 开发者模式”“Xcode 打包”“免费证书”这些都和这个流程有关。目前社区里有一些项目在尝试把 Wine 移植到 iOS 上思路是把 Wine 的 ARM64 版本编译成 iOS 能加载的动态库然后通过一个宿主应用来调用。FEX-Emu 在 iOS 上的运行需要 JIT 权限而 iOS 默认不允许普通应用使用 JIT除非开启开发者模式或者使用特定的 entitlement。这就是为什么“iOS 开发者模式”会成为热搜词——不开这个模式FEX-Emu 根本跑不起来。6.2 实际能跑什么在 iOS 上Madeira 这套方案目前能跑的东西比较有限。简单的 Windows 工具类程序比如文本编辑器、计算器、老式的小游戏成功率比较高。复杂的 3D 游戏尤其是依赖 D3D12 或者大量 AVX 指令的基本跑不动一方面是性能不够另一方面是兼容性问题太多。如果你只是想在 iPad 上跑一个 Windows 版的记事本或者文件管理器这套方案是可行的。但如果你指望用它来玩最新的 3A 大作现实会告诉你答案。6.3 安装与配置的注意事项在 iOS 上部署这套环境最大的坑是签名和权限。免费证书签名的应用只有 7 天有效期过期后需要重新签名。开发者模式虽然能延长一些但也不是永久的。另外iOS 对后台进程的限制很严格Wine 运行时的内存占用如果超过系统限制会被直接杀掉。建议在 iPad 上操作时关闭所有不必要的后台应用给 Wine 留出足够的内存。如果遇到闪退先看系统日志里有没有Jetsam相关的记录那说明是内存不足导致的。7. 跨平台扩展从 macOS 到 Linux ARM 的迁移思路7.1 Linux ARM 上的差异在 Linux ARM 设备上比如树莓派 5 或者一些 ARM 服务器Madeira 的部署方式和 macOS 有相似之处但图形接口不同。Linux 上没有 MetalDXMT 用不了需要换成 DXVK 加 Vulkan 的路线。DXVK 把 D3D 调用翻译成 Vulkan然后由 Mesa 的 Vulkan 驱动比如 Panfrost、PanVK提交给 GPU。FEX-Emu 在 Linux ARM 上的运行和 macOS 上基本一致但要注意内核版本和页大小。有些 ARM 设备用的是 64KB 页大小FEX-Emu 对这种情况的支持还在完善中可能会遇到对齐问题。7.2 统信和麒麟平台的兼容组件热搜词里出现了“统信 Wine Windows 兼容组件下载”“麒麟 Wine 助手”这些说明国产 Linux 发行版也在做类似的事情。这些平台通常会把 Wine 和相关的兼容层打包成 deb 或者 rpm用户直接安装就行不用自己编译。但版本可能比较旧对新游戏的支持不如自己编译的最新版。如果你在这些平台上折腾建议先确认系统自带的 Wine 版本如果太旧可以考虑用 Flatpak 或者 Snap 安装新版本的 Wine再手动配置 FEX-Emu 和 DXVK。7.3 迁移时的检查清单从 macOS 迁移到 Linux ARM需要重新确认的东西不少。图形接口从 Metal 换成 VulkanDLL 覆盖的配置要重做。音频后端从 CoreAudio 换成 PulseAudio 或者 PipeWireWine 的音频设置也要调整。文件系统的路径结构不同Wine 的 prefix 需要重新创建。最省事的做法是不要迁移直接在目标平台上重新部署一套。Wine 的 prefix 里有很多平台相关的配置跨平台复制容易出问题。8. 我踩过的坑和攒下的经验第一个坑是 FEX-Emu 的缓存目录权限。在 macOS 上如果缓存目录放在外置硬盘或者网络盘上FEX-Emu 可能会因为文件锁的问题无法写入缓存导致每次运行都要重新翻译指令性能直接腰斩。解决办法是把缓存目录放在本地 SSD 上并且确保当前用户有读写权限。第二个坑是 DXMT 的着色器缓存和游戏版本不匹配。有些游戏更新后着色器代码变了但 DXMT 还在用旧的缓存导致渲染错误或者崩溃。遇到这种情况删掉~/Library/Caches/DXMT/下对应的缓存文件让 DXMT 重新编译。第三个坑是 Wine 的注册表配置被覆盖。有些安装程序会修改 Wine 的注册表把 DLL 覆盖设置改回去导致 DXMT 失效。建议在安装完程序后重新检查一遍DllOverrides的设置确保没有被改掉。第四个坑是 iOS 上的内存限制。iPad 的内存虽然不小但 iOS 对单个进程的内存占用有硬性限制超过就会被系统杀掉。跑 Wine 的时候尽量用轻量级的程序不要同时开多个 Windows 应用。如果一定要跑大程序可以考虑用Jetsam相关的工具监控内存占用提前预警。最后一个经验是不要追求一次配置到位。Wine 和 FEX-Emu 的配置是一个迭代的过程先让程序能跑起来再逐步调优。每次只改一个参数改完测试确认有效再改下一个。这样出问题的时候容易定位是哪个改动导致的。一上来就照着网上的“最优配置”抄往往因为环境差异跑不起来还找不到原因。