
1. 项目缘起为什么要在 Linux 上折腾 Windows 应用兼容层第一次看到 Madeira 这个项目名很多人会以为是某个旅游目的地或者葡萄牙的岛屿但在我们这群常年混迹于 Linux 桌面兼容性圈子的人眼里它指向的是一类非常具体的技术实践在非 Windows 系统上运行 Windows 应用。而围绕这个目标热词里出现的 FEX-Emu、Wine、DXMT、x86-64、iOS 这些关键词恰好勾勒出了当前跨平台兼容方案的全貌。先说清楚这个项目要解决的核心问题。Windows 生态积累了海量的桌面软件和游戏很多用户因为工作流、硬件适配或者纯粹的使用习惯没法完全迁移到 Linux 或 macOS。Wine 这类兼容层就是干这个的它不模拟 Windows 内核而是把 Windows 的 API 调用实时翻译成 POSIX 调用让 exe 文件在 Linux 上直接跑起来。这个思路从 1993 年就开始了到现在已经相当成熟但坑依然不少。Madeira 这个标题背后我理解它代表的是一套完整的兼容方案组合底层用 Wine 做 API 转译图形层用 DXMT 把 DirectX 调用转成 Metal在 Apple Silicon 上或者 VulkanCPU 指令层用 FEX-Emu 处理 x86-64 到 ARM64 的翻译。这套组合拳打下来理论上能让大量 Windows 程序在 ARM 架构的 Linux 设备或者 Apple 设备上运行。适合谁来参考这篇内容三类人一是 Linux 桌面用户想跑某些没有原生版本的 Windows 软件二是 Apple Silicon Mac 用户想通过兼容层玩 Windows 游戏三是嵌入式或国产化平台开发者需要在非 x86 架构上跑 Windows 遗留程序。不管你是哪一类下面的内容都会覆盖到。2. 核心组件拆解Wine、FEX-Emu、DXMT 各自扮演什么角色2.1 Wine 到底做了什么为什么会有乱码Wine 的全称是 Wine Is Not an Emulator这句话本身就是它的设计哲学。它不模拟 CPU 指令而是实现了一套 Windows API 的兼容层。当你双击一个 exeWine 加载 PE 格式的可执行文件然后拦截里面所有对 kernel32.dll、user32.dll、gdi32.dll 等系统库的调用把它们翻译成 Linux 的对应实现。热词里 wine 乱码 和 wine 栏是乱码 出现的频率很高这几乎是每个 Wine 用户都会遇到的问题。根本原因在于字符编码和字体映射。Windows 程序默认使用 GBK 或者 UTF-16 编码而 Linux 环境通常是 UTF-8。当 Wine 把 Windows 的字体请求映射到 Linux 字体时如果字体缺失或者映射表不对就会显示成方块或者问号。解决思路分三步走。第一步安装核心字体包把wine-mono、wine-gecko、winetricks里的corefonts、cjkfonts都装上。第二步在winecfg的 显示 选项卡里把默认字体替换成系统里已有的中文字体比如 Noto Sans CJK SC 或者文泉驿微米黑。第三步如果还有个别程序乱码用winetricks单独给这个程序的前缀安装riched20、riched30和msxml系列组件很多老程序的界面渲染依赖这些。注意不要全局修改 Wine 的字体注册表最好给每个程序单独建 prefixWINEPREFIX~/.wine-appname winecfg这样出问题不会互相影响。2.2 FEX-Emu 解决的是指令集翻译问题FEX-Emu 是一个 x86-64 到 ARM64 的用户态模拟器。它的定位和 qemu-user 类似但性能优化做得更激进。核心原理是动态二进制翻译程序运行时FEX 把 x86-64 指令块翻译成 ARM64 指令块然后缓存起来下次执行同一段代码就直接用缓存。为什么需要它因为 Wine 本身只做 API 翻译不做指令翻译。如果你的设备是 ARM 架构比如 Apple M 系列芯片、树莓派、很多国产化平台x86-64 的 exe 文件根本没法直接执行。FEX-Emu 补上了这一环。实测下来FEX-Emu 对 SSE4.2、AVX 指令集的支持比较完整但 AVX-512 支持还在完善中。如果你要跑的程序重度依赖 AVX-512可能会遇到非法指令错误。这时候可以试试在 FEX 配置里开启FEX_AVX5120强制降级或者换用支持更好的模拟器。2.3 DXMT 把 DirectX 翻译成 MetalDXMT 是 DirectX Metal Translation 的缩写专门针对 Apple 平台。它的作用是把 Windows 程序里的 D3D11 和 D3D12 调用翻译成 Metal API。为什么不用 Vulkan 中转因为在 macOS 上Vulkan 本身也要通过 MoltenVK 转成 Metal多一层转换就多一层性能损耗和兼容性问题。DXMT 直接一步到位延迟更低。目前 DXMT 对 D3D11 的支持已经相当可用D3D12 还在早期阶段。如果你要跑的游戏是 DX11 的成功率很高DX12 的游戏建议先查兼容性列表别盲目折腾。3. 实操环境搭建从零开始配置一套可用的兼容层3.1 基础环境准备与依赖安装假设你用的是 Ubuntu 22.04 或者 Debian 12先装基础依赖。这一步不能省很多奇怪的报错都是因为缺库。sudo dpkg --add-architecture i386 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 --version正常应该输出类似wine-9.0的版本号。如果提示找不到命令检查 PATH 或者重新登录终端。接下来装 winetricks这是管理 Wine 组件的瑞士军刀sudo apt install winetricks然后初始化 Wine 前缀WINEPREFIX~/.wine-madeira WINEARCHwin64 winecfg这里我特意用了独立的 prefix 目录不污染默认的~/.wine。WINEARCHwin64指定 64 位架构现在大部分程序都是 64 位的除非你要跑很老的 32 位软件。3.2 字体与中文环境配置中文乱码是重灾区单独拎出来说。在 prefix 初始化完成后执行WINEPREFIX~/.wine-madeira winetricks corefonts cjkfontscorefonts装的是 Arial、Times New Roman 这些西文字体cjkfonts装的是中文字体。装完之后把系统字体链接到 Wine 的字体目录ln -s /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc ~/.wine-madeira/drive_c/windows/Fonts/然后在winecfg里把 显示 选项卡的默认字体改成Noto Sans CJK SC。这一步做完大部分程序的界面中文就能正常显示了。如果还有个别程序乱码大概率是它自己带了字体文件但没正确加载。可以试试在程序目录下放一个font.ini或者修改注册表HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes把MS Shell Dlg映射到中文字体。3.3 FEX-Emu 的安装与配置如果你在 ARM 设备上需要先装 FEX-Emu。以 Ubuntu ARM64 为例sudo add-apt-repository ppa:fex-emu/fex sudo apt update sudo apt install fex-emu装完之后需要把 x86-64 的库文件放到 FEX 的 rootfs 里。FEX 提供了一个脚本FEXRootFSFetcher来自动下载FEXRootFSFetcher选择 Ubuntu 22.04 的 x86-64 rootfs下载完成后会放在~/.local/share/fex-emu/RootFS/下面。配置 FEX 的环境变量export FEX_ROOTFS~/.local/share/fex-emu/RootFS/Ubuntu_22_04 export FEX_APP_CONFIG~/.fex-emu/Config.json然后在Config.json里可以调整一些参数比如{ Config: { RootFS: Ubuntu_22_04, ThunkHostLibs: true, X87ReducedPrecision: true } }ThunkHostLibs开启后FEX 会直接调用宿主系统的库而不是 rootfs 里的能提升性能。X87ReducedPrecision对老程序的浮点运算兼容性有帮助。3.4 DXMT 的编译与部署DXMT 目前没有现成的二进制包需要自己编译。先装依赖sudo apt install meson ninja-build glslang-tools libvulkan-dev然后克隆源码编译git clone https://github.com/3Shain/dxmt.git cd dxmt meson setup build ninja -C build编译完成后把生成的dxmt.dll、d3d11.dll、dxgi.dll复制到 Wine prefix 的system32目录cp build/dxmt.dll ~/.wine-madeira/drive_c/windows/system32/ cp build/d3d11.dll ~/.wine-madeira/drive_c/windows/system32/ cp build/dxgi.dll ~/.wine-madeira/drive_c/windows/system32/然后在winecfg的 函数库 选项卡里把d3d11和dxgi都设为 原装native这样 Wine 就会优先加载 DXMT 的版本而不是自带的。4. 常见问题排查与性能调优实录4.1 程序启动报错速查表报错信息可能原因解决方法err:module:import_dll Library XXX not found缺少依赖 DLL用winetricks安装对应组件或者手动复制 DLL 到 system32wine: cannot find LC:\\windows\\system32\\xxx.exe路径映射错误检查winecfg的驱动器映射确保 Z: 盘指向根目录Unhandled page fault on read access内存访问越界通常是模拟器 bug尝试关闭 FEX 的 JIT 优化或者换用不同版本的 WineDXGI_ERROR_UNSUPPORTEDDXMT 不支持该图形特性降级到 D3D11 模式或者换用 Vulkan 后端界面中文显示为方块字体缺失或映射错误按 3.2 节重新配置字体4.2 性能调优的几个关键参数Wine 的性能调优空间其实不大但有几个参数值得关注。首先是WINEDEBUG默认情况下 Wine 会输出大量调试信息拖慢启动速度。可以在启动脚本里加上export WINEDEBUG-all这会关闭所有调试输出启动速度能快 20% 到 30%。其次是 FEX 的 JIT 缓存。默认情况下 FEX 每次启动都重新翻译指令开启缓存后第二次启动会快很多export FEX_JITCACHE~/.fex-emu/JITCacheDXMT 这边可以在dxmt.conf里调整maxFrameLatency参数默认是 3改成 1 能降低输入延迟但可能增加卡顿。这个要根据具体游戏来调。4.3 我踩过的几个坑第一个坑是prefix 架构混用。我一开始图省事在 64 位 prefix 里直接跑 32 位程序结果各种 DLL 加载失败。后来老老实实建了两个 prefix一个win64一个win32问题就没了。Wine 虽然支持 WoW6432 位程序跑在 64 位 prefix 里但兼容性还是不如原生架构。第二个坑是FEX 和 Wine 的版本匹配。FEX 更新比较快有时候新版本 FEX 配老版本 Wine 会出问题。我的经验是Wine 用 stable 版本FEX 用 release 版本别追最新的 git master。第三个坑是DXMT 的 DLL 覆盖顺序。DXMT 的dxgi.dll必须比d3d11.dll先加载否则会初始化失败。在winecfg里调整函数库顺序的时候要注意这一点。5. 跨平台场景延伸从 Linux 到 iOS 的兼容思路热词里出现了不少 iOS 相关的词比如 ios 开发者模式、ios 自动化、ios 分屏、xcode 从证书配置到上架全流程。这些和 Wine 兼容层看似不相关但其实底层逻辑是相通的都是在非原生环境下运行目标平台的程序。iOS 的沙盒机制比 Linux 严格得多没法直接跑 Wine。但有一些间接思路比如通过 Xcode 的模拟器运行 x86-64 的 iOS 应用在 Apple Silicon 上需要 Rosetta 2 做指令翻译或者用 uniapp 这类跨平台框架把 Web 应用打包成 iOS 原生插件。热词里 uniapp 使用 ios 原生插件 说的就是这个场景。如果你在做 iOS 开发遇到 xcode 打包 ios 突然很慢 的问题大概率是证书链验证或者代码签名环节卡住了。可以试试清理 DerivedData 目录或者把 Automatically manage signing 关掉手动配置。这个和 Wine 的 prefix 隔离思路是一样的把问题隔离到最小范围逐个排查。至于 ios 浏览器唤起安装 app 和那个https://cb95f.advrbluks.com/download/jgdj/ios?aff_codeagskv链接这属于 Web 端分发场景。实现方式是在页面里放一个itms-services://协议的链接配合 plist 文件描述安装包信息。不过这种分发方式需要企业证书个人开发者用不了。6. 国产化平台上的 Wine 实践热词里 麒麟 wine 助手、统信 wine windows 兼容组件下载、麒麟 wine 助手下载 这几个词指向的是国产 Linux 发行版上的 Wine 集成方案。麒麟和统信都提供了图形化的 Wine 配置工具本质上是对winecfg和winetricks的封装降低了使用门槛。在麒麟系统上Wine 的安装路径通常是/opt/wine或者/usr/lib/wine。如果遇到 wine deepin 无法下载 的问题大概率是软件源配置不对。可以手动添加官方源或者直接下载 deb 包用dpkg -i安装。统信的 Wine 兼容组件包名一般是deepin-wine或者uos-wine安装后会在/opt/deepinwine下生成 prefix。这个 prefix 已经预装了大量常用组件比如riched20、msxml、vcrun系列省去了手动配置的麻烦。提示国产化平台上的 Wine 版本通常比较老对新版 DirectX 的支持有限。如果要跑较新的游戏建议自己编译新版 Wine或者用 Flatpak 安装org.winehq.Wine。7. 一些零散但有用的经验关于 win7 系统镜像 ios 下载 和 rhel8.0 镜像下载 ios 这类词我理解可能是有人在找系统镜像文件。这里提醒一句下载系统镜像一定要从官方渠道第三方来源的镜像可能被篡改存在安全风险。而且很多所谓的 ios 镜像 其实是 ISO 文件的误写ISO 是光盘镜像格式和 iOS 没有任何关系。win pe uefi 版 ios 也是同样的误写应该是 win pe uefi 版 iso。WinPE 是 Windows 预安装环境常用于系统维护和部署。制作 UEFI 版的 WinPE 启动盘需要用 Rufus 或者 Ventoy 这类工具把 ISO 写入 U 盘时选择 GPT 分区方案和 UEFI 启动模式。银行模拟器 ios 和 ios 游戏 这两个词如果是指 iOS 平台上的应用那和 Wine 兼容层关系不大。但如果是指在 PC 上模拟 iOS 环境目前没有成熟的方案。iOS 的闭源程度太高模拟器只能做到界面级别的模仿没法运行真实的 iOS 应用。notification banner 仿 ios 通知横幅 这个需求在 Web 开发里很常见。实现方式是用 CSS 动画做一个从顶部滑入的横幅配合 JavaScript 控制显示和隐藏。关键点是动画曲线要用cubic-bezier(0.4, 0, 0.2, 1)这样才有 iOS 那种顺滑感。圆角和阴影也要调到位border-radius: 12px加上box-shadow: 0 4px 12px rgba(0,0,0,0.15)基本就能以假乱真了。ios 无感 和 ios 无感漏洞 这两个词我不太确定具体指什么。如果是指无感登录或者无感支付那属于业务层面的设计和系统兼容性无关。如果是指某种绕过系统限制的方法那不在本文讨论范围内。最后说一个实际经验Wine 的兼容性数据库AppDB是个好东西遇到跑不起来的程序先去上面搜一下大概率有人已经踩过坑并给出了解决方案。地址是appdb.winehq.org虽然界面丑了点但信息量很足。我每次遇到新程序第一件事就是查 AppDB能省下大量试错时间。