Madeira 跨平台兼容方案:Wine、FEX-Emu 与 DXMT 实战指南
1. 从“Madeira”这个名字说起它到底是什么第一次看到“Madeira”这个词很多人第一反应是葡萄牙那个产葡萄酒的海岛或者是一块叫马德拉的蛋糕。但在折腾跨平台兼容层的圈子里Madeira 指的是一套围绕 Wine 构建的、面向移动端和桌面端的 Windows 应用兼容方案。它要解决的问题很直接让原本只能在 Windows 上跑的 x86-64 程序在别的系统上也能跑起来尤其是 iOS 这类封闭生态。我接触这套东西的起因很朴素——手头有一堆老旧的 Windows 工具和游戏想在 iPad 上偶尔用一下又不想随身多带一台笔记本。市面上能查到的资料要么太碎要么停留在“能跑就行”的层面真正把 Wine、FEX-Emu、DXMT 这几层关系讲清楚的并不多。所以这篇内容我打算按自己实际踩坑的顺序把 Madeira 这套方案的来龙去脉、核心组件、实操步骤和常见故障一次讲透。适合谁看如果你对以下任意一条感兴趣这篇都值得往下读想在 iOS 或 Linux 上运行 Windows 程序听说过 Wine 但被乱码、依赖缺失劝退想搞清楚 FEX-Emu 和 DXMT 各自负责什么或者你只是好奇 x86-64 指令怎么在 ARM 设备上跑起来。我会尽量用生活化的类比解释原理同时给出可以直接抄的配置和命令。需要先说明一点Madeira 不是一个官方发行版更像是一套“配方”——把 Wine、FEX-Emu、DXMT 以及一堆兼容组件按特定方式组合起来。不同的人搭出来的 Madeira 可能细节不同但核心思路是一致的。下面我按“整体设计 → 核心组件 → 实操搭建 → 问题排查”的顺序展开。2. 整体设计与思路拆解为什么要这么组合2.1 三层结构翻译、转译、图形要理解 Madeira先得理解它为什么需要三个核心组件而不是一个 Wine 就完事。Wine 本身做的是 API 层面的翻译——把 Windows 的系统调用翻译成宿主系统的调用。但这里有个前提Wine 假设程序的指令集和宿主一致。也就是说x86-64 的 Windows 程序在 x86-64 的 Linux 上Wine 直接就能处理。问题出在 iOS 和现代 ARM 设备上。这些设备的 CPU 是 ARM 架构根本看不懂 x86-64 指令。这时候就需要 FEX-Emu 出场它负责指令集转译把 x86-64 指令实时翻译成 ARM64 指令。你可以把它想象成一个同声传译Wine 负责翻译“语言”APIFEX-Emu 负责翻译“口音”指令集。那 DXMT 又是干嘛的Windows 程序画图靠的是 DirectX而 iOS 和 Linux 上用的是 Metal 或 Vulkan。DXMT 的作用就是把 DirectX 调用翻译成 Metal在 iOS 上或 Vulkan在 Linux 上。没有它程序能跑起来但屏幕是黑的或者直接崩溃。所以这三层的关系是FEX-Emu指令集层x86-64 → ARM64WineAPI 层Windows API → POSIXDXMT图形层DirectX → Metal / Vulkan三者缺一不可。这也是为什么很多人只装了个 Wine 却发现程序跑不起来——缺了指令转译或图形翻译等于三条腿的凳子少了两条。2.2 为什么不用现成的虚拟机有人会问直接上虚拟机不香吗在桌面端确实可以但在 iOS 上虚拟机这条路基本走不通系统限制太多。而且虚拟机的资源开销大一个简单的记事本程序也要启动整个 Windows 系统体验很差。Madeira 这套方案是“按需翻译”只翻译程序实际用到的指令和 API启动快、占用低更适合移动端这种资源紧张的环境。另一个考量是授权和分发。Wine 是开源项目FEX-Emu 和 DXMT 也是整套方案可以自由组合、自由分发不依赖任何商业授权。这对于想自己折腾、甚至想集成到自己产品里的开发者来说是很重要的优势。2.3 方案选型背后的取舍搭 Madeira 的过程中有几个关键取舍值得说清楚。第一Wine 版本的选择。Wine 有稳定版和开发版还有各种分支比如 Proton。稳定版兼容性好但新特性少开发版新特性多但可能引入回归。我的经验是跑老程序用稳定版跑新游戏或需要新 DirectX 特性的用开发版。如果你不确定先用稳定版遇到问题再换。第二FEX-Emu 的配置。FEX-Emu 有 JIT即时编译和 AOT提前编译两种模式。JIT 启动快但运行时开销大AOT 启动慢但运行流畅。移动端一般用 JIT因为存储和内存有限桌面端如果程序固定可以考虑 AOT 优化。第三DXMT 的渲染后端。在 iOS 上只能用 Metal没得选在 Linux 上可以在 Vulkan 和 OpenGL 之间选。Vulkan 性能更好但驱动要求高OpenGL 兼容性好但性能一般。老设备建议 OpenGL新设备上 Vulkan。这些取舍没有绝对的对错取决于你的具体场景。下面我会在实操部分给出具体的配置建议。3. 核心组件深度解析与实操要点3.1 WineAPI 翻译层的关键细节Wine 的全称是“Wine Is Not an Emulator”它不模拟硬件而是直接翻译 API。这个设计的好处是性能损耗小坏处是兼容性依赖实现程度——Windows API 太多了Wine 不可能 100% 实现。在实际使用中最容易出问题的是这几个方面字体和编码。热词里“wine 乱码”“wine 栏是乱码”出现频率很高根本原因是 Wine 默认的字体配置不包含中文字形或者 locale 设置不对。解决办法是安装中文字体并把 locale 设成zh_CN.UTF-8。具体操作# 安装中文字体以 Debian 系为例 sudo apt install fonts-wqy-microhei fonts-wqy-zenhei # 设置 locale export LANGzh_CN.UTF-8 export LC_ALLzh_CN.UTF-8 # 在 wine 注册表中设置字体替换 wine reg add HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes /v MS Shell Dlg /d WenQuanYi Micro Hei /f依赖组件。很多 Windows 程序依赖 .NET、Visual C 运行库、DirectX 运行库等。Wine 自带了一部分但不可能全带。这时候需要用 winetricks 来补# 安装常用依赖 winetricks corefonts vcrun2019 dotnet48注意 dotnet48 安装过程很慢而且经常失败建议单独装、多试几次。如果程序不需要 .NET就别装省得折腾。Gecko 和 Mono。Wine 在首次运行需要 HTML 渲染或 .NET 的程序时会提示安装 Gecko 和 Mono。热词里“wine gecko官方正版下载”说明很多人卡在这一步。其实 Wine 自带下载器但网络不好时会失败。可以手动下载对应的 .msi 包放到 Wine 的缓存目录里再重新运行程序它就会自动安装。提示Gecko 和 Mono 的版本必须和你的 Wine 版本匹配版本不对会安装失败。下载前先确认 Wine 版本号。3.2 FEX-Emux86-64 到 ARM64 的桥梁FEX-Emu 是整个方案里最“黑科技”的部分。它用 JIT 技术把 x86-64 指令块翻译成 ARM64 指令块翻译结果会缓存起来下次执行同样的代码就直接用缓存。这个过程对用户是透明的但配置不当会严重影响性能。安装 FEX-Emu。不同平台的安装方式不同。在 Linux 上很多发行版有现成的包# Ubuntu / Debian sudo apt install fex-emu # Arch sudo pacman -S fex-emu在 iOS 上就麻烦得多需要自己编译而且要有开发者账号和相应的签名权限。这也是为什么 iOS 上的 Madeira 方案门槛较高。配置 FEX-Emu。核心配置文件是~/.fex-emu/Config.json几个关键参数参数作用推荐值RootFS根文件系统路径指向你的 Wine 前缀Thunks库转发配置按需配置SMCChecks自修改代码检查默认即可TSODisable时间戳优化老程序设 trueThunks 是 FEX-Emu 的一个重要机制它允许 x86-64 程序直接调用宿主系统的原生库而不需要经过翻译。比如图形库、音频库用 Thunks 转发到原生实现性能会好很多。配置 Thunks 需要写 JSON格式如下{ ThunksDB: { libGL.so.1: /usr/lib/aarch64-linux-gnu/libGL.so.1, libasound.so.2: /usr/lib/aarch64-linux-gnu/libasound.so.2 } }注意Thunks 配置错了会导致程序崩溃建议一个一个加加完测试一次。3.3 DXMT让 DirectX 程序在 Metal 上跑起来DXMT 是 DirectX 到 Metal 的翻译层主要面向 iOS 和 macOS。它的工作方式是把 D3D11 和 D3D12 的调用翻译成 Metal 调用。相比之前的 DXVKDirectX 到 VulkanDXMT 在 Apple 生态里更原生性能也更好。DXMT 的安装。在 iOS 上DXMT 通常以动态库的形式集成到 Wine 里。你需要把编译好的dxmt.dll和相关的 Metal 着色器放到 Wine 的system32目录然后在 Wine 注册表里注册# 复制 DXMT 库 cp dxmt.dll $WINEPREFIX/drive_c/windows/system32/ # 注册 DLL wine reg add HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides /v d3d11 /d native /f wine reg add HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides /v dxgi /d native /f性能调优。DXMT 有几个环境变量可以调DXMT_SHADER_CACHE着色器缓存路径设了之后第二次运行会快很多DXMT_MAX_FRAME_LATENCY最大帧延迟默认 3竞技类游戏可以设 1DXMT_METAL_DEVICE指定 Metal 设备多 GPU 设备上有用实测下来着色器缓存对体验提升最明显。第一次运行某个程序可能卡顿第二次就流畅了因为着色器已经编译并缓存了。3.4 组件之间的协作关系把这三个组件串起来看一个 Windows 程序的执行流程是这样的程序启动FEX-Emu 开始翻译 x86-64 指令程序调用 Windows APIWine 翻译成 POSIX 调用程序调用 DirectXDXMT 翻译成 Metal 调用翻译结果被缓存下次执行更快这个链条里任何一环出问题程序都跑不起来。所以排查问题时要按这个顺序逐层检查先确认 FEX-Emu 能正常翻译再确认 Wine 能正常响应 API最后确认 DXMT 能正常渲染。4. 实操过程与核心环节实现4.1 环境准备与依赖安装先说 Linux 桌面端的搭建因为这是最容易复现的环境。我用的是一台 ARM64 的 Linux 机器系统是 Ubuntu 22.04。第一步装基础依赖sudo apt update sudo apt install -y build-essential cmake ninja-build pkg-config \ libgl1-mesa-dev libvulkan-dev libasound2-dev libpulse-dev \ libdbus-1-dev libudev-dev libx11-dev libxext-dev这些是编译 Wine、FEX-Emu、DXMT 都需要的基础库。缺了任何一个编译到一半就会报错。第二步装 FEX-Emusudo add-apt-repository ppa:fex-emu/fex sudo apt update sudo apt install fex-emu装完后验证FEX --version能输出版本号就说明装好了。第三步装 Wine。Ubuntu 自带的 Wine 版本比较老建议用 WineHQ 的源sudo dpkg --add-architecture arm64 sudo mkdir -pm755 /etc/apt/keyrings sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources sudo apt update sudo apt install --install-recommends winehq-stable第四步初始化 Wine 前缀export WINEPREFIX~/.wine-madeira export WINEARCHwin64 wineboot --init这一步会创建 Wine 的目录结构并弹出 Gecko 和 Mono 的安装提示。如果网络不好可以跳过后面手动装。4.2 配置 FEX-Emu 与 Wine 的联动FEX-Emu 和 Wine 要联动关键是让 Wine 通过 FEX-Emu 来运行 x86-64 程序。这需要设置一个包装脚本#!/bin/bash # /usr/local/bin/wine-fex export FEX_ROOTFS$WINEPREFIX export FEX_THUNKS1 exec FEXInterpreter /usr/bin/wine $然后给脚本加执行权限sudo chmod x /usr/local/bin/wine-fex之后用wine-fex代替wine来运行程序就会自动走 FEX-Emu 的翻译层。这里有个细节FEX-Emu 的 RootFS 要指向 Wine 前缀这样它才能找到 Wine 的库文件。如果 RootFS 设错了程序会报“找不到 xxx.dll”之类的错误。4.3 安装 DXMT 并配置图形后端DXMT 需要从源码编译因为现成的二进制包不多。编译过程git clone https://github.com/3Shain/dxmt.git cd dxmt mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease ninja编译完成后把生成的dxmt.dll、d3d11.dll、dxgi.dll复制到 Wine 的system32目录cp dxmt.dll d3d11.dll dxgi.dll $WINEPREFIX/drive_c/windows/system32/然后在 Wine 注册表里设置 DLL 覆盖wine reg add HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides /v d3d11 /d native /f wine reg add HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides /v dxgi /d native /f设置环境变量启用 DXMTexport DXMT_ENABLE1 export DXMT_SHADER_CACHE~/.cache/dxmt4.4 运行第一个 Windows 程序拿一个简单的程序测试比如 Notepad。下载安装包然后用 wine-fex 运行wine-fex npp-installer.exe如果一切正常安装界面会弹出来。安装完成后运行wine-fex $WINEPREFIX/drive_c/Program Files/Notepad/notepad.exe第一次运行会慢一些因为 FEX-Emu 要翻译指令、DXMT 要编译着色器。第二次就快了。如果程序没弹出来先看终端输出。常见的错误和对应原因错误信息原因解决办法找不到 xxx.dllWine 前缀不完整重新 wineboot --init无法加载 d3d11DXMT 没装好检查 DLL 是否在 system32段错误FEX-Emu 翻译失败换 FEX-Emu 版本或关掉 JIT黑屏图形翻译失败检查 DXMT 环境变量4.5 iOS 端的特殊处理iOS 上的搭建和 Linux 差别很大主要是签名和权限问题。你需要一个开发者账号免费账号也行但签名有效期只有 7 天Xcode 和 iOS SDK编译好的 Wine、FEX-Emu、DXMT 的 iOS 版本编译过程这里不展开因为涉及大量交叉编译配置。重点说几个 iOS 特有的坑开发者模式。热词里“ios开发者模式”“ios 26.3.1怎么开发者模式”说明很多人卡在这。iOS 16 以后开发者模式默认隐藏需要在“设置 → 隐私与安全性”里找到“开发者模式”并开启然后重启设备。如果找不到这个选项说明设备没有连接过 Xcode或者签名证书没装好。签名和证书。iOS 应用必须签名才能运行。免费账号签名的应用 7 天后失效需要重新签。这也是为什么 iOS 上的 Madeira 方案更适合折腾而不是日常使用。内存限制。iOS 对应用内存有限制Wine 加 FEX-Emu 加 DXMT 这套组合本身就吃内存跑大型程序容易被系统杀掉。建议只跑轻量级程序。5. 常见问题与排查技巧实录5.1 乱码问题的完整解决路径乱码是 Wine 用户遇到最多的问题没有之一。表现是菜单栏、对话框、文件名显示成方块或问号。根本原因是字体缺失或编码不匹配。解决步骤确认系统装了中文字体fc-list :langzh应该有输出确认 Wine 能访问这些字体把字体复制到$WINEPREFIX/drive_c/windows/Fonts/设置 Wine 的 localewine reg add HKEY_CURRENT_USER\\Control Panel\\International /v Locale /d 00000804 /f设置字体替换把MS Shell Dlg、Tahoma、SimSun等替换成中文字体如果做完这些还是乱码检查程序的编码设置。有些老程序用的是 GBK 编码而 Wine 默认按 UTF-8 处理需要在程序内部切换编码或者用LANGzh_CN.GBK启动。提示乱码问题有时候是程序自己的字体文件缺失不是 Wine 的问题。把程序目录下的字体文件复制到系统字体目录试试。5.2 性能问题的排查思路性能问题分两种启动慢和运行卡。启动慢通常是 FEX-Emu 的翻译开销。第一次运行某个程序FEX-Emu 要翻译所有用到的指令这个过程可能几秒到几十秒。解决办法是启用 FEX-Emu 的缓存export FEX_CACHE~/.cache/fex第二次运行就会快很多。运行卡可能是图形翻译的问题。检查 DXMT 的着色器缓存是否启用以及是否用了正确的渲染后端。在 Linux 上如果 Vulkan 驱动有问题可以切到 OpenGLexport DXMT_BACKENDopengl另一个常见原因是 CPU 占用过高。FEX-Emu 的 JIT 翻译本身吃 CPU如果程序是计算密集型的性能损耗会很明显。这种情况下可以考虑 AOT 编译把常用指令提前翻译好。5.3 程序兼容性速查表不同程序对 Wine 的兼容性差异很大。下面是我实测过的一些程序的情况程序类型兼容性备注记事本类很好基本即开即用老游戏DX9较好需要 DXMT 或 DXVK新游戏DX12一般需要较新 Wine 和 DXMT办公软件较好需要装字体和运行库开发工具一般依赖多配置复杂反作弊游戏很差基本跑不起来反作弊程序是 Wine 的死穴因为它们会检测运行环境发现不是原生 Windows 就拒绝运行。这类程序目前没有好的解决办法。5.4 依赖缺失的排查方法程序启动时报“找不到 xxx.dll”说明依赖缺失。排查方法用winecfg查看当前 Wine 的库配置用winetricks list-installed查看已装的组件用ldd检查原生库是否齐全常见的缺失组件和安装方法# Visual C 运行库 winetricks vcrun2019 vcrun2017 vcrun2015 # .NET Framework winetricks dotnet48 # DirectX 运行库 winetricks d3dx9 d3dx11_43注意winetricks 安装组件时会下载文件网络不好容易失败。可以手动下载对应的安装包放到~/.cache/winetricks/目录再重新运行 winetricks。5.5 iOS 端的特有故障iOS 上的问题更棘手因为调试手段少。几个常见故障应用闪退。多半是签名问题或内存不足。先检查签名是否有效再看控制台日志有没有内存警告。无法连接调试器。热词里“ios怎么连接fiddler”说明有人想抓包调试。iOS 上抓包需要装证书、设代理而且很多应用有证书固定抓不到。调试 Wine 的话更推荐用 Xcode 的日志功能。开发者模式反复失效。这是免费账号的正常现象7 天到期后需要重新签名。想省事就买开发者账号一年 99 美元。Metal 着色器编译失败。DXMT 在 iOS 上依赖 Metal 着色器编译器如果程序用了 Metal 不支持的特性会编译失败。这种情况只能等 DXMT 更新或者换程序。6. 一些实操心得和后续可折腾的方向折腾 Madeira 这套方案有一段时间了最大的体会是它不是一个“装完就能用”的东西而是一个需要不断调试和调整的方案。每个程序都有自己的脾气同一个配置在这个程序上跑得好换个程序可能就崩。所以心态要放平把它当成一个持续折腾的项目而不是一个成品工具。几个我觉得比较有用的经验第一保持 Wine 前缀干净。不要把所有程序装在一个前缀里不同程序对依赖的要求可能冲突。给每个程序单独建前缀虽然占空间但省心。第二善用日志。Wine 的WINEDEBUG环境变量可以输出详细日志排查问题时非常有用。比如WINEDEBUGd3d11可以看到 DirectX 调用的详细信息。第三关注社区。Wine、FEX-Emu、DXMT 都是活跃的开源项目更新频繁。遇到问题先去 GitHub Issues 搜一下大概率有人遇到过。后续可以折腾的方向一是尝试把 Madeira 方案打包成容器镜像简化部署二是研究 FEX-Emu 的 AOT 编译提升性能三是探索在更多平台上运行比如 Android。这些都需要时间和精力但值得一试。最后分享一个小技巧如果某个程序在 Wine 里跑不起来先别急着放弃试试换个 Wine 版本。有时候稳定版不行开发版反而能跑反之亦然。Wine 的版本差异对兼容性影响很大多试几个版本往往能找到能用的。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →