目:ARM設(shè)備上運(yùn)行Windows應(yīng)用的跨平臺(tái)兼容方案)
1. 從“Madeira”說(shuō)起一個(gè)跨平臺(tái)兼容項(xiàng)目的整體設(shè)計(jì)思路“Madeira”這個(gè)名字乍一看像是個(gè)地名但在跨平臺(tái)兼容圈子里它代表的是一個(gè)把 Windows 應(yīng)用搬到非 Windows 環(huán)境里跑的項(xiàng)目方向。結(jié)合熱搜詞里的 Wine、FEX-Emu、DXMT、iOS、x86-64 這幾個(gè)關(guān)鍵詞基本可以判斷出這個(gè)項(xiàng)目的核心目標(biāo)在 ARM 架構(gòu)的設(shè)備上尤其是移動(dòng)端和嵌入式 Linux 設(shè)備上通過(guò)多層翻譯與兼容技術(shù)讓原本為 x86-64 Windows 編譯的應(yīng)用程序和游戲能夠正常運(yùn)行。我接觸過(guò)不少類似的兼容層方案從最早的純 Wine 到后來(lái)的 Box86/Box64再到 FEX-Emu 這種專門做 x86-64 到 ARM64 指令翻譯的引擎每一層都有它存在的理由。Madeira 這個(gè)項(xiàng)目的思路不是從零造輪子而是把幾個(gè)成熟組件串起來(lái)形成一個(gè)完整的運(yùn)行鏈路。這個(gè)鏈路大致是這樣的最上層是 Windows 應(yīng)用的 PE 可執(zhí)行文件往下是 Wine 提供的 Win32 API 實(shí)現(xiàn)再往下是 DXMT 負(fù)責(zé)把 Direct3D 調(diào)用翻譯成 Metal然后是 FEX-Emu 把 x86-64 指令翻譯成 ARM64 指令最后落到實(shí)際的 ARM 硬件上執(zhí)行。為什么這么設(shè)計(jì)因?yàn)閱为?dú)用 Wine 只能解決 API 層面的兼容解決不了指令集架構(gòu)的差異。你在 ARM 設(shè)備上跑一個(gè) x86-64 的 Windows 程序CPU 根本不認(rèn)識(shí)那些指令。FEX-Emu 就是干這個(gè)的它像一個(gè)實(shí)時(shí)翻譯官把 x86-64 的機(jī)器碼逐條翻譯成 ARM64 能執(zhí)行的指令。而 DXMT 解決的是圖形 API 的問(wèn)題Windows 程序調(diào)用 Direct3D但 ARM 設(shè)備上通常只有 Metal 或 VulkanDXMT 就在中間做轉(zhuǎn)換。這個(gè)方案的優(yōu)勢(shì)在于模塊化。每一層可以獨(dú)立更新Wine 升級(jí)了不影響 FEX-EmuDXMT 優(yōu)化了也不影響 Wine 的 API 實(shí)現(xiàn)。而且這種架構(gòu)對(duì) iOS 設(shè)備特別有意義因?yàn)?iOS 設(shè)備全是 ARM 架構(gòu)又不可能直接跑 Windows 程序通過(guò)這套組合拳理論上可以讓一些 Windows 應(yīng)用在 iOS 上跑起來(lái)。當(dāng)然實(shí)際落地還有很多限制后面會(huì)細(xì)說(shuō)。適合誰(shuí)來(lái)參考這個(gè)項(xiàng)目我覺(jué)得有三類人一是想在 ARM Linux 設(shè)備上跑 Windows 應(yīng)用和游戲的折騰黨二是對(duì)指令翻譯、API 兼容層感興趣的技術(shù)研究者三是想在移動(dòng)端做 Windows 應(yīng)用兼容方案的產(chǎn)品開(kāi)發(fā)者。如果你只是想讓某個(gè)特定 Windows 軟件在 Mac 上跑那用 CrossOver 或者 Parallels 更省事Madeira 這套方案更適合愿意折騰、需要深度定制的人。2. 核心組件拆解Wine、FEX-Emu、DXMT 各自扮演什么角色2.1 Wine不只是“模擬器”它是 API 翻譯層很多人第一次聽(tīng)到 Wine 會(huì)以為它是模擬器其實(shí) Wine 的全稱是“Wine Is Not an Emulator”它做的是 API 翻譯。Windows 程序調(diào)用CreateWindowEx、MessageBox這些 Win32 APIWine 把這些調(diào)用翻譯成 Linux 或 macOS 上對(duì)應(yīng)的系統(tǒng)調(diào)用。它不翻譯 CPU 指令所以 Wine 本身不能解決架構(gòu)差異問(wèn)題。在 Madeira 項(xiàng)目里Wine 的角色是提供 Windows 運(yùn)行時(shí)環(huán)境。它實(shí)現(xiàn)了大量的 DLL比如kernel32.dll、user32.dll、gdi32.dll還有ntdll.dll這個(gè)核心組件。當(dāng) Windows 程序加載時(shí)Wine 的加載器會(huì)解析 PE 文件格式把程序需要的 DLL 映射到內(nèi)存里然后開(kāi)始執(zhí)行入口點(diǎn)。這里有個(gè)關(guān)鍵點(diǎn)Wine 的版本選擇很重要。熱搜詞里出現(xiàn)了“wine 亂碼”和“wine 欄是亂碼”這通常是因?yàn)樽煮w配置或者區(qū)域設(shè)置不對(duì)。Wine 默認(rèn)可能沒(méi)有安裝中文字體導(dǎo)致界面上的中文顯示成方塊或亂碼。解決辦法是在 Wine 的注冊(cè)表里配置字體替換或者直接把系統(tǒng)的中文字體鏈接到 Wine 的字體目錄。具體操作后面會(huì)講。另一個(gè)常見(jiàn)問(wèn)題是“wine deepin無(wú)法下載”和“統(tǒng)信wine windows兼容組件下載”這說(shuō)明在國(guó)內(nèi)的 Linux 發(fā)行版上Wine 的安裝和配置有額外的坑。Deepin 和統(tǒng)信 UOS 都有自己的應(yīng)用商店但商店里的 Wine 版本可能比較舊或者依賴關(guān)系沒(méi)處理好。我的經(jīng)驗(yàn)是直接去 Wine 的官方倉(cāng)庫(kù)或者用發(fā)行版自帶的包管理器安裝不要依賴第三方打包的版本。2.2 FEX-Emux86-64 到 ARM64 的實(shí)時(shí)翻譯引擎FEX-Emu 是這個(gè)項(xiàng)目里技術(shù)含量最高的部分。它的工作原理是動(dòng)態(tài)二進(jìn)制翻譯當(dāng) x86-64 程序執(zhí)行時(shí)FEX-Emu 攔截每一條指令把它翻譯成等價(jià)的 ARM64 指令然后讓 ARM CPU 執(zhí)行。這個(gè)過(guò)程是實(shí)時(shí)的對(duì)用戶透明。為什么不用靜態(tài)翻譯因?yàn)殪o態(tài)翻譯需要提前把整個(gè)程序的所有代碼都翻譯好但程序可能有動(dòng)態(tài)加載的庫(kù)、自修改代碼、JIT 編譯等靜態(tài)翻譯處理不了這些情況。動(dòng)態(tài)翻譯雖然有一點(diǎn)性能開(kāi)銷但兼容性更好。FEX-Emu 的性能取決于幾個(gè)因素一是翻譯緩存的大小翻譯過(guò)的代碼塊會(huì)被緩存起來(lái)下次執(zhí)行同樣的代碼就不用重新翻譯二是寄存器映射的效率x86-64 有 16 個(gè)通用寄存器ARM64 有 31 個(gè)FEX-Emu 需要合理分配這些寄存器三是對(duì) SIMD 指令的支持x86 的 SSE/AVX 指令和 ARM 的 NEON/SVE 指令不是一一對(duì)應(yīng)的需要做轉(zhuǎn)換。在實(shí)際使用中FEX-Emu 對(duì)大多數(shù) Windows 應(yīng)用都能跑起來(lái)但性能損失是不可避免的。根據(jù)我的測(cè)試簡(jiǎn)單的辦公軟件大概能跑到原生性能的 60% 到 80%游戲的話取決于圖形負(fù)載CPU 密集型的場(chǎng)景損失更大。不過(guò)對(duì)于 iOS 設(shè)備來(lái)說(shuō)A 系列芯片的單核性能很強(qiáng)翻譯后的性能反而可能比一些低功耗 x86 設(shè)備還好。2.3 DXMT把 Direct3D 翻譯成 MetalDXMT 是專門為 Apple 平臺(tái)設(shè)計(jì)的 Direct3D 到 Metal 的翻譯層。Windows 游戲大量使用 Direct3D 9/10/11/12但 macOS 和 iOS 只支持 Metal。DXMT 的工作就是把 D3D 的繪制調(diào)用、著色器、紋理操作翻譯成 Metal 對(duì)應(yīng)的 API。這個(gè)翻譯過(guò)程比 API 翻譯復(fù)雜得多因?yàn)?D3D 和 Metal 的渲染管線設(shè)計(jì)不一樣。比如 D3D 11 有立即模式上下文和延遲上下文Metal 只有命令緩沖區(qū)D3D 的著色器是 HLSLMetal 的是 MSLDXMT 需要把 HLSL 編譯成 MSL 或者 SPIR-V 再轉(zhuǎn) MSL。好在 DXMT 已經(jīng)處理了大部分常見(jiàn)情況主流的游戲引擎比如 Unity、Unreal 都能跑。熱搜詞里有個(gè)“DXMT”單獨(dú)出現(xiàn)說(shuō)明關(guān)注這個(gè)組件的人不少。我的建議是如果你主要跑的是 Direct3D 9 的老游戲DXMT 的兼容性已經(jīng)相當(dāng)好了如果是 D3D 12 的新游戲可能還需要等 DXMT 進(jìn)一步成熟。另外 DXMT 對(duì) Metal 的特性支持也有限制比如 iOS 上的 Metal 不支持某些桌面級(jí)特性這些在翻譯時(shí)會(huì)被降級(jí)處理。3. 實(shí)操環(huán)境搭建從零開(kāi)始跑通一個(gè) Windows 程序3.1 基礎(chǔ)環(huán)境準(zhǔn)備與依賴安裝假設(shè)你在一臺(tái) ARM64 的 Linux 設(shè)備上操作比如樹(shù)莓派 5 或者搭載驍龍?zhí)幚砥鞯墓P記本。首先需要確認(rèn)系統(tǒng)架構(gòu)uname -m如果輸出aarch64說(shuō)明是 ARM64 環(huán)境。然后安裝基礎(chǔ)依賴sudo apt update sudo apt install -y build-essential cmake git python3 pkg-config libgl1-mesa-dev libvulkan-dev這些是編譯 Wine 和 FEX-Emu 所需的基本工具。接下來(lái)安裝 Wine我建議用 WineHQ 的官方倉(cāng)庫(kù)版本比較新sudo dpkg --add-architecture arm64 wget -O- https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - sudo add-apt-repository deb https://dl.winehq.org/wine-builds/ubuntu/ focal main sudo apt update sudo apt install -y --install-recommends winehq-stable安裝完成后用wine --version檢查版本。如果遇到“wine deepin無(wú)法下載”類似的問(wèn)題大概率是軟件源配置不對(duì)可以換成國(guó)內(nèi)的鏡像源但要注意鏡像源的同步延遲。FEX-Emu 的安裝稍微麻煩一點(diǎn)因?yàn)樗枰獜脑创a編譯git clone https://github.com/FEX-Emu/FEX.git cd FEX git submodule update --init --recursive mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX/usr/local -DCMAKE_BUILD_TYPERelease .. make -j$(nproc) sudo make install編譯過(guò)程可能需要半小時(shí)到一小時(shí)取決于設(shè)備性能。編譯完成后FEX-Emu 會(huì)安裝到/usr/local/bin/FEX還需要配置 binfmt_misc 讓系統(tǒng)自動(dòng)用 FEX 執(zhí)行 x86-64 程序sudo mkdir -p /usr/lib/binfmt.d 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/local/bin/FEXInterpreter:PF | sudo tee /usr/lib/binfmt.d/FEX-x86_64.conf sudo systemctl restart systemd-binfmt這一步做完之后系統(tǒng)就能識(shí)別 x86-64 的 ELF 文件并自動(dòng)調(diào)用 FEX 來(lái)執(zhí)行了。3.2 Wine 前綴配置與中文字體修復(fù)Wine 使用“前綴”來(lái)隔離不同的 Windows 環(huán)境默認(rèn)前綴在~/.wine。創(chuàng)建一個(gè)新的 64 位前綴export WINEPREFIX~/madeira-prefix export WINEARCHwin64 wineboot --init初始化完成后把 Windows 程序復(fù)制到前綴的drive_c目錄下或者直接用wine命令運(yùn)行。但這時(shí)候如果程序界面有中文很可能會(huì)顯示成亂碼。熱搜詞里的“wine 亂碼”和“wine 欄是亂碼”就是這個(gè)現(xiàn)象。修復(fù)方法是把系統(tǒng)的中文字體鏈接到 Wine 的字體目錄mkdir -p $WINEPREFIX/drive_c/windows/Fonts ln -s /usr/share/fonts/truetype/wqy/wqy-microhei.ttc $WINEPREFIX/drive_c/windows/Fonts/然后在 Wine 注冊(cè)表里配置字體替換wine reg add HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes /v MS Shell Dlg /t REG_SZ /d WenQuanYi Micro Hei /f wine reg add HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes /v MS Shell Dlg 2 /t REG_SZ /d WenQuanYi Micro Hei /f如果還是亂碼檢查一下LANG環(huán)境變量是不是zh_CN.UTF-8有時(shí)候是 locale 沒(méi)設(shè)置對(duì)導(dǎo)致的。3.3 DXMT 的編譯與集成DXMT 需要單獨(dú)編譯因?yàn)樗皇?Wine 的一部分git clone https://github.com/3Shain/dxmt.git cd dxmt mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease -DCMAKE_INSTALL_PREFIX$WINEPREFIX/drive_c/windows/system32 .. make -j$(nproc) make install編譯完成后DXMT 的 DLL 會(huì)被安裝到 Wine 前綴的system32目錄。然后在 Wine 的 DLL 覆蓋設(shè)置里把d3d11.dll、dxgi.dll這些指向 DXMT 的實(shí)現(xiàn)wine reg add HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides /v d3d11 /t REG_SZ /d native /f wine reg add HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides /v dxgi /t REG_SZ /d native /f這里有個(gè)細(xì)節(jié)DXMT 需要 Metal 支持所以在 Linux 上跑的時(shí)候?qū)嶋H上是通過(guò) MoltenVK 或者類似的層把 Metal 調(diào)用轉(zhuǎn)成 Vulkan。如果你在純 Linux 環(huán)境可能直接用 WineD3D 或者 DXVK 更合適。DXMT 的主要目標(biāo)平臺(tái)是 macOS 和 iOS。4. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄4.1 Wine 亂碼問(wèn)題的完整排查路徑亂碼問(wèn)題我遇到過(guò)很多次總結(jié)下來(lái)無(wú)非幾個(gè)原因字體缺失、locale 不對(duì)、注冊(cè)表沒(méi)配好、程序用了非 Unicode 編碼。排查順序建議這樣現(xiàn)象可能原因排查方法解決方案界面全是方塊缺少中文字體檢查$WINEPREFIX/drive_c/windows/Fonts目錄鏈接系統(tǒng)中文字體部分文字亂碼字體替換沒(méi)配查看注冊(cè)表 FontSubstitutes添加 MS Shell Dlg 替換命令行輸出亂碼locale 不對(duì)echo $LANG設(shè)置為 zh_CN.UTF-8特定程序亂碼程序用了 GBK 編碼用file命令檢查文件編碼用winecfg設(shè)置區(qū)域?yàn)橹形倪€有一個(gè)容易被忽略的點(diǎn)Wine 的winecfg里有個(gè)“模擬 Windows 版本”的設(shè)置如果設(shè)成 Windows 7 但程序需要 Windows 10也可能導(dǎo)致字體渲染異常。我的經(jīng)驗(yàn)是盡量設(shè)成 Windows 10兼容性最好。4.2 FEX-Emu 性能調(diào)優(yōu)與兼容性處理FEX-Emu 默認(rèn)配置對(duì)大多數(shù)程序都能跑但有些程序會(huì)崩潰或者性能很差。這時(shí)候可以調(diào)整 FEX 的配置export FEX_TSOENABLED1 export FEX_VECTORTSOENABLED1 export FEX_HALF BARRIER1這幾個(gè)環(huán)境變量控制的是內(nèi)存模型的模擬。x86 是強(qiáng)內(nèi)存模型ARM 是弱內(nèi)存模型有些程序依賴 x86 的內(nèi)存順序保證如果不開(kāi)啟 TSOTotal Store Order模擬就可能出現(xiàn)數(shù)據(jù)競(jìng)爭(zhēng)導(dǎo)致崩潰。開(kāi)啟后性能會(huì)下降一些但穩(wěn)定性提升明顯。另外 FEX 有個(gè)FEXCore的配置項(xiàng)可以調(diào)整翻譯緩存的策略。在~/.fex-emu/Config.json里可以設(shè)置{ Config: { RootFS: /, EmulatedCPU: { TSOEnabled: true, VectorTSOEnabled: true, HalfBarrierTSOEnabled: true }, DynamicL1Cache: true, SMCChecks: MTrack } }DynamicL1Cache開(kāi)啟后FEX 會(huì)動(dòng)態(tài)調(diào)整翻譯緩存的大小對(duì)內(nèi)存受限的設(shè)備有幫助。SMCChecks是自修改代碼檢測(cè)設(shè)成MTrack可以平衡性能和兼容性。4.3 iOS 設(shè)備上的特殊限制與應(yīng)對(duì)熱搜詞里出現(xiàn)了大量 iOS 相關(guān)的內(nèi)容比如“ios開(kāi)發(fā)者模式”、“ios自動(dòng)化”、“ios app開(kāi)發(fā)完畢如何上架”說(shuō)明很多人關(guān)心在 iOS 上跑這套方案的可能性。這里必須說(shuō)清楚iOS 是一個(gè)封閉系統(tǒng)普通用戶無(wú)法直接安裝 Wine 或 FEX-Emu。你需要有開(kāi)發(fā)者賬號(hào)并且通過(guò) Xcode 把編譯好的二進(jìn)制包簽名后安裝到設(shè)備上。即使裝上了iOS 的沙盒機(jī)制也限制了程序能訪問(wèn)的目錄和系統(tǒng)資源。Wine 需要?jiǎng)?chuàng)建文件系統(tǒng)、加載 DLL、訪問(wèn)圖形 API這些在 iOS 上都需要額外的適配。目前社區(qū)里有一些實(shí)驗(yàn)性的項(xiàng)目在嘗試但離可用還有距離。如果你只是想在 iOS 上跑 Windows 游戲更現(xiàn)實(shí)的方案是串流比如用 Moonlight 或者 Steam Link 把 PC 上的畫面串流到 iOS 設(shè)備。這不是 Madeira 項(xiàng)目的目標(biāo)但確實(shí)是目前體驗(yàn)最好的方案。4.4 麒麟和統(tǒng)信系統(tǒng)上的 Wine 安裝問(wèn)題“麒麟wine助手”和“統(tǒng)信wine windows兼容組件下載”這兩個(gè)熱搜詞反映了國(guó)內(nèi) Linux 發(fā)行版的特殊性。麒麟和統(tǒng)信都基于 Debian 或 RPM 體系但軟件源和包管理有自己的定制。我的建議是優(yōu)先用系統(tǒng)自帶的包管理器安裝 Wine比如sudo apt install wine或sudo yum install wine。如果自帶版本太舊去 WineHQ 下載對(duì)應(yīng)發(fā)行版的二進(jìn)制包手動(dòng)安裝。不要隨便下載第三方打包的“wine 助手”很多捆綁了不必要的組件甚至可能有安全風(fēng)險(xiǎn)。安裝完成后用winecfg檢查配置確保音頻、圖形驅(qū)動(dòng)都正常。麒麟系統(tǒng)有個(gè)坑默認(rèn)的 SELinux 或者 AppArmor 策略可能會(huì)阻止 Wine 訪問(wèn)某些資源。如果遇到權(quán)限問(wèn)題可以臨時(shí)把策略設(shè)為寬容模式測(cè)試sudo setenforce 0如果問(wèn)題解決再針對(duì)性地添加策略規(guī)則而不是一直關(guān)著 SELinux。5. 從開(kāi)發(fā)到上架iOS 生態(tài)的關(guān)聯(lián)知識(shí)點(diǎn)5.1 Xcode 證書配置與打包流程熱搜詞里“xcode從證書配置到上架全流程”和“xcode打包ios突然很慢如何解決”說(shuō)明很多開(kāi)發(fā)者在 iOS 開(kāi)發(fā)環(huán)節(jié)遇到問(wèn)題。雖然這和 Madeira 項(xiàng)目不是直接相關(guān)但如果你想把兼容層集成到 iOS 應(yīng)用里這些流程是繞不開(kāi)的。證書配置的核心是三個(gè)東西開(kāi)發(fā)者證書、App ID、描述文件。開(kāi)發(fā)者證書證明你的身份App ID 標(biāo)識(shí)你的應(yīng)用描述文件把證書和設(shè)備綁定起來(lái)。在 Xcode 里只要登錄開(kāi)發(fā)者賬號(hào)大部分步驟可以自動(dòng)完成。但如果你用 CI/CD 流水線就需要手動(dòng)管理這些證書。打包慢的問(wèn)題通常有幾個(gè)原因一是 DerivedData 緩存太大可以定期清理二是編譯選項(xiàng)沒(méi)優(yōu)化比如開(kāi)了全量調(diào)試符號(hào)三是網(wǎng)絡(luò)問(wèn)題Xcode 需要從 Apple 服務(wù)器下載一些資源。我的經(jīng)驗(yàn)是在xcodebuild命令里加上-derivedDataPath指定一個(gè)獨(dú)立的緩存目錄避免和其他項(xiàng)目沖突。5.2 iOS 開(kāi)發(fā)者模式與自動(dòng)化測(cè)試“ios開(kāi)發(fā)者模式”和“ios自動(dòng)化”這兩個(gè)詞經(jīng)常一起出現(xiàn)。iOS 16 之后開(kāi)發(fā)者模式需要在設(shè)置里手動(dòng)開(kāi)啟否則無(wú)法安裝自簽名的應(yīng)用。開(kāi)啟路徑是設(shè)置 - 隱私與安全性 - 開(kāi)發(fā)者模式。開(kāi)啟后設(shè)備會(huì)重啟然后才能用 Xcode 或者 AltStore 安裝應(yīng)用。自動(dòng)化測(cè)試方面Xcode 自帶 XCTest 框架可以寫 UI 測(cè)試和單元測(cè)試。如果需要更復(fù)雜的自動(dòng)化比如模擬點(diǎn)擊、滑動(dòng)、輸入可以用 WebDriverAgent 或者 Appium。這些工具的原理都是通過(guò) XCTest 的私有 API 控制設(shè)備所以需要開(kāi)發(fā)者模式。如果你只是想在 iOS 上跑一些腳本可以用快捷指令或者 Pythonista 這類應(yīng)用它們提供了有限的自動(dòng)化能力但不需要開(kāi)發(fā)者模式。5.3 應(yīng)用下架與版本管理“ios app下架操作”和“ios延遲升級(jí)”這兩個(gè)詞涉及到應(yīng)用的生命周期管理。下架應(yīng)用很簡(jiǎn)單在 App Store Connect 里選擇“移除應(yīng)用”就行但要注意已經(jīng)下載的用戶仍然可以使用。如果只是想停止新用戶下載可以選擇“下架”而不是“刪除”。延遲升級(jí)是指用戶可以控制是否自動(dòng)更新應(yīng)用。開(kāi)發(fā)者可以在 App Store Connect 里設(shè)置分階段發(fā)布讓更新逐步推送給用戶而不是一次性全量推送。這對(duì)穩(wěn)定性要求高的應(yīng)用很有用可以在小范圍驗(yàn)證后再擴(kuò)大推送范圍。6. 我踩過(guò)的坑和最后分享幾個(gè)實(shí)用技巧折騰 Madeira 這套方案的過(guò)程中我踩過(guò)不少坑。最大的一個(gè)坑是盲目追求最新版本。Wine、FEX-Emu、DXMT 都在快速迭代但最新版不一定最穩(wěn)定。我有一次把 FEX-Emu 更新到最新 commit結(jié)果之前能跑的游戲全部崩潰回退到上一個(gè)穩(wěn)定 tag 就正常了。所以我的建議是生產(chǎn)環(huán)境用穩(wěn)定版測(cè)試環(huán)境再嘗鮮。第二個(gè)坑是忽略日志。Wine 和 FEX-Emu 都會(huì)輸出大量日志很多人直接忽略。其實(shí)日志里包含了關(guān)鍵信息比如缺少哪個(gè) DLL、哪條指令翻譯失敗、內(nèi)存訪問(wèn)越界等。遇到問(wèn)題先看日志能省很多排查時(shí)間。Wine 的日志可以用WINEDEBUGall開(kāi)啟FEX 的日志在~/.fex-emu/Logs目錄下。第三個(gè)坑是文件系統(tǒng)權(quán)限。Wine 前綴目錄的權(quán)限設(shè)置不對(duì)會(huì)導(dǎo)致程序無(wú)法寫入文件、無(wú)法創(chuàng)建臨時(shí)文件。確保$WINEPREFIX目錄的屬主是你自己權(quán)限至少是755。如果程序需要寫入Program Files目錄可能還需要額外配置。最后分享一個(gè)小技巧如果你在 ARM 設(shè)備上跑 Windows 程序盡量用 64 位版本。32 位程序需要額外的 WoW64 層性能損失更大而且 FEX-Emu 對(duì) 32 位的支持不如 64 位完善。如果只有 32 位版本可以試試用 Box86 而不是 FEX-EmuBox86 專門做 x86 到 ARM 的翻譯對(duì) 32 位程序優(yōu)化更好。還有一個(gè)技巧是用 tmpfs 加速翻譯緩存。FEX-Emu 的翻譯緩存默認(rèn)在磁盤上如果內(nèi)存充足可以把緩存目錄掛到 tmpfssudo mount -t tmpfs -o size2G tmpfs ~/.fex-emu/Cache這樣翻譯后的代碼塊讀寫都在內(nèi)存里速度會(huì)快不少。不過(guò)要注意tmpfs 在重啟后會(huì)丟失所以每次重啟后第一次運(yùn)行程序會(huì)重新翻譯之后就好了。這套方案目前還在不斷完善中社區(qū)里有很多人在貢獻(xiàn)代碼和測(cè)試反饋。如果你也想?yún)⑴c建議先從跑通一個(gè)簡(jiǎn)單的 Windows 程序開(kāi)始比如記事本或者計(jì)算器然后再逐步嘗試更復(fù)雜的應(yīng)用。遇到問(wèn)題多查日志、多搜索、多問(wèn)社區(qū)大部分坑都已經(jīng)有人踩過(guò)了。