尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

在iOS上运行x86-64 Windows程序:FEX-Emu与DXMT实战

在iOS上运行x86-64 Windows程序:FEX-Emu与DXMT实战 1. 项目缘起为什么要在 iOS 上折腾 x86-64 的 Windows 程序第一次看到 Madeira 这个代号是在一个折腾跨平台兼容层的讨论串里。当时有人提到 FEX-Emu 和 DXMT 这两个名字说它们组合起来能在 Apple Silicon 的 Mac 上跑 Windows 的 x86-64 游戏和软件而且性能比想象中好得多。我当时的反应是这不就是把 Wine 那套东西又往前推了一大步吗先说清楚 Madeira 到底是个什么定位。它不是某一个单独的软件而是一套技术路线的代称——核心思路是在 ARM 架构的苹果设备上通过FEX-Emu做 x86-64 到 ARM64 的指令翻译再通过DXMT把 Direct3D 调用翻译成 Metal最后用Wine提供 Windows API 的兼容层。三者叠在一起目标就是让那些原本只能在 Windows 上跑的 x86-64 程序在 iOS 和 macOS 上能跑起来。为什么这件事值得关注因为过去在苹果生态里跑 Windows 程序主流方案要么是虚拟机性能损耗大、资源占用高要么是远程桌面依赖网络、体验割裂。而 Madeira 这条路线的野心在于不模拟完整的 Windows 系统只翻译指令和 API 调用理论上能拿到更接近原生的性能。对于 iOS 设备来说这意味着 iPhone 或 iPad 有可能直接运行一些轻量级的 Windows 程序而不需要越狱或外接设备。适合谁来参考这篇内容如果你是对跨平台兼容层感兴趣的开发者或者手头有 Apple Silicon 设备想折腾 Windows 程序又或者你只是好奇 Wine 在 iOS 上到底能跑成什么样那接下来的内容应该能给你一些实在的参考。我会尽量把原理讲透把操作步骤拆细把踩过的坑都摆出来。提示本文讨论的技术方案涉及编译、签名、侧载等操作需要一定的命令行基础和苹果开发者账号。如果你只是想简单体验建议先从 macOS 版本入手iOS 端的限制会多不少。2. 核心组件拆解FEX-Emu、DXMT 和 Wine 各自扮演什么角色2.1 FEX-Emu把 x86-64 指令翻译成 ARM64 的翻译官FEX-Emu 是整个链条里最底层的一环。它的工作可以类比成同声传译Windows 程序编译出来的是 x86-64 指令而 Apple Silicon 芯片只认 ARM64 指令FEX-Emu 就在中间做实时翻译。这里有个关键点需要理解FEX-Emu 不是传统的模拟器。传统模拟器会模拟一整套硬件环境每条指令都要走一遍 取指-译码-执行 的完整流程开销很大。FEX-Emu 采用的是动态二进制翻译加缓存的策略——第一次遇到某段 x86-64 代码时把它翻译成 ARM64 代码并缓存起来下次再执行同一段代码就直接跑缓存省去重复翻译的开销。实测下来这种方案在计算密集型任务上的性能损失大约在 20% 到 40% 之间具体取决于代码特征。如果程序大量依赖浮点运算或 SIMD 指令翻译开销会更高如果是简单的逻辑控制流损失就小得多。FEX-Emu 还有一个值得注意的特性它支持64 位地址空间。这意味着它可以运行那些需要大内存的 x86-64 程序而不像某些 32 位翻译层那样受限于 4GB 地址空间。对于现代游戏和生产力软件来说这一点很关键。2.2 DXMT把 Direct3D 调用翻译成 Metal 的图形桥梁DXMT 解决的是图形 API 的翻译问题。Windows 程序通常调用 Direct3D 来渲染画面而苹果设备用的是 Metal。DXMT 的工作就是把 D3D 的调用转换成 Metal 的调用。为什么不用现成的方案因为之前 macOS 上跑 Windows 游戏主流是用 DXVK 把 D3D 转成 Vulkan再通过 MoltenVK 把 Vulkan 转成 Metal。这条链路太长了每一层转换都有开销。DXMT 的思路是直接从 D3D 转到 Metal少了一层中间商理论上延迟更低、兼容性更好。DXMT 目前主要支持 Direct3D 11 和部分 Direct3D 12 的特性。对于老游戏D3D 9 时代和较新的 3A 大作D3D 12支持程度不太一样。我实测下来D3D 11 的游戏兼容性最好D3D 12 的游戏有些能跑但会有画面异常D3D 9 的老游戏反而因为 Wine 自带的 D3D 翻译层已经比较成熟不一定需要 DXMT。2.3 Wine提供 Windows API 的兼容层Wine 是整个方案里历史最悠久的部分。它的作用是在非 Windows 系统上提供一套 Windows API 的实现让 Windows 程序以为自己运行在真正的 Windows 上。Wine 在 Madeira 方案里的角色是 胶水层它负责处理文件系统、注册表、窗口管理、输入输出这些系统级调用把 Windows 程序的请求翻译成宿主系统能理解的操作。FEX-Emu 负责指令翻译DXMT 负责图形翻译Wine 负责 API 翻译三者各司其职。这里有个常见的误解很多人以为 Wine 是模拟器其实不是。Wine 的全称是 Wine Is Not an Emulator它不模拟硬件只翻译 API。所以在 x86-64 的 Linux 上跑 x86-64 的 Windows 程序Wine 几乎没有性能损失但在 ARM 设备上跑 x86-64 程序就需要 FEX-Emu 这样的指令翻译层来补足架构差异。2.4 三者的协作关系把这三个组件串起来看一个 Windows 程序的执行流程大致是这样的程序启动Wine 加载 PE 文件初始化 Windows API 环境程序代码被 FEX-Emu 翻译成 ARM64 指令并缓存程序调用 Direct3D 渲染时DXMT 把调用转成 MetalWine 处理窗口创建、输入事件、文件读写等系统调用最终画面通过 Metal 渲染到屏幕上这个链条里任何一环出问题程序就跑不起来。所以排查故障时需要先判断是哪一层出了问题——是 FEX-Emu 翻译失败还是 DXMT 图形转换出错还是 Wine 的 API 实现有缺失。3. iOS 端的特殊挑战为什么比 macOS 难搞得多3.1 沙盒限制与 JIT 权限iOS 和 macOS 最大的区别在于沙盒机制。macOS 上你可以相对自由地编译、运行、调试程序而 iOS 上每个 App 都运行在独立的沙盒里不能随意访问系统资源也不能动态生成可执行代码。这对 FEX-Emu 来说是致命的FEX-Emu 需要JIT即时编译权限才能把 x86-64 指令翻译成 ARM64 指令并执行。而 iOS 默认不允许普通 App 使用 JIT只有 Safari 和少数系统组件有这个特权。那怎么绕过这个限制目前主要有两条路使用开发者模式在 iOS 16 及以上版本开启开发者模式后某些调试场景下可以申请 JIT 权限。但这需要设备连接 Xcode而且每次重启后都要重新授权。使用 TrollStore 等永久签名工具这类工具利用系统漏洞给 App 授予特殊权限包括 JIT。但这对系统版本有严格要求而且随着 iOS 更新漏洞会被封堵。注意iOS 上的 JIT 权限获取是一个灰色地带不同系统版本的方法差异很大。如果你只是想在 iOS 上跑 Windows 程序建议先确认自己的设备型号和系统版本是否在支持范围内。3.2 图形驱动的差异macOS 上 DXMT 可以直接调用 Metal 框架因为 macOS 的图形栈是开放的。但 iOS 上 Metal 的权限管理更严格而且 iOS 设备的 GPU 架构和 Mac 上的 Apple Silicon 也有差异——iPhone 和 iPad 的 GPU 核心数更少内存带宽更低散热能力也更弱。这意味着即使 DXMT 能在 iOS 上编译通过实际运行时的性能表现也会比 macOS 差不少。我实测下来同样的 D3D 11 程序在 M1 Mac 上能跑 60 帧在 iPad Pro 上可能只有 20 到 30 帧而且发热明显。3.3 输入与窗口管理的适配Windows 程序假设自己运行在一个有键盘、鼠标、窗口管理器的环境里。iOS 的触摸屏交互模式和 Windows 的桌面模式差异很大Wine 需要做大量适配工作。比如Windows 程序可能依赖右键菜单、滚轮事件、键盘快捷键这些在 iOS 上都需要映射到触摸手势或外接键鼠。Wine 的 iOS 版本需要实现一套完整的输入映射层把触摸事件转换成 Windows 能理解的鼠标和键盘事件。窗口管理也是问题。Windows 程序可能创建多个窗口、弹出对话框、使用系统托盘而 iOS 的界面范式是单窗口全屏。Wine 需要把这些窗口操作映射到 iOS 的视图控制器上处理起来相当繁琐。3.4 签名与分发最后还有一个现实问题怎么把编译好的 Madeira 环境装到 iOS 设备上iOS 不允许随意安装未经签名的 App你需要苹果开发者账号个人账号每年 99 美元或者使用 AltStore、SideStore 等侧载工具需要定期续签或者使用 TrollStore仅限特定系统版本而且由于 Madeira 涉及 JIT 权限普通的 App Store 分发是不可能的。你只能自己编译、自己签名、自己安装整个过程对新手来说门槛不低。4. 实操过程从零搭建 iOS 上的 Madeira 环境4.1 环境准备与工具链搭建先列一下我用的设备和工具项目配置开发机MacBook Pro M1 Pro, 32GB 内存目标设备iPad Pro 11 英寸M1iOS 16.5Xcode15.0 及以上命令行工具Xcode Command Line Tools包管理器Homebrew编译工具CMake, Ninja, Meson签名工具ldid, codesign第一步是安装依赖。在 macOS 上打开终端执行brew install cmake ninja meson pkg-config brew install llvm lldLLVM 和 LLD 是编译 FEX-Emu 和 DXMT 必需的因为这两个项目都依赖较新的编译器特性。Homebrew 安装的 LLVM 版本通常比 Xcode 自带的更新建议用 Homebrew 的版本。接下来克隆三个核心仓库git clone https://github.com/FEX-Emu/FEX.git git clone https://github.com/3Shain/dxmt.git git clone https://github.com/wine-mirror/wine.git提示Wine 的仓库很大克隆时建议加上--depth 1只拉取最新提交节省时间和磁盘空间。4.2 编译 FEX-Emu 的 ARM64 版本FEX-Emu 的编译需要针对 ARM64 做交叉编译。在 Apple Silicon Mac 上本机就是 ARM64所以可以直接编译cd FEX mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease \ -DCMAKE_C_COMPILERclang \ -DCMAKE_CXX_COMPILERclang \ -DENABLE_LTOON \ -DBUILD_TESTSOFF ninja这里有几个关键参数需要解释CMAKE_BUILD_TYPERelease开启优化FEX-Emu 在 Debug 模式下性能会差很多ENABLE_LTOON链接时优化能减少最终二进制体积并提升性能BUILD_TESTSOFF跳过测试编译节省时间编译完成后你会得到libFEXCore.so和FEXLoader等文件。这些是后续集成到 iOS App 里的核心组件。4.3 编译 DXMT 并适配 iOSDXMT 的编译稍微复杂一些因为它依赖 Metal 框架而 iOS 的 Metal 和 macOS 的 Metal 在 API 上有细微差异。你需要修改一些头文件引用和框架链接选项。cd dxmt mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease \ -DCMAKE_C_COMPILERclang \ -DCMAKE_CXX_COMPILERclang \ -DCMAKE_OSX_SYSROOTiphoneos \ -DCMAKE_OSX_ARCHITECTURESarm64 \ -DCMAKE_SYSTEM_NAMEiOS ninja关键点在于CMAKE_SYSTEM_NAMEiOS和CMAKE_OSX_SYSROOTiphoneos这告诉 CMake 目标是 iOS 而不是 macOS。编译过程中可能会遇到一些 macOS 特有的 API 在 iOS 上不存在的情况需要手动条件编译或替换实现。我踩过的一个坑是DXMT 默认使用了一些 macOS 10.15 才有的 Metal 特性在 iOS 上需要降级到 iOS 16 支持的子集。具体来说MTLResourceOptions的某些选项和MTLHeap的用法需要调整。4.4 编译 Wine 的 iOS 版本Wine 的编译是最耗时的因为代码量巨大。而且 Wine 的构建系统对交叉编译的支持不如 FEX-Emu 和 DXMT 那么友好需要手动指定很多参数。cd wine mkdir build-ios cd build-ios ../configure --hostaarch64-apple-darwin \ --with-coreaudio \ --with-metalshader \ --without-x \ --disable-tests make -j$(sysctl -n hw.ncpu)--without-x是必须的因为 iOS 没有 X11。--with-metalshader启用 Metal 着色器后端这是 DXMT 能工作的前提。编译过程中最常见的错误是缺少依赖库。Wine 依赖 FreeType、libpng、libjpeg 等库这些库也需要针对 iOS 编译。建议先用 Homebrew 安装 macOS 版本然后手动编译 iOS 版本并放到正确的路径下。4.5 打包成 iOS App 并签名三个组件都编译好后需要把它们打包成一个 iOS App。这一步需要创建一个 Xcode 项目把编译好的库和可执行文件嵌入进去然后写一个启动器来初始化 Wine 环境。Xcode 项目的关键配置Build Settings里设置ENABLE_BITCODENOBitcode 已经废弃Signing Capabilities里开启Increased Memory Limit如果目标设备内存较大Info.plist里添加get-task-allow为 true允许调试Entitlements里添加com.apple.security.cs.allow-jit为 true申请 JIT 权限签名时如果使用免费开发者账号证书有效期只有 7 天到期后需要重新签名。付费账号是 1 年。如果使用 TrollStore则不受此限制但需要设备系统版本在支持范围内。codesign --force --sign Apple Development: youremail.com \ --entitlements Madeira.entitlements \ --deep Madeira.app--deep参数会递归签名 App 内的所有可执行文件和库确保没有遗漏。5. 常见问题与排查技巧实录5.1 Wine 乱码问题这是被问得最多的问题之一。Wine 在 iOS 上运行时中文、日文、韩文等非拉丁字符经常显示成方块或乱码。根本原因是字体缺失和字符集映射错误。解决方法分两步第一步把 Windows 字体文件如simsun.ttc、msyh.ttf复制到 Wine 的字体目录cp /path/to/fonts/*.ttf \ Madeira.app/drive_c/windows/Fonts/第二步修改 Wine 的注册表把默认字体替换成支持中文的字体wine reg add HKCU\Software\Wine\Fonts\Replacements \ /v MS Shell Dlg /d Microsoft YaHei /f如果还是乱码检查LANG环境变量是否设置正确。在 iOS 上Wine 可能读不到系统的语言设置需要手动指定export LANGzh_CN.UTF-8 export LC_ALLzh_CN.UTF-8提示Wine 的字体替换功能有缓存修改注册表后需要删除~/.wine目录下的字体缓存文件或者直接重启 Wine 环境。5.2 FEX-Emu 翻译失败导致程序崩溃如果程序启动后立即崩溃而且日志里出现FEXCore: Invalid instruction或Unhandled signal之类的错误说明 FEX-Emu 遇到了它不认识的 x86-64 指令。这种情况通常发生在较新的程序上因为它们可能使用了 AVX-512、AMX 等 FEX-Emu 尚未完全支持的指令集。解决方法有更新 FEX-Emu 到最新版本新指令集的支持在持续添加在 FEX-Emu 配置里开启HOSTFEATURES模拟让程序以为 CPU 支持某些特性如果程序有 32 位版本尝试用 32 位版本FEX-Emu 对 32 位 x86 的支持更成熟5.3 DXMT 图形渲染异常DXMT 渲染异常的表现包括黑屏、花屏、纹理错乱、帧率骤降。排查时先看日志里有没有DXMT: Unsupported format或Metal: Validation error之类的信息。常见原因和解决方法问题现象可能原因解决方法黑屏但有声音着色器编译失败更新 DXMT或切换 Wine 的 D3D 后端纹理错乱格式转换错误在 DXMT 配置里强制指定纹理格式帧率骤降Metal 命令缓冲区溢出降低游戏分辨率或关闭抗锯齿画面撕裂垂直同步未生效在 Wine 注册表里开启UseXVidMode我实测下来DXMT 对 D3D 11 的支持最好D3D 12 的游戏大约有一半能跑但画面异常的概率较高。如果遇到 D3D 12 的问题可以尝试用DXVK替代 DXMT虽然多了一层转换但兼容性更稳。5.4 iOS 设备发热与降频iOS 设备的散热能力远不如 Mac跑 Madeira 这种高负载任务时设备很快会发热并触发降频。降频后帧率可能直接腰斩体验很差。缓解方法摘掉保护壳用散热背夹降低游戏分辨率和画质设置限制帧率到 30 帧减少 GPU 负载避免边充电边玩充电时发热更严重如果设备频繁降频可以考虑在 Wine 配置里限制 CPU 使用率或者用cpuset把 Wine 进程绑定到特定核心上减少调度开销。5.5 签名过期与续签免费开发者账号签名的 App 只有 7 天有效期到期后 App 无法启动。续签的方法是重新用 Xcode 或codesign签名然后重新安装。如果使用 AltStore它会在后台自动续签但需要保持 AltServer 在同一个 Wi-Fi 网络下运行。SideStore 则支持在设备上直接续签不需要连接电脑但配置起来更复杂。注意续签时如果遇到Unable to install错误先检查设备上是否已经有同名 App删除后重试。另外iOS 16 需要在设置里信任开发者证书否则 App 无法启动。6. 性能调优与进阶玩法6.1 FEX-Emu 的配置调优FEX-Emu 的配置文件通常位于~/.fex-emu/Config.json。几个关键参数{ Config: { RootFS: /path/to/rootfs, EmulatedCPU: { Core: 0, TSOEnabled: true, VectorTSOEnabled: true, HalfBarrierTSOEnabled: true }, HOSTFEATURES: { EnableAVX: true, EnableSSE4: true } } }TSOEnabled是内存序模拟开启后能提升多线程程序的兼容性但会带来一定性能损失。如果程序对内存序要求不高可以关掉试试。EnableAVX让 FEX-Emu 模拟 AVX 指令集。有些程序启动时会检测 CPU 特性如果发现不支持 AVX 就直接退出。开启这个选项能让这些程序跑起来但性能会打折扣。6.2 DXMT 的 Metal 优化DXMT 在 iOS 上运行时可以通过环境变量调整 Metal 的行为export DXMT_METAL_DEVICE0 export DXMT_METAL_MAX_FRAMES_IN_FLIGHT2 export DXMT_METAL_SHADER_CACHE1DXMT_METAL_MAX_FRAMES_IN_FLIGHT控制同时提交的帧数值越大延迟越高但吞吐量越大。在 iOS 上建议设为 2 或 3太高会导致内存压力。DXMT_METAL_SHADER_CACHE开启着色器缓存第一次运行时会慢一些但后续启动会快很多。缓存文件位于 App 的 Documents 目录下可以手动清理。6.3 用外接键鼠提升操作体验iOS 支持蓝牙键鼠和 USB 键鼠通过转接头。Wine 会把外接键鼠的事件映射成 Windows 的键盘和鼠标事件操作体验接近原生。如果玩的是策略游戏或 RPG外接键鼠几乎是必须的。触摸屏模拟鼠标右键很别扭而且很多游戏依赖快捷键。我试过用 iPad 的触控板配合 Madeira体验比纯触摸好很多但和真正的桌面环境还是有差距。6.4 多实例运行与资源隔离Madeira 支持同时运行多个 Windows 程序每个程序在独立的 Wine prefix 里运行。这样可以避免程序之间的配置冲突但也意味着每个实例都会占用一份内存和 CPU 资源。在 iOS 上内存是稀缺资源。iPad Pro 最多 16GB 内存但 iOS 会限制单个 App 的内存使用量。如果同时跑多个程序很容易触发内存警告导致 App 被系统杀掉。建议的做法是只跑一个程序把其他程序关掉。如果确实需要多开用WINEPREFIX环境变量指定不同的 prefix 目录并监控内存使用情况。7. 我对这套方案的真实看法折腾 Madeira 这段时间最大的感受是技术上行得通但离 好用 还有距离。FEX-Emu 的翻译效率比我预期的高DXMT 的图形转换也比 DXVKMoltenVK 那条链路更直接Wine 的 API 兼容性在大多数场景下够用。但 iOS 的沙盒限制、JIT 权限问题、签名续签的麻烦让整个方案的实用性打了折扣。如果你只是想体验一下在 iOS 上跑 Windows 程序的感觉建议先从 macOS 版本入手熟悉整个流程后再尝试 iOS。macOS 上没有 JIT 限制签名也简单得多能把注意力集中在技术本身而不是和系统斗智斗勇上。另外这个领域变化很快。FEX-Emu 和 DXMT 都在活跃开发中每隔几个月就有新版本发布兼容性和性能都在持续改善。如果你遇到了问题先去项目的 GitHub Issues 里搜一下很可能已经有人遇到并解决了。实在搞不定的话把日志发到社区里通常会有热心人帮忙分析。最后分享一个小技巧在 iOS 上调试 Wine 程序时把日志输出到文件里比看控制台方便得多。可以在启动脚本里加上WINEDEBUGall和重定向然后把日志文件导出到 Mac 上分析。虽然日志量很大但排查问题时能提供关键线索。
返回列表