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_TSOENABLED=1和FEX_ROOTFS相关的优化选项,具体参数后面会细说。
还有一个关键点:FEX-Emu 需要配合一个 RootFS 使用。这个 RootFS 本质上是一个精简的 x86-64 Linux 文件系统,里面包含了 Wine 运行所需的库和二进制文件。Madeira 项目通常会提供一个预构建的 RootFS 包,但如果你要自己定制,就得用debootstrap或者mmdebstrap手动构建一个 x86-64 的 Debian 根文件系统,然后再把 Wine 装进去。这个过程比较繁琐,新手建议直接用现成的。
2.2 Wine:Windows 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. 环境搭建实操:从零开始配置 Madeira
3.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-Emu
FEX-Emu 的编译过程比较耗时,在 RK3588 上大概要 40 分钟。首先克隆源码:
git clone https://github.com/FEX-Emu/FEX.git cd FEX git submodule update --init --recursive然后配置编译选项。这里有个关键点:-DENABLE_LTO=ON可以开启链接时优化,能提升 10%-15% 的性能,但编译时间会更长。如果你赶时间,可以先关掉。
mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release \ -DENABLE_LTO=ON \ -DENABLE_ASSERTIONS=OFF \ -DCMAKE_INSTALL_PREFIX=/usr/local \ .. make -j$(nproc) sudo make install编译完成后,你需要准备一个 RootFS。Madeira 项目通常会提供一个打包好的 RootFS 压缩包,解压到/opt/fex-rootfs即可。如果没有现成的,可以用mmdebstrap自己构建:
sudo mmdebstrap --arch=amd64 bullseye /opt/fex-rootfs \ "deb http://deb.debian.org/debian bullseye main contrib non-free"构建完成后,进入 RootFS 安装 Wine:
sudo 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 的 Shell:
FEXBash winecfgwinecfg会弹出图形界面,如果没弹出来,检查一下DISPLAY环境变量是否设置正确。在配置界面里,把 Windows 版本设置为 Windows 10,图形驱动选 Vulkan(如果 DXMT 已经装好)。
字体乱码的修复,我推荐用winetricks:
winetricks 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_ENABLE=1 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/ttyUSB0:
wine 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 内存模型,提升多线程性能 | 1 |
FEX_ROOTFS | 指定 RootFS 路径 | /opt/fex-rootfs |
DXMT_FRAME_RATE | 限制帧率,降低 CPU 占用 | 60 |
WINE_CPU_TOPOLOGY | 模拟 CPU 核心数 | 4:4 |
注意:
FEX_TSOENABLED=1虽然能提升性能,但在某些应用下会导致崩溃。如果遇到随机崩溃,先把这个参数关掉试试。
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 编码 | 设置LANG=zh_CN.UTF-8 |
5.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_LEVEL=debug,查看日志输出。常见的错误是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 应用,可以尝试安装dotnet48:
winetricks 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。很多兼容性问题都是多线程引起的,单核模式下反而更稳定。这个技巧帮我解决了好几个疑难杂症,你可以试试。