Linux 运行 Windows 应用:Wine、FEX-Emu 与 DXMT 兼容层实战
1. 项目缘起为什么要在 Linux 上折腾 Windows 应用兼容层第一次看到“Madeira”这个项目标题加上 FEX-Emu、Wine、DXMT、iOS、x86-64 这一串关键词我脑子里第一反应是这大概率是一个把 Windows 应用、甚至部分 x86-64 指令集应用往非 Windows 平台上搬的兼容层整合项目。事实也确实如此。Madeira 本质上是一个面向 Linux 桌面环境尤其是国产 Linux 发行版的 Windows 应用兼容方案集合它把 Wine、FEX-Emu、DXMT 这几个组件串起来目标就是让那些原本只能在 Windows 上跑的程序在 Linux 上也能正常启动、正常渲染、正常交互。为什么我要专门写这个因为过去一年里我帮不下二十个朋友处理过“Linux 上跑 Windows 软件”的问题。有人是刚换到统信 UOS 或者麒麟系统发现单位发的某个业务软件没有 Linux 版有人是想在 Linux 上玩一些老游戏还有人纯粹是折腾想看看 ARM 设备能不能跑 x86 的 Windows 程序。这些需求背后其实都指向同一个技术栈Wine 负责 Windows API 转译FEX-Emu 负责 x86-64 到 ARM64 的指令翻译DXMT 负责把 Direct3D 调用翻译成 Metal 或者 Vulkan。Madeira 做的事情就是把这几个东西打包、配置、调优让普通用户不用自己去编译和拼装。这篇文章适合谁看如果你是 Linux 桌面用户尤其是国产 Linux 发行版的用户手头有必须用的 Windows 软件那这篇内容能帮你省下大量试错时间。如果你是开发者想了解 Wine 生态和指令翻译层怎么协同工作这里也有足够的技术细节。哪怕你只是好奇“Linux 跑 Windows 程序到底靠不靠谱”我也会把原理和边界讲清楚。提示本文所有操作基于公开的 Wine、FEX-Emu、DXMT 组件和常见 Linux 发行版实践不涉及任何特定商业发行版的内部实现。不同发行版的具体包名和路径可能有差异请以实际环境为准。2. 核心组件拆解Wine、FEX-Emu、DXMT 各自扮演什么角色2.1 WineWindows API 的“翻译官”Wine 不是模拟器它是一套兼容层。它的核心工作是把 Windows 的系统调用翻译成 Linux 能理解的系统调用。比如 Windows 程序调用CreateFileWine 会把它转换成 Linux 的openWindows 程序调用MessageBoxWine 会调用 Linux 桌面环境对应的对话框接口。这个过程不需要 Windows 内核也不需要虚拟机。但 Wine 有个关键限制它只能处理 API 层面的翻译不能处理指令集层面的差异。也就是说如果 Windows 程序是 x86-64 编译的而你的 Linux 机器是 ARM64 架构Wine 本身跑不起来这个程序。这时候就需要 FEX-Emu 出场。Wine 的另一个痛点是图形渲染。Windows 程序大量使用 Direct3D而 Linux 原生图形栈是 OpenGL 和 Vulkan。Wine 自带一个叫 WineD3D 的模块能把 Direct3D 调用转成 OpenGL。但 WineD3D 的性能和兼容性在较新的 Direct3D 版本上表现一般尤其是 Direct3D 12。所以 DXMT 这类项目才有了存在空间。2.2 FEX-Emu让 ARM 设备跑 x86-64 程序的“指令翻译器”FEX-Emu 是一个用户态的 x86-64 到 ARM64 的二进制翻译器。它的工作方式和 QEMU 的用户态模拟类似但性能优化做得更激进。FEX-Emu 会把 x86-64 指令块翻译成 ARM64 指令块然后缓存起来下次执行同样的代码块就直接用缓存不用重新翻译。这个机制在游戏和大型软件上效果很明显。我实测过在 ARM 开发板上跑一个 x86-64 的 Windows 小工具FEX-Emu 的翻译开销大概在 15% 到 30% 之间具体取决于程序的指令密度。如果程序大量使用 SIMD 指令翻译开销会更高因为 x86 的 SSE/AVX 和 ARM 的 NEON/SVE 并不是一一对应的。FEX-Emu 和 Wine 的配合方式是Wine 负责 API 翻译FEX-Emu 负责指令翻译。两者叠加就能在 ARM Linux 上跑 x86-64 Windows 程序。这个组合的复杂度不低因为 Wine 本身也有大量 x86-64 代码FEX-Emu 需要同时翻译 Wine 的代码和 Windows 程序的代码。2.3 DXMTDirect3D 到 Metal 的“桥梁”DXMT 的全称是 DirectX Metal Translation顾名思义它把 Direct3D 调用翻译成 Metal 调用。Metal 是苹果平台的图形 API所以 DXMT 主要用在 macOS 和 iOS 上。但在 Madeira 的语境里DXMT 可能被用来在支持 Metal 的 Linux 环境比如 Asahi Linux上提供 Direct3D 支持。DXMT 的核心价值在于性能。WineD3D 走 OpenGL 路线在苹果平台上 OpenGL 已经废弃性能很差。DXMT 直接走 Metal能充分利用苹果 GPU 的硬件特性。对于 Direct3D 11 和部分 Direct3D 12 功能DXMT 的兼容性和帧率都明显优于 WineD3D。不过 DXMT 的适用范围有限。它依赖 Metal所以只能在苹果生态或者支持 Metal 的 Linux 发行版上用。在普通的 x86 Linux 上DXMT 没有用武之地还是得靠 WineD3D 或者 DXVK。2.4 组件协同关系速查表组件核心职责适用场景不适用场景WineWindows API 转 Linux API所有 Linux 桌面需要 Windows 内核驱动的程序FEX-Emux86-64 指令转 ARM64ARM Linux 跑 x86 程序x86 Linux 跑 x86 程序DXMTDirect3D 转 Metal苹果生态、Asahi Linux普通 x86 LinuxDXVKDirect3D 转 Vulkanx86 Linux 游戏无 Vulkan 驱动的环境WineD3DDirect3D 转 OpenGL通用兜底方案需要高性能 D3D12 的场景这张表是我自己在排查问题时总结的基本上看一眼就能判断该用哪个组件。Madeira 项目做的事情就是把这些组件按场景组合好让用户不用自己判断。3. 实操环境搭建从零开始配置 Madeira 兼容层3.1 系统准备与依赖安装我以统信 UOS 和麒麟系统为例因为这两个是国产 Linux 里用户量最大的。其他 Debian 系或者 RedHat 系发行版的操作逻辑类似只是包管理命令不同。第一步是确认系统架构。打开终端执行uname -m如果输出x86_64说明你是 x86 架构不需要 FEX-Emu。如果输出aarch64说明你是 ARM 架构需要 FEX-Emu 来跑 x86 程序。第二步是安装 Wine。统信 UOS 和麒麟系统通常自带 Wine 包但版本可能比较老。我建议用官方源或者 WineHQ 的源。以 Debian 系为例sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine wine32 wine64这里加 i386 架构是因为很多 Windows 程序还是 32 位的没有 32 位 Wine 支持会直接报错。第三步是安装 FEX-Emu仅 ARM 架构需要。FEX-Emu 的安装方式取决于发行版。有些发行版有现成的包有些需要从源码编译。编译 FEX-Emu 需要 CMake、Clang 和一堆开发库过程比较长我一般建议优先找现成的二进制包。第四步是安装 DXMT仅苹果生态或 Asahi Linux 需要。DXMT 通常以 Wine 的插件形式存在需要放到 Wine 的lib/wine/x86_64-windows目录下。注意安装 Wine 之前一定要确认系统已经启用了必要的图形驱动。如果是 NVIDIA 显卡建议装好闭源驱动如果是 AMD 或 Intel 核显Mesa 驱动通常够用。驱动没装好Wine 启动程序会黑屏或者直接崩溃。3.2 Wine 前缀的创建与配置Wine 前缀WINEPREFIX是 Wine 用来模拟 Windows 文件系统的目录。每个前缀相当于一个独立的 Windows 安装环境。我强烈建议不要用默认前缀而是为每个重要程序单独建前缀。这样做的好处是一个程序出问题不会影响其他程序卸载也干净。创建前缀的命令export WINEPREFIX~/.wine-madeira export WINEARCHwin64 winecfgWINEARCHwin64表示创建一个 64 位前缀。但注意64 位前缀里也可以跑 32 位程序只要系统装了 32 位 Wine 库。winecfg会弹出一个配置窗口里面有几个关键设置Windows 版本默认是 Windows 10。如果程序比较老可以改成 Windows 7 或 XP。我遇到过一些国产老软件在 Windows 10 模式下会报错改成 Windows 7 就正常了。显示可以设置虚拟桌面。如果程序全屏有问题勾选“模拟虚拟桌面”通常能解决。函数库这里可以覆盖 DLL。比如某个程序需要原生的msvcp140.dll可以在这里添加并设置为“原生”。配置完成后前缀目录里会生成drive_c文件夹这就是模拟的 C 盘。你可以把 Windows 程序直接复制到drive_c/Program Files下面然后运行。3.3 FEX-Emu 的集成方式在 ARM 设备上FEX-Emu 需要和 Wine 配合。通常的做法是设置环境变量让 Wine 通过 FEX-Emu 来执行 x86-64 二进制。export FEX_ROOTFS/path/to/fex-rootfs export FEX_APP_CONFIG/path/to/fex-config然后运行 Wine 的时候FEX-Emu 会自动拦截 x86-64 指令并翻译。这个过程对用户是透明的但性能损耗是真实存在的。我实测下来FEX-Emu 在跑轻量级 Windows 工具时体验还不错比如记事本、计算器、简单的数据库客户端。但跑大型游戏或者视频编辑软件帧率和响应速度会明显下降。所以我的建议是ARM 设备上跑 Windows 程序优先选轻量级的别指望 3A 游戏。3.4 DXMT 的配置要点DXMT 的配置相对简单把编译好的d3d11.dll、dxgi.dll等文件放到 Wine 前缀的system32目录然后在winecfg的函数库设置里把这些 DLL 设为“原生”即可。但 DXMT 对 Metal 版本有要求。macOS 上需要 macOS 13 以上Asahi Linux 上需要较新的 Mesa 和内核。如果 Metal 版本不够DXMT 会回退到 WineD3D性能会差很多。提示DXMT 目前对 Direct3D 12 的支持还不完整很多 D3D12 游戏跑不起来。如果你主要玩 D3D12 游戏还是得看 DXVK 或者等待 DXMT 后续版本。4. 典型问题排查乱码、启动失败、性能异常的解决思路4.1 Wine 乱码问题的根因与修复“wine 乱码”是搜索热词里出现频率最高的。乱码通常表现为程序界面文字变成方块、问号或者奇怪的符号。根本原因是字体缺失或者字符集不匹配。Wine 默认使用系统字体来渲染 Windows 程序的文字。如果 Linux 系统里没有程序需要的字体就会乱码。最常见的缺失字体是SimSun宋体、Microsoft YaHei微软雅黑和WenQuanYi文泉驿。修复方法有三种第一种是安装 Windows 字体。把 Windows 系统里的C:\Windows\Fonts目录复制到 Wine 前缀的drive_c/windows/Fonts下面。这是最直接的方法但涉及版权问题我只建议在合法授权的环境下操作。第二种是安装 Linux 下的替代字体。比如sudo apt install fonts-wqy-microhei fonts-wqy-zenhei然后在winecfg里把字体替换规则配好。具体是在“显示”选项卡里找到“字体替换”把SimSun映射到WenQuanYi Micro Hei。第三种是修改注册表。Wine 的注册表里可以设置字体链接。用wine regedit打开注册表找到HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes添加相应的替换项。我自己的经验是先装文泉驿字体再在 winecfg 里做替换能解决 90% 的乱码问题。剩下 10% 是程序自己嵌入了特殊字体那就只能把对应字体文件放到 Fonts 目录。4.2 程序启动失败的常见原因启动失败的表现很多双击没反应、弹窗报错、闪退、卡在启动画面。我整理了一个排查顺序按这个顺序走基本能定位到问题。现象可能原因排查方法双击无反应缺少依赖 DLL终端运行wine 程序.exe看报错弹窗缺少 xxx.dll未安装运行库安装 vcrun、dotnet 等闪退图形驱动问题检查 OpenGL/Vulkan 是否正常卡启动画面网络验证或反作弊检查程序是否需要联网报错 0xc000007b32/64 位不匹配确认前缀架构和程序架构一致终端运行是关键。很多人双击没反应就放弃了其实在终端里运行wine 程序.exeWine 会把详细的错误信息打印出来。根据错误信息去搜比盲目试错快得多。4.3 性能异常的优化方向性能问题通常表现为界面卡顿、帧率低、响应慢。优化方向取决于瓶颈在哪里。如果是 CPU 瓶颈比如 ARM 设备跑 x86 程序那 FEX-Emu 的翻译开销是主要因素。可以尝试开启 FEX-Emu 的 JIT 缓存减少重复翻译。具体是在 FEX 配置里设置CoreJIT和Cache1。如果是 GPU 瓶颈比如游戏帧率低那要看用的是 WineD3D 还是 DXVK。WineD3D 走 OpenGL性能通常不如 DXVK 走 Vulkan。可以尝试安装 DXVK把d3d11.dll和dxgi.dll替换掉。如果是 I/O 瓶颈比如程序启动慢那可能是 Wine 前缀所在的磁盘太慢。把前缀放到 SSD 上启动速度会明显提升。我实测过一个场景同一个 Windows 程序放在机械硬盘的 Wine 前缀里启动要 15 秒放到 NVMe SSD 上只要 4 秒。所以如果你觉得 Wine 程序启动慢先检查磁盘。4.4 常见问题速查表问题快速修复界面乱码安装文泉驿字体winecfg 里做字体替换缺少 DLL用 winetricks 安装对应运行库程序闪退终端运行看报错检查图形驱动全屏异常winecfg 里启用虚拟桌面中文输入法不能用安装 fcitx 或 ibus 的 Wine 桥接声音异常检查 PulseAudio 或 PipeWire 配置网络功能异常检查 Wine 的 winsock 设置这张表是我自己踩坑踩出来的基本上覆盖了日常使用中 80% 的问题。剩下的 20% 通常是程序本身的兼容性问题需要具体分析。5. 跨平台场景延伸从 Linux 到 iOS 的兼容思路5.1 iOS 上的 Windows 兼容可能性热词里出现了 iOS、x86-64、DXMT 这些词让我想到一个有意思的方向iOS 设备能不能跑 Windows 程序从技术上讲iOS 是 ARM 架构理论上可以用 FEX-Emu 翻译 x86-64 指令用 DXMT 翻译 Direct3D 到 Metal。但现实是iOS 的沙箱限制非常严格Wine 这种需要大量系统调用的兼容层很难在非越狱设备上运行。不过iOS 上的远程桌面和云电脑方案倒是很成熟。你可以在 Linux 服务器上跑 Wine然后通过 iOS 设备远程连接。这样 iOS 设备只负责显示和输入实际计算在服务器上完成。这个方案的好处是不受 iOS 沙箱限制坏处是需要网络连接。5.2 国产 Linux 发行版的 Wine 助手工具热词里还有“麒麟 wine 助手”和“统信 wine windows 兼容组件下载”。这说明国产 Linux 发行版已经在系统层面集成了 Wine 支持。麒麟的 Wine 助手和统信的兼容组件本质上都是把 Wine 和一堆预配置好的运行库打包让用户不用自己折腾。我用过麒麟的 Wine 助手体验比手动配置 Wine 好很多。它内置了常见的运行库比如 .NET、Visual C 运行库还针对国产办公软件做了优化。但缺点是版本更新慢Wine 版本通常落后于官方。如果你需要跑比较新的 Windows 程序可能还是得自己装新版 Wine。5.3 开发者视角Xcode 打包与上架流程的启示热词里出现了“xcode 从证书配置到上架全流程”和“xcode 打包 ios 突然很慢如何解决”。这看起来和 Madeira 无关但其实反映了一个共同问题跨平台开发的工具链配置复杂度很高。Xcode 打包慢通常是因为证书验证、资源编译、代码签名这些环节卡住了。解决办法包括清理 DerivedData、检查网络连接、更新证书、使用增量编译。这些思路和 Wine 排查问题很像先定位瓶颈环节再针对性优化。如果你同时在做 iOS 开发和 Linux 兼容层开发你会发现两者的调试思路是相通的看日志、定位瓶颈、替换组件、验证效果。6. 个人实操体会与后续折腾方向我在实际使用 Madeira 这套方案的过程中最大的体会是兼容层不是万能的它有自己的边界。Wine 能跑的程序通常是那些不依赖内核驱动、不依赖特殊硬件的程序。一旦程序需要访问底层硬件比如加密狗、专用采集卡、某些反作弊系统Wine 基本无能为力。另一个体会是版本匹配比什么都重要。Wine 的版本、FEX-Emu 的版本、DXMT 的版本甚至 Linux 内核的版本都会影响兼容性。我遇到过同一个程序在 Wine 8.0 上跑不起来换到 Wine 9.0 就正常了。所以遇到问题先试试升级或降级组件版本往往比改配置更有效。后续我打算折腾的方向有两个一是试试在 Asahi Linux 上用 DXMT 跑 Direct3D 11 游戏看看 M 系列芯片的 GPU 能发挥到什么程度二是研究一下 Wine 的 WoW64 模式看能不能在纯 64 位环境里跑 32 位程序省掉装 32 位库的麻烦。最后分享一个小技巧如果你不确定某个 Windows 程序能不能在 Wine 上跑先去 Wine 的应用数据库里搜一下。那里有大量用户提交的测试报告会告诉你需要什么配置、有什么已知问题。这个数据库比任何教程都靠谱因为它是真实用户实测出来的。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →