1. 项目缘起为什么要在 Linux 上折腾 Windows 应用兼容层第一次接触 Madeira 这个项目是在一台老旧的 ThinkPad 上。那台机器跑着某个国产 Linux 发行版硬件配置不算差但日常办公里总有几个 Windows 独占的小工具绕不开——比如某个老版本的串口调试助手、一套只能在 Windows 下跑的行业软件还有一个客户坚持要用的报表生成器。虚拟机方案试过资源占用太高风扇呼呼转双系统也试过切换一次要重启效率低得让人抓狂。后来在社区里翻帖子看到有人提到 Madeira 这个思路把 Wine 和 FEX-Emu 这两套东西组合起来在 Linux 上直接跑 Windows 应用尤其是那些 x86-64 架构的二进制程序。Madeira 这个名字本身挺有意思它是一座岛屿的名字也暗示着“连接”和“桥梁”的意味。这个项目的核心目标很明确在非 x86 架构的 Linux 设备上比如 ARM64 的笔记本、开发板、甚至某些国产芯片平台通过 FEX-Emu 做指令集翻译再通过 Wine 提供 Windows API 兼容层最终让 Windows 应用能够直接运行。DXMT 则是其中负责 DirectX 转译的关键组件把 Windows 下的图形调用翻译成 Vulkan 或 OpenGL让游戏和图形应用也能跑起来。这套方案解决的核心问题是什么简单说就是跨架构、跨系统的应用兼容。你不需要买一台 Windows 机器也不需要装虚拟机直接在 Linux 上就能用 Windows 软件。适合谁来参考三类人一是 Linux 桌面用户手头有几个 Windows 独占软件离不开二是嵌入式或国产平台开发者需要在 ARM 设备上跑 x86 的 Windows 工具链三是对系统兼容层、指令翻译技术感兴趣的技术爱好者。我写这篇东西就是把这几个月折腾 Madeira 的经验、踩过的坑、以及最终跑通的配置完整记录下来给后来人省点时间。2. 核心组件拆解FEX-Emu、Wine、DXMT 各自扮演什么角色2.1 FEX-Emu把 x86-64 指令翻译成 ARM64 的“实时口译员”FEX-Emu 是整个链条里最底层的一环。它的工作方式可以类比成一场同声传译Windows 应用编译出来的是 x86-64 指令而你的 ARM64 CPU 根本看不懂这些指令FEX-Emu 就在中间做实时翻译。它不像 QEMU 那样做完整的系统模拟而是专注于用户态的指令翻译所以性能损耗相对小很多。我实测下来FEX-Emu 对 SSE4.2、AVX 这些指令集的支持已经相当完整大部分办公软件和中小型游戏都能跑。但要注意FEX-Emu 的配置对性能影响极大。默认配置下它用的是“按需翻译”模式第一次执行某段代码时会慢之后有缓存就快了。如果你跑的是那种循环密集型的计算任务建议开启FEX_TSOENABLED1和FEX_ROOTFS相关的优化选项具体参数后面会细说。还有一个关键点FEX-Emu 需要配合一个 RootFS 使用。这个 RootFS 本质上是一个精简的 x86-64 Linux 文件系统里面包含了 Wine 运行所需的库和二进制文件。Madeira 项目通常会提供一个预构建的 RootFS 包但如果你要自己定制就得用debootstrap或者mmdebstrap手动构建一个 x86-64 的 Debian 根文件系统然后再把 Wine 装进去。这个过程比较繁琐新手建议直接用现成的。2.2 WineWindows API 的“翻译官”但不止是翻译Wine 在 Madeira 里的角色是提供 Windows API 的实现。Windows 应用调用CreateWindowEx、MessageBox这些函数时Wine 负责把这些调用翻译成 Linux 下的 X11 或 Wayland 调用。很多人以为 Wine 是个模拟器其实它更像是一个“兼容层”——它不模拟 Windows 内核而是直接实现 Windows 的 API 接口。在 Madeira 的架构里Wine 是跑在 FEX-Emu 之上的。也就是说Wine 本身也是 x86-64 的二进制由 FEX-Emu 翻译执行。这就带来一个有意思的现象Wine 的某些底层操作比如内存管理、线程调度会被 FEX-Emu 拦截并翻译而上层 API 调用则由 Wine 自己处理。这种双层结构对性能有一定影响但换来的是更好的兼容性。我遇到的一个典型问题是 Wine 的乱码。热词里提到的“wine 乱码”和“wine 栏是乱码”多半是因为字体配置不对。Wine 默认会去找 Windows 字体但在 Linux 环境下这些字体往往不存在。解决办法有两个一是把 Windows 的字体文件比如simsun.ttc、msyh.ttf复制到 Wine 的字体目录二是通过winetricks安装corefonts和cjkfonts。我一般用第二种省事。具体命令是winetricks corefonts cjkfonts跑完之后重启 Wine 应用乱码基本就消失了。2.3 DXMT让 DirectX 游戏在 Vulkan 上跑起来DXMT 是 Madeira 里负责图形转译的组件。它的作用是把 Windows 下的 DirectX 9/10/11 调用翻译成 Vulkan。为什么选 Vulkan 而不是 OpenGL因为 Vulkan 的底层控制能力更强转译效率更高尤其是在 ARM 平台上Vulkan 驱动的成熟度普遍比 OpenGL 好。DXMT 的配置相对复杂需要根据你的 GPU 型号调整。比如在 Mali GPU 上你需要确保 Vulkan 驱动已经正确安装并且VK_ICD_FILENAMES环境变量指向正确的 ICD 文件。我试过在 RK3588 开发板上跑一个老版本的《魔兽争霸3》帧率能稳定在 40-50 帧对于这种转译方案来说已经相当不错了。但如果是 DX11 的大型游戏帧率会明显下降毕竟多了一层翻译性能损耗是不可避免的。需要注意的是DXMT 目前对 DX12 的支持还不完善很多新游戏跑不起来。如果你主要目的是玩游戏建议优先考虑那些 DX9 或 DX11 的老游戏兼容性和性能都会好很多。3. 环境搭建实操从零开始配置 Madeira3.1 系统准备与依赖安装我用的基础系统是 Ubuntu 22.04 ARM64 版本跑在一台 RK3588 开发板上。理论上任何 ARM64 Linux 发行版都可以但 Ubuntu 的软件源最全踩坑最少。首先更新系统并安装基础依赖sudo apt update sudo apt upgrade -y sudo apt install -y build-essential cmake ninja-build git python3 python3-pip \ libsdl2-dev libepoxy-dev libdrm-dev libgbm-dev libvulkan-dev \ vulkan-tools mesa-vulkan-drivers这些依赖里libsdl2-dev和libepoxy-dev是 FEX-Emu 编译时需要的vulkan-tools和mesa-vulkan-drivers是 DXMT 运行的基础。如果你用的是其他发行版包名可能略有不同比如 Fedora 下是SDL2-devel和libepoxy-devel。注意一定要确认你的内核版本在 5.15 以上并且开启了CONFIG_USER_NS和CONFIG_BINFMT_MISC。FEX-Emu 依赖用户命名空间来做一些隔离操作如果内核没开这个选项跑起来会报权限错误。3.2 编译安装 FEX-EmuFEX-Emu 的编译过程比较耗时在 RK3588 上大概要 40 分钟。首先克隆源码git clone https://github.com/FEX-Emu/FEX.git cd FEX git submodule update --init --recursive然后配置编译选项。这里有个关键点-DENABLE_LTOON可以开启链接时优化能提升 10%-15% 的性能但编译时间会更长。如果你赶时间可以先关掉。mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease \ -DENABLE_LTOON \ -DENABLE_ASSERTIONSOFF \ -DCMAKE_INSTALL_PREFIX/usr/local \ .. make -j$(nproc) sudo make install编译完成后你需要准备一个 RootFS。Madeira 项目通常会提供一个打包好的 RootFS 压缩包解压到/opt/fex-rootfs即可。如果没有现成的可以用mmdebstrap自己构建sudo mmdebstrap --archamd64 bullseye /opt/fex-rootfs \ deb http://deb.debian.org/debian bullseye main contrib non-free构建完成后进入 RootFS 安装 Winesudo chroot /opt/fex-rootfs dpkg --add-architecture amd64 apt update apt install -y wine64 wine32 winetricks exit3.3 Wine 的配置与字体修复Wine 装好之后第一次运行会初始化配置目录。在 FEX-Emu 环境下你需要通过FEXBash来进入 x86-64 的 ShellFEXBash winecfgwinecfg会弹出图形界面如果没弹出来检查一下DISPLAY环境变量是否设置正确。在配置界面里把 Windows 版本设置为 Windows 10图形驱动选 Vulkan如果 DXMT 已经装好。字体乱码的修复我推荐用winetrickswinetricks corefonts cjkfonts这个命令会下载并安装微软的核心字体和 CJK 字体。如果下载速度慢可以手动把字体文件放到~/.wine/drive_c/windows/Fonts/目录下。我一般会把 Windows 系统里的simsun.ttc、msyh.ttf、simhei.ttf都拷过去覆盖面更广。实操心得Wine 的字体配置有个坑就是Fonts目录下的字体文件权限必须是可读的而且文件名不能有中文。我有一次把字体文件命名为“宋体.ttc”结果 Wine 死活认不出来改成simsun.ttc就正常了。3.4 DXMT 的安装与验证DXMT 的安装相对简单直接从 GitHub Releases 下载预编译的.so文件放到 Wine 的system32目录wget https://github.com/3Shain/dxmt/releases/download/v0.1.0/dxmt.tar.gz tar -xzf dxmt.tar.gz cp dxmt/*.so ~/.wine/drive_c/windows/system32/然后设置环境变量export DXMT_ENABLE1 export VK_ICD_FILENAMES/usr/share/vulkan/icd.d/your_gpu_icd.json验证 DXMT 是否生效可以跑vulkaninfo看看 Vulkan 是否正常然后在 Wine 里运行dxdiag如果显示 DirectX 版本和显卡信息说明 DXMT 已经工作了。4. 典型应用场景与性能调优4.1 办公软件WPS、Notepad 和串口工具在 Madeira 上跑 WPS Office 是我最常用的场景。安装过程和 Windows 下一样直接运行安装程序即可。实测下来WPS 的文字处理和表格功能都能正常使用启动速度比虚拟机快不少。但要注意WPS 的某些云同步功能依赖 Windows 的网络栈在 Wine 下可能会报错建议关闭云同步。Notepad 这种轻量级编辑器跑起来毫无压力甚至比在 Windows 下还流畅。串口调试工具稍微麻烦一点因为需要访问/dev/ttyUSB0这样的设备节点。解决办法是在 Wine 的注册表里把COM1映射到/dev/ttyUSB0wine reg add HKEY_LOCAL_MACHINE\Software\Wine\Ports /v COM1 /t REG_SZ /d /dev/ttyUSB0这样串口工具就能正常识别串口了。4.2 游戏场景DX9 老游戏的兼容性实测我用 DXMT 跑了几款老游戏兼容性最好的是《魔兽争霸3》和《红色警戒2》。这两款都是 DX8/DX9 时代的游戏DXMT 的转译效率很高帧率稳定。但《魔兽世界》这种 DX11 的游戏就吃力了帧率只有 15-20 帧基本没法玩。性能调优方面有几个参数很关键参数作用推荐值FEX_TSOENABLED开启 TSO 内存模型提升多线程性能1FEX_ROOTFS指定 RootFS 路径/opt/fex-rootfsDXMT_FRAME_RATE限制帧率降低 CPU 占用60WINE_CPU_TOPOLOGY模拟 CPU 核心数4:4注意FEX_TSOENABLED1虽然能提升性能但在某些应用下会导致崩溃。如果遇到随机崩溃先把这个参数关掉试试。4.3 开发工具在 ARM 上跑 x86 工具链Madeira 还有一个很有意思的用法在 ARM 设备上跑 x86-64 的编译工具链。比如某些嵌入式开发工具只提供 x86-64 的 Linux 版本在 ARM 上没法直接运行。通过 FEX-Emu Wine 的组合你可以把这些工具跑起来虽然性能有损耗但至少能用。我试过在 RK3588 上跑一个 x86-64 的 GCC 交叉编译器编译一个中等规模的项目耗时大约是原生 x86 机器的 3 倍。对于不赶时间的场景这个方案完全可行。5. 常见问题与排查技巧实录5.1 Wine 乱码问题速查表现象可能原因解决方法菜单栏乱码缺少 CJK 字体winetricks cjkfonts对话框文字显示为方块字体文件权限不对chmod 644 ~/.wine/drive_c/windows/Fonts/*部分文字正常部分乱码字体替换表未配置在winecfg中设置字体替换安装程序界面乱码安装程序使用了非 Unicode 编码设置LANGzh_CN.UTF-85.2 FEX-Emu 启动失败的排查思路FEX-Emu 启动失败最常见的原因是 RootFS 路径不对或者权限不足。首先检查FEX_ROOTFS环境变量是否指向正确的目录然后确认该目录下的bin/bash是否可执行。如果报Permission denied用chmod x加上执行权限。另一个常见问题是内核不支持用户命名空间。运行FEXBash时如果报unshare failed说明内核的CONFIG_USER_NS没开。解决办法是重新编译内核或者换一个支持的内核版本。5.3 DXMT 图形问题的排查DXMT 跑游戏时如果黑屏或者花屏先检查 Vulkan 驱动是否正常。运行vulkaninfo | grep GPU看看能不能识别到显卡。如果识别不到说明 Vulkan 驱动没装好。在 Mali GPU 上需要安装libmali-valhall-g610-g6p0-x11这样的专有驱动包。如果 Vulkan 正常但游戏还是黑屏尝试设置DXMT_LOG_LEVELdebug查看日志输出。常见的错误是vkCreateDevice failed这通常是 Vulkan 驱动版本太老升级驱动即可。实操心得DXMT 对显卡驱动的版本很敏感。我有一次升级了 Mesa 驱动结果 DXMT 直接崩溃。后来回退到之前的版本才恢复正常。所以如果你跑通了某个配置建议把驱动版本锁定不要随便升级。5.4 性能调优的独家技巧经过几个月的折腾我总结了几条性能调优的经验第一FEX-Emu 的代码缓存目录要放在 SSD 上。默认情况下FEX-Emu 会把翻译后的代码缓存到~/.cache/fex-emu如果这个目录在机械硬盘上加载速度会慢很多。我把它软链接到了 NVMe 分区启动速度提升了将近一倍。第二Wine 的wineserver进程可以设置 CPU 亲和性。在多核 ARM 设备上把wineserver绑定到大核上能明显减少卡顿taskset -cp 4-7 $(pgrep wineserver)第三DXMT 的着色器缓存要开启。在~/.wine/drive_c/windows/system32/dxmt.conf里加上shader_cache true第二次运行游戏时加载速度会快很多。6. 跨平台兼容的边界与后续扩展思路Madeira 这套方案虽然强大但也不是万能的。我实测下来以下几类应用基本跑不起来一是依赖内核级驱动的软件比如某些杀毒软件和虚拟化工具二是使用反作弊系统的游戏因为反作弊会检测运行环境三是依赖 .NET Framework 4.8 以上版本的应用Wine 的 .NET 支持还不完善。如果你需要跑 .NET 应用可以尝试安装dotnet48winetricks dotnet48但这个过程非常漫长而且经常失败。我的建议是如果 .NET 应用是刚需还是老老实实用虚拟机。后续扩展方面Madeira 的架构其实可以支持更多场景。比如你可以把 FEX-Emu 单独拿出来在 ARM 上跑 x86-64 的 Linux 二进制程序不需要 Wine。我就用这种方式在 RK3588 上跑了一个 x86-64 的 Docker 镜像虽然性能有损耗但至少能跑起来。另外DXMT 的 Vulkan 转译层也可以单独用于其他场景比如在 ARM 上跑 Vulkan 应用时通过 DXMT 做一层中间转换。不过这个用法比较小众感兴趣的话可以自己研究。最后分享一个小技巧如果你在 Madeira 上跑某个应用时遇到奇怪的崩溃先试试把FEX_TSOENABLED关掉再把WINE_CPU_TOPOLOGY设置为1:1也就是模拟单核 CPU。很多兼容性问题都是多线程引起的单核模式下反而更稳定。这个技巧帮我解决了好几个疑难杂症你可以试试。