ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Madeira兼容层解析:Wine、FEX-Emu与DXMT如何让Windows应用在ARM设备上运行

Madeira兼容层解析:Wine、FEX-Emu与DXMT如何让Windows应用在ARM设备上运行 1. 从“Madeira”这个名字说起一个跨平台兼容层的真实面貌第一次看到“Madeira”这个词很多人会以为是某个旅游目的地或者葡萄酒品牌。但在技术圈子里尤其是折腾过跨平台应用兼容的开发者眼中它指向的是一个非常具体的方向在非Windows系统上运行Windows应用。热词里出现的Wine、FEX-Emu、DXMT、iOS、x86-64这几个关键词已经把技术轮廓勾勒得很清楚了——这是一个围绕Wine生态、面向ARM架构设备、试图在移动端或异构平台上跑起Windows程序的兼容层项目。我接触Wine相关的东西有些年头了。从早期在Linux桌面发行版上折腾各种Windows软件到后来看Valve把Proton做进Steam Deck再到如今ARM设备大爆发之后各种转译方案层出不穷这个领域的变化非常快。Madeira这个标题背后我理解它想做的事情是把Wine的兼容能力、FEX-Emu的指令集转译能力、DXMT的图形翻译能力整合到一起让x86-64的Windows应用能在ARM架构的设备上跑起来甚至包括iOS这样的移动平台。这件事为什么值得关注因为ARM设备的算力已经足够强了Apple Silicon的Mac、高通骁龙的Windows on ARM笔记本、各种安卓平板和iPad硬件性能早就不是瓶颈。真正的瓶颈在软件生态——大量存量Windows应用是x86-64架构的直接搬到ARM上跑不了。Wine负责解决API层面的兼容FEX-Emu负责解决指令集层面的转译DXMT负责把DirectX调用翻译成Metal这三者叠起来理论上就能在ARM设备上跑Windows程序。Madeira如果能把这条链路打通并且做好集成那价值就很大了。这篇文章我会从实际从业者的角度把Madeira涉及的核心技术点拆开讲清楚。包括Wine的工作机制、FEX-Emu怎么做x86-64到ARM64的转译、DXMT为什么选择Metal作为后端、在iOS上做这件事会遇到什么特殊限制以及整个方案在实操层面有哪些坑。适合对跨平台兼容层感兴趣的中高级开发者也适合想了解Wine生态最新进展的技术爱好者。我会尽量用大白话把原理讲明白同时给出可参考的实操思路。2. 核心架构拆解Wine、FEX-Emu、DXMT各自扮演什么角色2.1 Wine不是模拟器它是API翻译层很多人第一次听到Wine会以为它是个虚拟机或者模拟器。这个理解偏差很大。Wine的全称是“Wine Is Not an Emulator”它做的事情是把Windows的API调用翻译成宿主系统的API调用。比如一个Windows程序调用了CreateWindowExWine会把这个调用转换成Linux上的X11或者Wayland对应的窗口创建操作。程序本身还是以原生指令在CPU上执行的没有指令集层面的模拟。这个设计带来的好处是性能损耗小。因为不需要模拟CPU指令程序跑起来的速度接近原生。但代价是兼容性需要一个个API去实现Windows的API浩如烟海Wine团队做了三十多年仍然有大量API没有完全实现或者行为不一致。这就是为什么有些Windows程序在Wine上跑得完美有些直接崩溃。在Madeira这个场景里Wine的角色是基础兼容层。它负责让Windows程序以为自己在一个Windows系统里提供注册表、文件系统映射、DLL加载等基础设施。热词里提到的“wine乱码”和“wine栏是乱码”就是Wine在中文字体处理上的经典问题——Wine默认不带Windows字体程序找不到对应字体就会显示方块或者乱码。解决办法通常是安装winetricks里的corefonts和cjkfonts或者把Windows的字体文件复制到Wine的字体目录。2.2 FEX-Emu解决的是指令集不匹配问题Wine解决了API层面的兼容但还有一个更底层的问题如果Windows程序是x86-64架构编译的而设备是ARM64架构CPU根本不认识这些指令。这时候就需要FEX-Emu出场了。FEX-Emu是一个开源的x86-64到ARM64的指令集转译器。它的工作方式不是逐条指令解释执行而是把x86-64的指令块动态翻译成ARM64指令块然后缓存起来重复使用。这种“块翻译缓存”的策略比逐条解释快得多因为大部分程序的执行热点是集中的翻译一次可以反复用。FEX-Emu的一个关键设计是它同时支持32位和64位x86指令。这意味着它不仅能跑64位的Windows程序也能跑32位的。对于游戏来说这点很重要很多老游戏是32位的。另外FEX-Emu还实现了x86的一些特殊指令集扩展比如SSE、AVX的部分指令这些在多媒体处理和游戏里用得很多。实际使用中FEX-Emu的性能损耗大概在20%到50%之间具体取决于负载类型。计算密集型的任务损耗小一些因为翻译后的ARM64代码执行效率接近原生但频繁调用系统API的任务损耗会大一些因为每次进出转译层都有开销。在Apple Silicon上由于M系列芯片的单核性能很强FEX-Emu跑x86-64程序的体验已经相当可用了。2.3 DXMT把DirectX翻译成Metal图形是另一个大问题。Windows程序大量使用DirectX进行渲染而ARM设备上尤其是Apple平台图形API是Metal。DXMT的作用就是把DirectX 11的调用翻译成Metal调用。DXMT是基于DXVK的思路做的。DXVK是把DirectX 9/10/11翻译成Vulkan在Linux上很成熟。但iOS和macOS上Vulkan的支持不好Metal才是原生API所以DXMT选择了Metal作为后端。这个选择很合理因为Metal在Apple设备上的性能和兼容性都是最好的。DXMT目前主要支持DirectX 11对DirectX 12的支持还在完善中。对于大部分老游戏和办公软件来说DirectX 11已经够用了。实际使用中DXMT的图形翻译效率取决于具体的渲染负载。简单的2D界面翻译开销很小复杂的3D场景可能会有一定的性能损失但整体上已经能做到可玩的水平。2.4 三者如何协同工作把这三个组件串起来看一个Windows程序在Madeira环境下的执行流程是这样的程序启动时FEX-Emu把x86-64指令翻译成ARM64指令执行程序调用Windows API时Wine把这些调用翻译成宿主系统的API程序进行图形渲染时DXMT把DirectX调用翻译成Metal调用。三层翻译各司其职共同让一个为Windows/x86-64编译的程序在ARM64设备上跑起来。这个架构的复杂度在于三层之间的交互。比如Wine在实现某个API时可能需要调用图形驱动这个调用会经过DXMTFEX-Emu在翻译指令时可能需要处理内存模型差异这又和Wine的虚拟内存管理有交互。任何一个环节出问题程序都可能崩溃或者表现异常。Madeira如果能把这三者做好集成和调试那它的价值就在于省去了用户自己拼装和调优的麻烦。3. 实操环境搭建从零开始跑通一个Windows程序3.1 基础环境准备假设你在一台Apple Silicon的Mac上想通过Madeira方案跑一个Windows程序。第一步是准备基础环境。你需要安装Homebrew这是macOS上最方便的包管理器。然后通过Homebrew安装Wine的macOS版本、FEX-Emu和DXMT。具体的安装命令大致是这样的# 安装Homebrew如果还没装 /bin/bash -c $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) # 安装Wine brew install --cask wine-stable # 安装FEX-Emu可能需要从源码编译 git clone https://github.com/FEX-Emu/FEX.git cd FEX mkdir build cd build cmake .. make -j$(sysctl -n hw.ncpu) sudo make install # 安装DXMT git clone https://github.com/3Shain/dxmt.git cd dxmt mkdir build cd build cmake .. make -j$(sysctl -n hw.ncpu)这里要注意FEX-Emu和DXMT在macOS上的编译可能会有依赖问题需要提前安装好CMake、Ninja、Python等工具。另外Wine的版本选择很重要建议用最新的开发版而不是稳定版因为开发版对新API的支持更好。3.2 配置Wine前缀Wine使用“前缀”的概念来隔离不同程序的运行环境。一个前缀就是一个目录里面模拟了Windows的C盘结构。你可以为每个程序创建独立的前缀避免相互干扰。# 创建一个新的Wine前缀 export WINEPREFIX~/madeira-test export WINEARCHwin64 wineboot --init创建好前缀后需要安装一些基础组件。用winetricks可以方便地安装字体、运行库等# 安装中文字体和基础运行库 winetricks corefonts cjkfonts vcrun2019 dotnet48这里cjkfonts就是解决中文乱码的关键。如果不装这个中文程序里的文字会显示成方块。vcrun2019和dotnet48是很多程序依赖的运行库提前装好可以避免后续报错。3.3 集成FEX-EmuFEX-Emu的集成方式取决于你的使用场景。如果你是在Linux ARM设备上FEX-Emu可以作为binfmt_misc的处理器注册这样系统会自动用FEX-Emu来执行x86-64的二进制文件。在macOS上由于系统限制可能需要通过包装脚本的方式手动调用。# 在Linux上注册binfmt_misc sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc echo :FEX-x86_64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/FEXInterpreter:OCF | sudo tee /proc/sys/fs/binfmt_misc/register在macOS上你可能需要写一个包装脚本在调用Wine之前先设置好FEX-Emu的环境变量。FEX-Emu提供了一些环境变量来控制转译行为比如FEX_APP_CONFIG可以指定配置文件FEX_ROOTFS可以指定根文件系统路径。3.4 配置DXMTDXMT的配置主要是把它的DLL文件放到Wine能找到的位置。DXMT编译后会生成d3d11.dll、dxgi.dll等文件这些需要覆盖Wine自带的版本。# 把DXMT的DLL复制到Wine前缀的system32目录 cp build/bin/d3d11.dll $WINEPREFIX/drive_c/windows/system32/ cp build/bin/dxgi.dll $WINEPREFIX/drive_c/windows/system32/ # 设置DXMT的环境变量 export DXMT_LOG_LEVELinfo export DXMT_ENABLE_METAL1DXMT还支持一些调优参数比如DXMT_MAX_FRAME_LATENCY可以控制最大帧延迟DXMT_SHADER_CACHE可以启用着色器缓存来加速二次加载。这些参数可以根据具体程序的表现来调整。3.5 运行第一个程序环境搭好之后可以拿一个简单的Windows程序来测试。建议从记事本或者计算器这种轻量级程序开始确认基础环境没问题后再上复杂的程序。# 运行Windows记事本 wine notepad.exe # 运行一个安装程序 wine setup.exe如果程序能正常启动并且界面显示正常说明基础环境没问题。如果遇到崩溃可以打开Wine的调试输出看具体报错WINEDEBUGall wine program.exe 21 | tee wine.log这个日志会非常详细包含Wine内部的所有调用。刚开始看可能会觉得信息量太大但定位问题时非常有用。可以先用grep过滤出错误和警告grep -i err: wine.log grep -i warn: wine.log4. 常见问题与排查技巧实录4.1 中文乱码问题这是Wine用户遇到频率最高的问题。表现是程序界面上的中文显示成方块、问号或者完全乱码。根本原因是Wine默认的字体配置里没有中文字体程序请求中文字体时找不到匹配。解决办法有几个层次。最简单的就是用winetricks cjkfonts安装中文字体包。如果这个不管用可以手动把Windows系统里的字体文件复制到Wine的字体目录# 把Windows字体复制到Wine前缀 cp /path/to/windows/Fonts/simsun.ttc $WINEPREFIX/drive_c/windows/Fonts/ cp /path/to/windows/Fonts/msyh.ttc $WINEPREFIX/drive_c/windows/Fonts/然后需要修改注册表让Wine知道这些字体对应哪些字体族wine regedit在注册表里找到HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts添加字体映射。这一步比较繁琐但一次配好之后所有程序都受益。还有一个更彻底的办法是直接替换Wine的字体链接。Wine的字体配置在$WINEPREFIX/drive_c/windows/Fonts/目录下你可以把simsun.ttc重命名为Wine默认查找的字体名比如tahoma.ttf这样所有请求Tahoma的地方都会用宋体来渲染。4.2 程序启动崩溃程序启动就崩溃是最让人头疼的问题因为可能的原因太多了。我的排查思路是这样的先看Wine的报错输出。用WINEDEBUGall跑一遍重点看err:级别的日志。常见的错误包括缺少DLL、API未实现、内存访问违规等。如果是缺少DLL可以用winetricks安装对应的运行库。比如提示缺少msvcp140.dll就装vcrun2019提示缺少d3dx9_43.dll就装d3dx9。如果是API未实现Wine的日志里会显示unimplemented function。这种情况比较麻烦因为需要等Wine团队实现或者找替代方案。可以到Wine的AppDB上查一下这个程序的支持情况看看别人是怎么解决的。如果是内存访问违规可能是FEX-Emu的转译出了问题。可以尝试关闭FEX-Emu的某些优化选项或者换一个FEX-Emu的版本。FEX-Emu的GitHub Issues里有很多类似问题的讨论值得翻一翻。4.3 图形渲染异常图形问题通常表现为黑屏、花屏、贴图错误、帧率极低等。DXMT的日志是排查这类问题的第一手资料。设置DXMT_LOG_LEVELdebug可以看到详细的渲染调用记录。常见的图形问题和对策问题表现可能原因解决思路黑屏但有声音渲染后端不匹配尝试切换DXMT的Metal设备选择贴图错误纹理格式不支持检查DXMT日志中的纹理格式警告帧率极低着色器编译卡顿启用DXMT的着色器缓存画面撕裂垂直同步未生效在DXMT配置中强制开启VSync花屏内存对齐问题更新FEX-Emu到最新版本DXMT的着色器缓存特别值得说一下。Windows游戏在第一次运行时需要编译大量着色器这个过程在翻译层下会更慢。启用缓存后第二次运行就不需要重新编译了。设置方法是export DXMT_SHADER_CACHE1 export DXMT_SHADER_CACHE_PATH~/dxmt-cache4.4 性能调优经验性能调优是个细活没有一招鲜的办法。我的一般思路是先用工具定位瓶颈再针对性优化。用Activity Monitor或者htop看CPU占用。如果CPU占用很高但GPU占用很低说明瓶颈在指令转译或者API翻译上。可以尝试调整FEX-Emu的配置比如增大翻译缓存、开启多线程翻译等。如果GPU占用很高但帧率上不去说明瓶颈在图形翻译上。可以尝试降低游戏的画质设置减少DXMT需要翻译的渲染调用数量。另外DXMT支持一些Metal特有的优化比如DXMT_METAL_FAMILY可以指定Metal的GPU家族让DXMT生成更优化的着色器代码。内存方面FEX-Emu和Wine都会占用额外内存。如果设备内存紧张可以尝试减小FEX-Emu的翻译缓存大小或者关闭Wine的一些调试功能。4.5 iOS平台的特殊限制热词里出现了iOS说明有人想在iOS设备上跑这套方案。这件事的难度比在macOS上大得多因为iOS的限制非常严格。首先是JIT即时编译的限制。FEX-Emu的动态翻译需要JIT权限而iOS默认不允许普通应用使用JIT。这意味着FEX-Emu在iOS上要么无法工作要么需要特殊的权限配置。在越狱设备上这个问题小一些但在非越狱设备上基本走不通。其次是Metal的访问限制。iOS上的Metal API和macOS上有差异DXMT需要针对iOS做适配。而且iOS的GPU驱动是封闭的调试图形问题比macOS上困难得多。第三是文件系统限制。iOS的沙盒机制让Wine的前缀管理变得复杂程序能访问的目录非常有限。所以我的判断是Madeira在iOS上的可行性目前还比较低除非有特殊的系统权限或者苹果开放相关限制。热词里那些“ios开发者模式”、“ios自动化”之类的词可能更多是在讨论其他话题时被关联进来的不一定和Madeira直接相关。5. 工具链选型与版本管理5.1 Wine版本的选择Wine有稳定版、开发版和Staging版三个分支。稳定版最可靠但功能更新慢开发版功能新但可能有回归问题Staging版包含了一些还没合并到主线的补丁。对于Madeira这种需要最新兼容性的场景我建议用开发版或者Staging版。特别是Staging版它包含了很多针对游戏和特定程序的优化补丁在实际使用中体验更好。版本管理方面不建议用系统包管理器安装的Wine因为版本往往比较旧。可以从Wine的官方仓库或者GitHub Releases下载最新的二进制包或者用brew install --HEAD wine从源码编译最新版。5.2 FEX-Emu的编译选项FEX-Emu的编译选项会影响转译效率和兼容性。几个关键的CMake选项ENABLE_JIT启用JIT编译必须开启否则性能很差ENABLE_LTO链接时优化可以提升性能但编译时间更长ENABLE_ASSERTIONS调试断言开发时开启发布时关闭X86_64_EMULATION启用x86-64模拟必须开启编译FEX-Emu需要比较新的编译器GCC 11以上或者Clang 13以上。在Apple Silicon上编译时注意要用ARM64的原生编译而不是通过Rosetta转译否则编译出来的FEX-Emu性能会受影响。5.3 DXMT的依赖管理DXMT依赖Metal Shading Language的编译器在macOS上需要安装Xcode Command Line Tools。另外DXMT用到了一些C20的特性需要比较新的Clang。DXMT的版本更新比较频繁建议定期从GitHub拉取最新代码重新编译。每次更新后注意看一下Release Notes有时候会有配置格式的变化。5.4 组件之间的版本兼容性Wine、FEX-Emu、DXMT三个组件的版本需要相互兼容。比如某个Wine版本可能修改了图形驱动的接口导致旧版DXMT无法工作。我的经验是尽量用三个组件都比较新的版本并且关注各自项目的Release Notes里有没有提到兼容性变化。如果遇到版本不兼容的问题可以尝试回退其中一个组件到上一个稳定版本。建议在升级前备份好当前能工作的版本组合这样出问题可以快速回滚。6. 实际案例跑一个典型Windows程序的完整记录6.1 案例选择与预期我选了一个比较有代表性的程序来做测试一个基于DirectX 11的2D游戏有中文界面安装包大概200MB。这个程序的特点是比较依赖图形渲染同时有中文字体需求能覆盖大部分常见问题。预期目标是程序能正常安装、启动、显示中文、渲染画面、响应操作。不追求满帧运行能到30帧以上就算成功。6.2 安装过程记录安装程序启动后界面显示正常中文没有乱码。这说明之前配置的字体是生效的。安装过程大概用了两分钟比在原生Windows上慢一些但在可接受范围内。安装完成后程序自动创建了桌面快捷方式。Wine会在前缀的drive_c/users/用户名/Desktop/目录下创建对应的.lnk文件。可以直接用wine命令运行这个快捷方式。6.3 首次运行的问题首次启动时程序卡在加载界面大概30秒然后崩溃了。查看Wine日志发现是DXMT在编译着色器时超时。这是第一次运行的典型问题因为着色器缓存是空的。解决办法是设置更长的超时时间并且启用着色器缓存export DXMT_SHADER_COMPILE_TIMEOUT120 export DXMT_SHADER_CACHE1重新启动后程序顺利加载进入了主界面。中文显示正常字体渲染质量也不错。6.4 性能表现与调优进入游戏后帧率大概在25到35之间波动。用Activity Monitor看CPU占用大概60%GPU占用大概40%。瓶颈主要在CPU端也就是FEX-Emu的指令转译上。尝试了几个优化措施把FEX-Emu的翻译缓存从默认的128MB增加到256MB帧率提升了大概3到5帧关闭Wine的调试输出又提升了2帧左右把DXMT的日志级别从debug调到warn减少了日志写入的开销。最终帧率稳定在35到40之间对于这个类型的游戏来说已经可以流畅玩了。整个调优过程大概花了半小时主要是反复调整参数和观察效果。6.5 这个案例的启示这个案例说明Madeira方案在Apple Silicon上跑Windows程序是可行的但需要一定的调优。首次运行的着色器编译是最耗时的环节启用缓存后后续启动会快很多。CPU端的转译开销是主要瓶颈FEX-Emu的缓存大小对性能有直接影响。另外中文字体问题一定要提前解决否则程序能跑但界面没法看。winetricks的cjkfonts是最省事的方案如果不行再手动复制字体和改注册表。7. 这个方向后续可以怎么玩Madeira这个方案目前还在早期阶段但已经展现出了不错的潜力。从技术演进的角度看有几个方向值得关注。FEX-Emu的转译效率还有提升空间。目前它主要是块翻译加缓存未来如果引入更智能的热点分析和自适应优化性能损耗可以进一步降低。另外FEX-Emu对AVX-512等新指令集的支持也在完善中这会让更多现代程序能跑起来。DXMT对DirectX 12的支持是下一个重点。现在很多新游戏只支持DX12如果DXMT能把DX12翻译做好覆盖面会大很多。不过DX12的翻译复杂度比DX11高不少尤其是涉及光线追踪和异步计算的部分。Wine本身也在持续进化。最近几个版本对ARM64的支持在加强未来可能原生支持ARM64的Windows程序那样就不需要FEX-Emu做指令转译了。当然这需要Windows生态本身向ARM64迁移是个长期过程。对于想尝鲜的开发者我的建议是从小程序开始逐步增加复杂度。先把Wine的基础环境跑通再加上FEX-Emu最后配DXMT。每加一层都充分测试确认稳定后再加下一层。遇到问题多看日志多查项目的GitHub Issues大部分坑别人已经踩过了。我在实际使用中的体会是这套方案的门槛主要在环境配置和问题排查上一旦跑通了日常使用还是比较稳定的。关键是要有耐心遇到崩溃不要慌一步步看日志定位问题。另外保持组件更新很重要很多问题在新版本里已经修了。
返回列表