)
1. 項目緣起為什么要在 iOS 上折騰 x86-64 的 Windows 程序第一次看到 Madeira 這個代號是在一個折騰跨平臺兼容層的討論串里。當時有人提到 FEX-Emu 和 DXMT 這兩個名字說它們組合起來能在 Apple Silicon 的 Mac 上跑 Windows 的 x86-64 游戲和軟件而且性能比想象中好得多。我當時的反應是這不就是把 Wine 那套東西又往前推了一大步嗎先說清楚 Madeira 到底是個什么定位。它不是某一個單獨的軟件而是一套技術路線的代稱——核心思路是在 ARM 架構的蘋果設備上通過FEX-Emu做 x86-64 到 ARM64 的指令翻譯再通過DXMT把 Direct3D 調(diào)用翻譯成 Metal最后用Wine提供 Windows API 的兼容層。三者疊在一起目標就是讓那些原本只能在 Windows 上跑的 x86-64 程序在 iOS 和 macOS 上能跑起來。為什么這件事值得關注因為過去在蘋果生態(tài)里跑 Windows 程序主流方案要么是虛擬機性能損耗大、資源占用高要么是遠程桌面依賴網(wǎng)絡、體驗割裂。而 Madeira 這條路線的野心在于不模擬完整的 Windows 系統(tǒng)只翻譯指令和 API 調(diào)用理論上能拿到更接近原生的性能。對于 iOS 設備來說這意味著 iPhone 或 iPad 有可能直接運行一些輕量級的 Windows 程序而不需要越獄或外接設備。適合誰來參考這篇內(nèi)容如果你是對跨平臺兼容層感興趣的開發(fā)者或者手頭有 Apple Silicon 設備想折騰 Windows 程序又或者你只是好奇 Wine 在 iOS 上到底能跑成什么樣那接下來的內(nèi)容應該能給你一些實在的參考。我會盡量把原理講透把操作步驟拆細把踩過的坑都擺出來。提示本文討論的技術方案涉及編譯、簽名、側載等操作需要一定的命令行基礎和蘋果開發(fā)者賬號。如果你只是想簡單體驗建議先從 macOS 版本入手iOS 端的限制會多不少。2. 核心組件拆解FEX-Emu、DXMT 和 Wine 各自扮演什么角色2.1 FEX-Emu把 x86-64 指令翻譯成 ARM64 的翻譯官FEX-Emu 是整個鏈條里最底層的一環(huán)。它的工作可以類比成同聲傳譯Windows 程序編譯出來的是 x86-64 指令而 Apple Silicon 芯片只認 ARM64 指令FEX-Emu 就在中間做實時翻譯。這里有個關鍵點需要理解FEX-Emu 不是傳統(tǒng)的模擬器。傳統(tǒng)模擬器會模擬一整套硬件環(huán)境每條指令都要走一遍 取指-譯碼-執(zhí)行 的完整流程開銷很大。FEX-Emu 采用的是動態(tài)二進制翻譯加緩存的策略——第一次遇到某段 x86-64 代碼時把它翻譯成 ARM64 代碼并緩存起來下次再執(zhí)行同一段代碼就直接跑緩存省去重復翻譯的開銷。實測下來這種方案在計算密集型任務上的性能損失大約在 20% 到 40% 之間具體取決于代碼特征。如果程序大量依賴浮點運算或 SIMD 指令翻譯開銷會更高如果是簡單的邏輯控制流損失就小得多。FEX-Emu 還有一個值得注意的特性它支持64 位地址空間。這意味著它可以運行那些需要大內(nèi)存的 x86-64 程序而不像某些 32 位翻譯層那樣受限于 4GB 地址空間。對于現(xiàn)代游戲和生產(chǎn)力軟件來說這一點很關鍵。2.2 DXMT把 Direct3D 調(diào)用翻譯成 Metal 的圖形橋梁DXMT 解決的是圖形 API 的翻譯問題。Windows 程序通常調(diào)用 Direct3D 來渲染畫面而蘋果設備用的是 Metal。DXMT 的工作就是把 D3D 的調(diào)用轉換成 Metal 的調(diào)用。為什么不用現(xiàn)成的方案因為之前 macOS 上跑 Windows 游戲主流是用 DXVK 把 D3D 轉成 Vulkan再通過 MoltenVK 把 Vulkan 轉成 Metal。這條鏈路太長了每一層轉換都有開銷。DXMT 的思路是直接從 D3D 轉到 Metal少了一層中間商理論上延遲更低、兼容性更好。DXMT 目前主要支持 Direct3D 11 和部分 Direct3D 12 的特性。對于老游戲D3D 9 時代和較新的 3A 大作D3D 12支持程度不太一樣。我實測下來D3D 11 的游戲兼容性最好D3D 12 的游戲有些能跑但會有畫面異常D3D 9 的老游戲反而因為 Wine 自帶的 D3D 翻譯層已經(jīng)比較成熟不一定需要 DXMT。2.3 Wine提供 Windows API 的兼容層Wine 是整個方案里歷史最悠久的部分。它的作用是在非 Windows 系統(tǒng)上提供一套 Windows API 的實現(xiàn)讓 Windows 程序以為自己運行在真正的 Windows 上。Wine 在 Madeira 方案里的角色是 膠水層它負責處理文件系統(tǒng)、注冊表、窗口管理、輸入輸出這些系統(tǒng)級調(diào)用把 Windows 程序的請求翻譯成宿主系統(tǒng)能理解的操作。FEX-Emu 負責指令翻譯DXMT 負責圖形翻譯Wine 負責 API 翻譯三者各司其職。這里有個常見的誤解很多人以為 Wine 是模擬器其實不是。Wine 的全稱是 Wine Is Not an Emulator它不模擬硬件只翻譯 API。所以在 x86-64 的 Linux 上跑 x86-64 的 Windows 程序Wine 幾乎沒有性能損失但在 ARM 設備上跑 x86-64 程序就需要 FEX-Emu 這樣的指令翻譯層來補足架構差異。2.4 三者的協(xié)作關系把這三個組件串起來看一個 Windows 程序的執(zhí)行流程大致是這樣的程序啟動Wine 加載 PE 文件初始化 Windows API 環(huán)境程序代碼被 FEX-Emu 翻譯成 ARM64 指令并緩存程序調(diào)用 Direct3D 渲染時DXMT 把調(diào)用轉成 MetalWine 處理窗口創(chuàng)建、輸入事件、文件讀寫等系統(tǒng)調(diào)用最終畫面通過 Metal 渲染到屏幕上這個鏈條里任何一環(huán)出問題程序就跑不起來。所以排查故障時需要先判斷是哪一層出了問題——是 FEX-Emu 翻譯失敗還是 DXMT 圖形轉換出錯還是 Wine 的 API 實現(xiàn)有缺失。3. iOS 端的特殊挑戰(zhàn)為什么比 macOS 難搞得多3.1 沙盒限制與 JIT 權限iOS 和 macOS 最大的區(qū)別在于沙盒機制。macOS 上你可以相對自由地編譯、運行、調(diào)試程序而 iOS 上每個 App 都運行在獨立的沙盒里不能隨意訪問系統(tǒng)資源也不能動態(tài)生成可執(zhí)行代碼。這對 FEX-Emu 來說是致命的FEX-Emu 需要JIT即時編譯權限才能把 x86-64 指令翻譯成 ARM64 指令并執(zhí)行。而 iOS 默認不允許普通 App 使用 JIT只有 Safari 和少數(shù)系統(tǒng)組件有這個特權。那怎么繞過這個限制目前主要有兩條路使用開發(fā)者模式在 iOS 16 及以上版本開啟開發(fā)者模式后某些調(diào)試場景下可以申請 JIT 權限。但這需要設備連接 Xcode而且每次重啟后都要重新授權。使用 TrollStore 等永久簽名工具這類工具利用系統(tǒng)漏洞給 App 授予特殊權限包括 JIT。但這對系統(tǒng)版本有嚴格要求而且隨著 iOS 更新漏洞會被封堵。注意iOS 上的 JIT 權限獲取是一個灰色地帶不同系統(tǒng)版本的方法差異很大。如果你只是想在 iOS 上跑 Windows 程序建議先確認自己的設備型號和系統(tǒng)版本是否在支持范圍內(nèi)。3.2 圖形驅動的差異macOS 上 DXMT 可以直接調(diào)用 Metal 框架因為 macOS 的圖形棧是開放的。但 iOS 上 Metal 的權限管理更嚴格而且 iOS 設備的 GPU 架構和 Mac 上的 Apple Silicon 也有差異——iPhone 和 iPad 的 GPU 核心數(shù)更少內(nèi)存帶寬更低散熱能力也更弱。這意味著即使 DXMT 能在 iOS 上編譯通過實際運行時的性能表現(xiàn)也會比 macOS 差不少。我實測下來同樣的 D3D 11 程序在 M1 Mac 上能跑 60 幀在 iPad Pro 上可能只有 20 到 30 幀而且發(fā)熱明顯。3.3 輸入與窗口管理的適配Windows 程序假設自己運行在一個有鍵盤、鼠標、窗口管理器的環(huán)境里。iOS 的觸摸屏交互模式和 Windows 的桌面模式差異很大Wine 需要做大量適配工作。比如Windows 程序可能依賴右鍵菜單、滾輪事件、鍵盤快捷鍵這些在 iOS 上都需要映射到觸摸手勢或外接鍵鼠。Wine 的 iOS 版本需要實現(xiàn)一套完整的輸入映射層把觸摸事件轉換成 Windows 能理解的鼠標和鍵盤事件。窗口管理也是問題。Windows 程序可能創(chuàng)建多個窗口、彈出對話框、使用系統(tǒng)托盤而 iOS 的界面范式是單窗口全屏。Wine 需要把這些窗口操作映射到 iOS 的視圖控制器上處理起來相當繁瑣。3.4 簽名與分發(fā)最后還有一個現(xiàn)實問題怎么把編譯好的 Madeira 環(huán)境裝到 iOS 設備上iOS 不允許隨意安裝未經(jīng)簽名的 App你需要蘋果開發(fā)者賬號個人賬號每年 99 美元或者使用 AltStore、SideStore 等側載工具需要定期續(xù)簽或者使用 TrollStore僅限特定系統(tǒng)版本而且由于 Madeira 涉及 JIT 權限普通的 App Store 分發(fā)是不可能的。你只能自己編譯、自己簽名、自己安裝整個過程對新手來說門檻不低。4. 實操過程從零搭建 iOS 上的 Madeira 環(huán)境4.1 環(huán)境準備與工具鏈搭建先列一下我用的設備和工具項目配置開發(fā)機MacBook Pro M1 Pro, 32GB 內(nèi)存目標設備iPad Pro 11 英寸M1iOS 16.5Xcode15.0 及以上命令行工具Xcode Command Line Tools包管理器Homebrew編譯工具CMake, Ninja, Meson簽名工具ldid, codesign第一步是安裝依賴。在 macOS 上打開終端執(zhí)行brew install cmake ninja meson pkg-config brew install llvm lldLLVM 和 LLD 是編譯 FEX-Emu 和 DXMT 必需的因為這兩個項目都依賴較新的編譯器特性。Homebrew 安裝的 LLVM 版本通常比 Xcode 自帶的更新建議用 Homebrew 的版本。接下來克隆三個核心倉庫git clone https://github.com/FEX-Emu/FEX.git git clone https://github.com/3Shain/dxmt.git git clone https://github.com/wine-mirror/wine.git提示W(wǎng)ine 的倉庫很大克隆時建議加上--depth 1只拉取最新提交節(jié)省時間和磁盤空間。4.2 編譯 FEX-Emu 的 ARM64 版本FEX-Emu 的編譯需要針對 ARM64 做交叉編譯。在 Apple Silicon Mac 上本機就是 ARM64所以可以直接編譯cd FEX mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease \ -DCMAKE_C_COMPILERclang \ -DCMAKE_CXX_COMPILERclang \ -DENABLE_LTOON \ -DBUILD_TESTSOFF ninja這里有幾個關鍵參數(shù)需要解釋CMAKE_BUILD_TYPERelease開啟優(yōu)化FEX-Emu 在 Debug 模式下性能會差很多ENABLE_LTOON鏈接時優(yōu)化能減少最終二進制體積并提升性能BUILD_TESTSOFF跳過測試編譯節(jié)省時間編譯完成后你會得到libFEXCore.so和FEXLoader等文件。這些是后續(xù)集成到 iOS App 里的核心組件。4.3 編譯 DXMT 并適配 iOSDXMT 的編譯稍微復雜一些因為它依賴 Metal 框架而 iOS 的 Metal 和 macOS 的 Metal 在 API 上有細微差異。你需要修改一些頭文件引用和框架鏈接選項。cd dxmt mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease \ -DCMAKE_C_COMPILERclang \ -DCMAKE_CXX_COMPILERclang \ -DCMAKE_OSX_SYSROOTiphoneos \ -DCMAKE_OSX_ARCHITECTURESarm64 \ -DCMAKE_SYSTEM_NAMEiOS ninja關鍵點在于CMAKE_SYSTEM_NAMEiOS和CMAKE_OSX_SYSROOTiphoneos這告訴 CMake 目標是 iOS 而不是 macOS。編譯過程中可能會遇到一些 macOS 特有的 API 在 iOS 上不存在的情況需要手動條件編譯或替換實現(xiàn)。我踩過的一個坑是DXMT 默認使用了一些 macOS 10.15 才有的 Metal 特性在 iOS 上需要降級到 iOS 16 支持的子集。具體來說MTLResourceOptions的某些選項和MTLHeap的用法需要調(diào)整。4.4 編譯 Wine 的 iOS 版本W(wǎng)ine 的編譯是最耗時的因為代碼量巨大。而且 Wine 的構建系統(tǒng)對交叉編譯的支持不如 FEX-Emu 和 DXMT 那么友好需要手動指定很多參數(shù)。cd wine mkdir build-ios cd build-ios ../configure --hostaarch64-apple-darwin \ --with-coreaudio \ --with-metalshader \ --without-x \ --disable-tests make -j$(sysctl -n hw.ncpu)--without-x是必須的因為 iOS 沒有 X11。--with-metalshader啟用 Metal 著色器后端這是 DXMT 能工作的前提。編譯過程中最常見的錯誤是缺少依賴庫。Wine 依賴 FreeType、libpng、libjpeg 等庫這些庫也需要針對 iOS 編譯。建議先用 Homebrew 安裝 macOS 版本然后手動編譯 iOS 版本并放到正確的路徑下。4.5 打包成 iOS App 并簽名三個組件都編譯好后需要把它們打包成一個 iOS App。這一步需要創(chuàng)建一個 Xcode 項目把編譯好的庫和可執(zhí)行文件嵌入進去然后寫一個啟動器來初始化 Wine 環(huán)境。Xcode 項目的關鍵配置Build Settings里設置ENABLE_BITCODENOBitcode 已經(jīng)廢棄Signing Capabilities里開啟Increased Memory Limit如果目標設備內(nèi)存較大Info.plist里添加get-task-allow為 true允許調(diào)試Entitlements里添加com.apple.security.cs.allow-jit為 true申請 JIT 權限簽名時如果使用免費開發(fā)者賬號證書有效期只有 7 天到期后需要重新簽名。付費賬號是 1 年。如果使用 TrollStore則不受此限制但需要設備系統(tǒng)版本在支持范圍內(nèi)。codesign --force --sign Apple Development: youremail.com \ --entitlements Madeira.entitlements \ --deep Madeira.app--deep參數(shù)會遞歸簽名 App 內(nèi)的所有可執(zhí)行文件和庫確保沒有遺漏。5. 常見問題與排查技巧實錄5.1 Wine 亂碼問題這是被問得最多的問題之一。Wine 在 iOS 上運行時中文、日文、韓文等非拉丁字符經(jīng)常顯示成方塊或亂碼。根本原因是字體缺失和字符集映射錯誤。解決方法分兩步第一步把 Windows 字體文件如simsun.ttc、msyh.ttf復制到 Wine 的字體目錄cp /path/to/fonts/*.ttf \ Madeira.app/drive_c/windows/Fonts/第二步修改 Wine 的注冊表把默認字體替換成支持中文的字體wine reg add HKCU\Software\Wine\Fonts\Replacements \ /v MS Shell Dlg /d Microsoft YaHei /f如果還是亂碼檢查LANG環(huán)境變量是否設置正確。在 iOS 上Wine 可能讀不到系統(tǒng)的語言設置需要手動指定export LANGzh_CN.UTF-8 export LC_ALLzh_CN.UTF-8提示W(wǎng)ine 的字體替換功能有緩存修改注冊表后需要刪除~/.wine目錄下的字體緩存文件或者直接重啟 Wine 環(huán)境。5.2 FEX-Emu 翻譯失敗導致程序崩潰如果程序啟動后立即崩潰而且日志里出現(xiàn)FEXCore: Invalid instruction或Unhandled signal之類的錯誤說明 FEX-Emu 遇到了它不認識的 x86-64 指令。這種情況通常發(fā)生在較新的程序上因為它們可能使用了 AVX-512、AMX 等 FEX-Emu 尚未完全支持的指令集。解決方法有更新 FEX-Emu 到最新版本新指令集的支持在持續(xù)添加在 FEX-Emu 配置里開啟HOSTFEATURES模擬讓程序以為 CPU 支持某些特性如果程序有 32 位版本嘗試用 32 位版本FEX-Emu 對 32 位 x86 的支持更成熟5.3 DXMT 圖形渲染異常DXMT 渲染異常的表現(xiàn)包括黑屏、花屏、紋理錯亂、幀率驟降。排查時先看日志里有沒有DXMT: Unsupported format或Metal: Validation error之類的信息。常見原因和解決方法問題現(xiàn)象可能原因解決方法黑屏但有聲音著色器編譯失敗更新 DXMT或切換 Wine 的 D3D 后端紋理錯亂格式轉換錯誤在 DXMT 配置里強制指定紋理格式幀率驟降Metal 命令緩沖區(qū)溢出降低游戲分辨率或關閉抗鋸齒畫面撕裂垂直同步未生效在 Wine 注冊表里開啟UseXVidMode我實測下來DXMT 對 D3D 11 的支持最好D3D 12 的游戲大約有一半能跑但畫面異常的概率較高。如果遇到 D3D 12 的問題可以嘗試用DXVK替代 DXMT雖然多了一層轉換但兼容性更穩(wěn)。5.4 iOS 設備發(fā)熱與降頻iOS 設備的散熱能力遠不如 Mac跑 Madeira 這種高負載任務時設備很快會發(fā)熱并觸發(fā)降頻。降頻后幀率可能直接腰斬體驗很差。緩解方法摘掉保護殼用散熱背夾降低游戲分辨率和畫質設置限制幀率到 30 幀減少 GPU 負載避免邊充電邊玩充電時發(fā)熱更嚴重如果設備頻繁降頻可以考慮在 Wine 配置里限制 CPU 使用率或者用cpuset把 Wine 進程綁定到特定核心上減少調(diào)度開銷。5.5 簽名過期與續(xù)簽免費開發(fā)者賬號簽名的 App 只有 7 天有效期到期后 App 無法啟動。續(xù)簽的方法是重新用 Xcode 或codesign簽名然后重新安裝。如果使用 AltStore它會在后臺自動續(xù)簽但需要保持 AltServer 在同一個 Wi-Fi 網(wǎng)絡下運行。SideStore 則支持在設備上直接續(xù)簽不需要連接電腦但配置起來更復雜。注意續(xù)簽時如果遇到Unable to install錯誤先檢查設備上是否已經(jīng)有同名 App刪除后重試。另外iOS 16 需要在設置里信任開發(fā)者證書否則 App 無法啟動。6. 性能調(diào)優(yōu)與進階玩法6.1 FEX-Emu 的配置調(diào)優(yōu)FEX-Emu 的配置文件通常位于~/.fex-emu/Config.json。幾個關鍵參數(shù){ Config: { RootFS: /path/to/rootfs, EmulatedCPU: { Core: 0, TSOEnabled: true, VectorTSOEnabled: true, HalfBarrierTSOEnabled: true }, HOSTFEATURES: { EnableAVX: true, EnableSSE4: true } } }TSOEnabled是內(nèi)存序模擬開啟后能提升多線程程序的兼容性但會帶來一定性能損失。如果程序對內(nèi)存序要求不高可以關掉試試。EnableAVX讓 FEX-Emu 模擬 AVX 指令集。有些程序啟動時會檢測 CPU 特性如果發(fā)現(xiàn)不支持 AVX 就直接退出。開啟這個選項能讓這些程序跑起來但性能會打折扣。6.2 DXMT 的 Metal 優(yōu)化DXMT 在 iOS 上運行時可以通過環(huán)境變量調(diào)整 Metal 的行為export DXMT_METAL_DEVICE0 export DXMT_METAL_MAX_FRAMES_IN_FLIGHT2 export DXMT_METAL_SHADER_CACHE1DXMT_METAL_MAX_FRAMES_IN_FLIGHT控制同時提交的幀數(shù)值越大延遲越高但吞吐量越大。在 iOS 上建議設為 2 或 3太高會導致內(nèi)存壓力。DXMT_METAL_SHADER_CACHE開啟著色器緩存第一次運行時會慢一些但后續(xù)啟動會快很多。緩存文件位于 App 的 Documents 目錄下可以手動清理。6.3 用外接鍵鼠提升操作體驗iOS 支持藍牙鍵鼠和 USB 鍵鼠通過轉接頭。Wine 會把外接鍵鼠的事件映射成 Windows 的鍵盤和鼠標事件操作體驗接近原生。如果玩的是策略游戲或 RPG外接鍵鼠幾乎是必須的。觸摸屏模擬鼠標右鍵很別扭而且很多游戲依賴快捷鍵。我試過用 iPad 的觸控板配合 Madeira體驗比純觸摸好很多但和真正的桌面環(huán)境還是有差距。6.4 多實例運行與資源隔離Madeira 支持同時運行多個 Windows 程序每個程序在獨立的 Wine prefix 里運行。這樣可以避免程序之間的配置沖突但也意味著每個實例都會占用一份內(nèi)存和 CPU 資源。在 iOS 上內(nèi)存是稀缺資源。iPad Pro 最多 16GB 內(nèi)存但 iOS 會限制單個 App 的內(nèi)存使用量。如果同時跑多個程序很容易觸發(fā)內(nèi)存警告導致 App 被系統(tǒng)殺掉。建議的做法是只跑一個程序把其他程序關掉。如果確實需要多開用WINEPREFIX環(huán)境變量指定不同的 prefix 目錄并監(jiān)控內(nèi)存使用情況。7. 我對這套方案的真實看法折騰 Madeira 這段時間最大的感受是技術上行得通但離 好用 還有距離。FEX-Emu 的翻譯效率比我預期的高DXMT 的圖形轉換也比 DXVKMoltenVK 那條鏈路更直接Wine 的 API 兼容性在大多數(shù)場景下夠用。但 iOS 的沙盒限制、JIT 權限問題、簽名續(xù)簽的麻煩讓整個方案的實用性打了折扣。如果你只是想體驗一下在 iOS 上跑 Windows 程序的感覺建議先從 macOS 版本入手熟悉整個流程后再嘗試 iOS。macOS 上沒有 JIT 限制簽名也簡單得多能把注意力集中在技術本身而不是和系統(tǒng)斗智斗勇上。另外這個領域變化很快。FEX-Emu 和 DXMT 都在活躍開發(fā)中每隔幾個月就有新版本發(fā)布兼容性和性能都在持續(xù)改善。如果你遇到了問題先去項目的 GitHub Issues 里搜一下很可能已經(jīng)有人遇到并解決了。實在搞不定的話把日志發(fā)到社區(qū)里通常會有熱心人幫忙分析。最后分享一個小技巧在 iOS 上調(diào)試 Wine 程序時把日志輸出到文件里比看控制臺方便得多??梢栽趩幽_本里加上WINEDEBUGall和重定向然后把日志文件導出到 Mac 上分析。雖然日志量很大但排查問題時能提供關鍵線索。