1. 从“Madeira”这个名字说起一个被低估的跨平台兼容层项目第一次看到“Madeira”这个项目名很多人会以为是某个葡萄酒产区的介绍或者是一个旅游类应用。但结合关键词里的 Wine、FEX-Emu、DXMT、x86-64 来看这其实是一个和跨平台二进制兼容、指令集翻译密切相关的技术项目。Madeira 的核心定位是让 x86-64 架构的 Windows 应用能够在 ARM 设备上跑起来而且不是那种“能启动就行”的勉强运行而是尽量做到图形、音频、输入都能正常工作的可用状态。我接触这类兼容层项目大概有几年时间了从最早的 Wine 在 Linux 上跑 Windows 程序到后来 Apple Silicon 上各种翻译层的出现再到如今 Madeira 这种把 Wine、FEX-Emu、DXMT 三者组合起来的方案整个技术路线其实一直在演进。Madeira 解决的问题很具体你手头有一台 ARM 架构的设备比如搭载 Apple Silicon 的 Mac或者某些 ARM 服务器、开发板但你需要的某个 Windows 软件只有 x86-64 版本没有原生 ARM 版本也没有网页版替代。这时候 Madeira 就是一座桥。它适合谁来参考如果你是一个喜欢折腾跨平台运行环境的开发者或者你需要在非 x86 设备上运行特定的 Windows 工具链再或者你对指令集翻译、图形 API 转换这些底层机制感兴趣那 Madeira 值得你花时间研究。但如果你只是想要一个“双击就能用”的成品软件那这类项目目前的成熟度还不足以让你完全省心需要有一定的排错能力和耐心。这篇文章我会从 Madeira 的架构组成讲起拆解 Wine、FEX-Emu、DXMT 各自扮演什么角色然后给出实际的部署思路和配置要点最后分享一些我在类似方案中踩过的坑和排查经验。内容会尽量贴近实际操作不堆砌理论让你看完能动手试。2. Madeira 的三层架构Wine 负责什么FEX-Emu 负责什么DXMT 又补了哪块短板2.1 Wine 提供 Windows API 兼容层但它不翻译指令集很多人对 Wine 的理解有偏差以为 Wine 是一个模拟器。其实 Wine 的全称是“Wine Is Not an Emulator”它做的是 API 转换不是指令集模拟。当你运行一个 Windows 程序时Wine 会把程序调用的 Windows API比如 CreateWindow、Direct3DCreate9 这些翻译成 POSIX 系统调用或者对应的图形库调用。程序本身的机器码还是直接在 CPU 上执行的。这就带来一个关键限制Wine 本身只能运行和宿主 CPU 同架构的 Windows 程序。如果你的设备是 x86-64那 Wine 可以直接跑 x86-64 的 Windows 程序但如果你的设备是 ARM 架构Wine 就无能为力了因为程序的机器码是 x86-64 的ARM CPU 不认识。所以在 Madeira 的架构里Wine 负责的是“Windows 程序以为自己在一个 Windows 系统上”这件事它处理注册表、文件系统路径映射、窗口管理、音频输出这些上层逻辑。但底层指令的执行Wine 管不了。2.2 FEX-Emu 填补指令集鸿沟把 x86-64 翻译成 ARM64FEX-Emu 就是解决上面那个问题的。它是一个 x86-64 到 ARM64 的指令集翻译层工作方式是在程序运行时动态地把 x86-64 指令翻译成 ARM64 指令。你可以把它理解为一个“实时翻译官”程序每执行一段 x86-64 代码FEX-Emu 就把它转换成等效的 ARM64 代码再交给 CPU 执行。FEX-Emu 的翻译不是逐条指令一一对应的它会做基本块级别的翻译和优化。所谓基本块就是一段没有跳转的连续指令序列。FEX-Emu 会把一个基本块整体翻译成 ARM64 代码缓存起来下次再执行到这个块就直接用缓存不用重新翻译。这个缓存机制对性能影响很大也是 FEX-Emu 能在实际使用中达到可接受速度的关键。但 FEX-Emu 也有它的边界。它主要针对用户态的 x86-64 指令对于某些特殊指令、系统调用、以及需要内核配合的功能支持程度有限。而且翻译本身有开销性能损失是必然的具体损失多少取决于程序的计算密集程度和 FEX-Emu 对特定指令模式的优化程度。2.3 DXMT 把 Direct3D 调用转成 Metal补齐图形性能短板Wine 自带的图形转换层在 macOS 上走的是 OpenGL 路线但 OpenGL 在 macOS 上已经被标记为废弃性能和新特性支持都不理想。DXMT 的出现就是为了解决这个问题它直接把 Direct3D 11 和部分 Direct3D 12 的调用翻译成 Metal API让 Windows 游戏和图形程序在 macOS 上能利用 Metal 的性能优势。DXMT 的工作层次在 Wine 的 Direct3D 实现和系统图形驱动之间。当 Windows 程序调用 D3D11CreateDevice 或者发出绘制命令时Wine 的 D3D 模块会把这些调用转给 DXMTDXMT 再转换成 Metal 的对应操作。这样做的好处是绕过了 OpenGL 这个中间层减少了转换开销同时能用到 Metal 的现代特性比如更高效的内存管理和多线程渲染。把这三者串起来看Wine 让 Windows 程序觉得“我在 Windows 上”FEX-Emu 让 ARM CPU 能执行 x86-64 指令DXMT 让图形调用走 Metal 而不是 OpenGL。三者缺一不可共同构成了 Madeira 在 ARM 设备上运行 x86-64 Windows 程序的完整链路。3. 部署 Madeira 之前必须想清楚的几件事环境、依赖与预期管理3.1 确认你的设备架构和系统版本Madeira 的目标运行环境是 ARM64 架构的设备目前最主要的场景是 Apple Silicon MacM1、M2、M3、M4 系列。如果你用的是 Intel Mac那其实不需要 FEX-Emu 这一层直接用 Wine 或者 CrossOver 就行指令集是原生匹配的。所以第一步是确认你的设备是不是 ARM64。在 macOS 上查架构很简单打开终端输入uname -m如果输出arm64说明你是 Apple Silicon如果输出x86_64那就是 Intel Mac。这个信息决定了你后续要不要部署 FEX-Emu。系统版本方面建议至少是 macOS 13 Ventura 或更高。原因有两个一是 Metal 的新特性在较新系统上才完整支持DXMT 依赖这些特性二是 FEX-Emu 在较新系统上的兼容性更好一些底层系统调用的行为在新系统上更稳定。3.2 依赖组件的获取与版本匹配Madeira 本身是一个整合方案它依赖多个上游项目的产物。你需要准备的东西包括Wine 的 ARM64 构建版本注意不是普通的 Wine而是专门为 ARM64 宿主编译的版本它内部会调用 FEX-Emu 来处理 x86-64 指令。FEX-Emu 的运行时库包括核心翻译引擎和相关的 rootfs 文件系统镜像。DXMT 的动态库通常是几个.dylib文件需要放到 Wine 的对应目录下。一个 Windows 程序的安装包或可执行文件用来测试整个链路是否跑通。版本匹配是这里最容易出问题的地方。Wine 的版本、FEX-Emu 的版本、DXMT 的版本之间有一定的对应关系版本错配可能导致程序启动失败、图形渲染异常、甚至整个 Wine 前缀崩溃。我的建议是优先使用 Madeira 项目官方推荐的版本组合不要自己随意混搭最新版。3.3 对性能和兼容性的合理预期在 ARM 设备上通过翻译层运行 x86-64 Windows 程序性能损失是客观存在的。根据我的实测经验CPU 密集型任务的性能大约是原生 x86-64 设备的 50% 到 70%具体取决于 FEX-Emu 对代码模式的优化程度。图形性能方面DXMT 转 Metal 的效率比 OpenGL 路线好不少但和原生 Metal 游戏相比仍有差距。兼容性方面不是所有 Windows 程序都能跑起来。依赖内核态驱动、需要特定硬件指令、或者使用了反作弊系统的程序基本上无法运行。办公类软件、老游戏、开发工具这类对系统底层依赖较少的程序成功率比较高。提示在正式部署之前先想清楚你要运行的具体程序是什么去 Madeira 或相关社区的兼容性列表里查一下有没有人成功运行过。如果没有先例做好折腾的准备。4. 从零搭建 Madeira 运行环境步骤拆解与关键配置说明4.1 创建独立的 Wine 前缀目录Wine 前缀prefix是 Wine 用来模拟 Windows 文件系统结构的目录里面包含drive_c、注册表文件、以及各种 Windows 系统库的替代实现。为每个应用创建独立的前缀是个好习惯因为不同程序对系统库版本、注册表设置的要求可能冲突。创建前缀的命令大致是这样的export WINEPREFIX$HOME/.madeira/prefix-test export WINEARCHwin64 wineboot --init这里WINEARCHwin64指定创建 64 位前缀因为我们要运行的是 x86-64 程序。wineboot --init会初始化前缀目录生成必要的文件结构。第一次执行会花一些时间因为要创建目录、复制基础文件、初始化注册表。初始化完成后你可以用winecfg打开配置界面检查一下 Windows 版本设置。对于大多数现代程序设置为 Windows 10 或 Windows 11 比较合适。如果程序比较老可能需要降到 Windows 7 或 XP。4.2 配置 FEX-Emu 的 rootfs 和运行参数FEX-Emu 需要一个 rootfs根文件系统来提供 x86-64 程序运行所需的基础库和系统调用接口。这个 rootfs 通常是一个包含 x86-64 版 glibc、libstdc 等库的目录树。你需要把 FEX-Emu 的 rootfs 路径配置到环境变量里export FEX_ROOTFS$HOME/.madeira/fex-rootfs export FEX_APP_CONFIG$HOME/.madeira/fex-config.jsonFEX-Emu 的配置文件里可以调整一些影响性能和兼容性的参数。比如TSOEnabled控制是否启用 x86 的内存序模型模拟开启后兼容性更好但性能略低Multiblock控制是否启用多块翻译优化开启后性能更好但可能在某些程序上出问题。这些参数需要根据具体运行的程序来调整没有一套万能配置。4.3 把 DXMT 放到 Wine 能找到的位置DXMT 的部署方式是把编译好的.dylib文件放到 Wine 前缀的drive_c/windows/system32目录下同时确保 Wine 的 DLL 加载顺序会优先加载 DXMT 而不是自带的 D3D 实现。具体来说你需要把d3d11.dll、dxgi.dll、d3d10core.dll这些替换成 DXMT 提供的版本。替换之前建议先备份原始文件万一出问题可以回滚。替换之后可以用WINEDEBUGd3d环境变量启动程序观察日志里加载的是哪个 D3D 实现。如果看到 DXMT 相关的日志输出说明替换生效了。4.4 安装并运行第一个测试程序建议从一个简单的、对图形要求不高的程序开始测试比如一个老版本的记事本替代品、或者一个 2D 小游戏。安装程序时用wine setup.exe如果安装程序能正常启动并完成安装说明 Wine 和 FEX-Emu 的基本链路是通的。然后尝试运行安装好的程序wine $WINEPREFIX/drive_c/Program Files/YourApp/app.exe第一次运行可能会比较慢因为 FEX-Emu 需要翻译和缓存指令块。第二次运行通常会快一些。如果程序窗口能正常显示、菜单能点击、文字能输入那基本就算跑通了。5. 实际运行中绕不开的坑乱码、崩溃、性能异常的排查思路5.1 Wine 界面和程序内文字乱码的根因与修复Wine 乱码是个老问题在 Madeira 这种多层架构下更容易出现。乱码的根因通常是字体缺失或者字符集映射不对。Wine 需要中文字体来正确渲染中文界面和程序内的中文文本如果前缀里没有安装合适的中文字体就会显示成方块或者乱码。修复方法是把系统中文字体复制到 Wine 前缀的字体目录cp /System/Library/Fonts/PingFang.ttc $WINEPREFIX/drive_c/windows/Fonts/然后修改注册表里的字体替换设置把MS Shell Dlg、MS Sans Serif这些默认字体映射到中文字体。可以用wine regedit打开注册表编辑器定位到HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes添加相应的映射项。如果乱码出现在特定的程序里而不是 Wine 自带界面那可能是程序使用了自定义字体或者特殊的字符编码。这种情况下需要具体分析程序的字体加载逻辑有时候把缺失的字体文件补上就能解决。5.2 程序启动即崩溃的几种常见原因程序启动就崩溃排查起来比较头疼因为可能的原因很多。我总结了几种最常见的情况第一种是缺少依赖的 Windows 运行库。很多程序依赖 Visual C Redistributable 或者 .NET Framework这些在纯净的 Wine 前缀里是没有的。解决办法是用winetricks安装对应的运行库winetricks vcrun2019 dotnet48第二种是 FEX-Emu 遇到了不支持的指令。某些程序使用了 AVX-512 或者特定的系统指令FEX-Emu 可能没有完整实现。这种情况下可以尝试在 FEX-Emu 配置里禁用相关指令的模拟或者换一个 FEX-Emu 版本。第三种是图形初始化失败。如果程序启动时需要创建 D3D 设备但 DXMT 没有正确加载就会直接崩溃。用WINEDEBUGd3d,dxgi启动可以看到详细的图形初始化日志定位是哪一步失败。5.3 性能远低于预期的调优方向如果程序能跑但卡得没法用可以从几个方向调优。首先是确认 FEX-Emu 的翻译缓存是否生效缓存目录是否有读写权限。缓存不生效会导致每次运行都重新翻译性能大幅下降。其次是检查 DXMT 是否真的在负责图形渲染。如果 DXMT 加载失败Wine 会回退到 OpenGL 实现性能会差很多。用WINEDEBUGd3d看日志里有没有 DXMT 的初始化信息。还有就是调整 FEX-Emu 的翻译参数。比如增大翻译缓存大小、启用多线程翻译、调整基本块合并策略等。这些参数在 FEX-Emu 的文档里有说明但需要根据具体程序反复试验才能找到最优组合。6. 兼容性边界与替代思路什么时候该放弃 Madeira6.1 明确无法运行的程序类型有些程序在 Madeira 上基本没有跑通的希望识别这些类型可以帮你节省大量时间。第一类是依赖内核态驱动的程序比如需要安装系统级驱动的杀毒软件、虚拟化软件、硬件检测工具。Wine 运行在用户态无法加载 Windows 内核驱动这类程序直接放弃。第二类是使用了反作弊系统的游戏。反作弊系统会检测运行环境发现是 Wine 或翻译层就会拒绝运行甚至封号。这类游戏不要尝试在 Madeira 上跑。第三类是对指令集有特殊要求的程序。比如某些科学计算软件使用了 AVX-512 指令集而 FEX-Emu 对 AVX-512 的支持不完整运行时会出错。这类程序可以尝试找老版本或者替代软件。6.2 替代方案对比虚拟机、远程桌面与原生替代如果 Madeira 跑不通你的目标程序还有几条路可以走。虚拟机方案是在 ARM 设备上跑一个 Windows ARM 虚拟机然后在虚拟机里运行程序。这种方案兼容性最好因为就是真正的 Windows 环境但性能开销大而且 Windows ARM 本身对 x86-64 程序也有翻译层是双层翻译性能更差。远程桌面方案是找一台 x86-64 的 Windows 机器通过网络远程连接使用。这种方案性能取决于网络质量本地设备只是显示和输入终端。适合对延迟不敏感的场景。原生替代方案是寻找功能相近的 macOS 原生软件或者网页版服务。这是最省心的方案但前提是存在可接受的替代品。6.3 社区资源与问题排查的常用入口Madeira 相关的社区资源主要集中在几个地方项目的代码仓库和 issue 列表、Wine 的官方论坛和 Wiki、FEX-Emu 的文档和讨论区、以及 DXMT 的项目页面。遇到问题时先在 issue 列表里搜索关键词很可能已经有人遇到并解决了。排查问题时日志是最好的朋友。Wine 的WINEDEBUG环境变量可以开启不同模块的详细日志FEX-Emu 也有自己的日志输出。把日志级别调高重现问题然后仔细阅读日志里的错误信息和警告通常能定位到根因。注意在社区提问时附上完整的日志、系统版本、各组件版本、以及你已经尝试过的步骤这样更容易得到有效的帮助。只写“跑不起来”这种描述没人能帮你。7. 我在多次部署中积累的几个实用技巧第一个技巧是关于前缀管理的。不要把所有程序都装在一个前缀里而是按程序或按程序类型分开。比如办公软件一个前缀、游戏一个前缀、开发工具一个前缀。这样某个前缀出问题时不会影响其他程序而且可以针对不同类型程序做不同的优化配置。第二个技巧是关于 FEX-Emu 缓存的。翻译缓存文件会随着使用不断增大时间长了可能占用几个 GB 的空间。定期清理不再使用的程序的缓存可以释放空间但注意不要清理正在使用的程序的缓存否则下次启动会变慢。第三个技巧是关于 DXMT 版本选择的。不是越新的版本越好有时候新版本引入了新特性但破坏了旧程序的兼容性。如果某个 DXMT 版本让你的程序跑得很稳除非有明确的需求否则不要轻易升级。第四个技巧是关于测试流程的。每次只改一个变量改完就测试确认有效再改下一个。同时改多个配置项出问题时就不知道是哪个改动导致的。这个原则在排查兼容性问题时尤其重要。第五个技巧是关于备份的。在做出任何可能影响前缀稳定性的操作之前先备份整个前缀目录。前缀目录可能很大但比起重新配置一遍所有环境备份恢复的时间成本要低得多。可以用tar打包压缩也可以直接用文件系统的快照功能。这些经验都是我在反复折腾中积累的有些是踩了坑才明白的。Madeira 这类项目本身还在演进中今天能用的配置明天可能就因为上游更新而失效。保持耐心做好记录遇到问题先看日志再动手改这样能少走很多弯路。
阅读完成 · 觉得有帮助?