說起 Wine,稍微資深一點(diǎn)的 Linux 用戶應(yīng)該都聽過,但是真要說起 Wine 到底是怎么回事,可能大多數(shù)人不見得說得清。這篇文章會簡單地介紹 Wine 的工作原理,以及如何開始 Wine 的開發(fā)。所以如果您屬于以下三類讀者之一:
想?yún)⑴c Wine 開發(fā),但是不知如何開始的。
僅僅想大致了解 Wine 是如何工作的。
只是想能夠愉快的用上最新版本 Wine 的。
希望在看完本文后,能夠有一些收獲。
Part 1 Wine 是什么
Wine 是 "Wine Is Not an Emulator" 的遞歸縮寫,如同 "GNU" 一樣(GNU's Not Unix),字面意思就是 Wine 不是一個模擬器。這里的模擬器主要是指 Wine 并不是一個虛擬機(jī),而是一個 Windows API 實(shí)現(xiàn)兼容層。這么說可能不太好理解,大家可以把 Windows 應(yīng)用程序類比成 Android 應(yīng)用程序,而 Wine 的角色就和 Android 很像了,將操作系統(tǒng)提供的各種功能封裝成 API,并讓應(yīng)用程序在隔離的環(huán)境內(nèi)運(yùn)行。至于 API 長成啥樣,隔離的力度如何,這些都是實(shí)現(xiàn)相關(guān)的,和本質(zhì)并不沖突。另一方面,Wine 其實(shí)又是一個模擬器,不過模擬的對象不是硬件 CPU,而是 Windows 的行為。
Part 2 Wine 原理介紹
本節(jié)內(nèi)容相對來說稍顯基礎(chǔ)和單一啦,并且閱讀時最好對操作系統(tǒng)有一定程度的了解哦。如果只是想編譯、運(yùn)行,對原理不敢興趣的同學(xué),可以跳過,不影響后面的閱讀。
Wine 的目的是運(yùn)行 Windows 上的可執(zhí)行程序(PE,portable executable)。我們知道,可執(zhí)行程序的本質(zhì)其實(shí)就是按照某一規(guī)則排列的機(jī)器碼,而機(jī)器碼是指令集相關(guān)的。得益于常見的 PC 機(jī)一般是 x86/x64 的,因此 Windows 應(yīng)用程序從指令集的角度看,是完全可以在 x86/x64 的 Linux 機(jī)器上直接運(yùn)行,而不需要硬件層模擬的。
但是為了能夠直接加載運(yùn)行 PE 文件,需要滿足一些 ABI 兼容。最基本的,Windows PE 程序會假定自己被加載到地址 0x400000 處,因此 Wine 實(shí)現(xiàn)自己的 loader 時,需要保證將 PE 鏡像加載到同樣的位置。對于靜態(tài)鏈接的程序,需要做的事情可能不是太多,但是對于動態(tài)鏈接的程序,Wine 需要模仿 Windows loader 的行為,加載依賴的庫,并進(jìn)行相應(yīng)的重定位工作。
為了最大程度上減少對二進(jìn)制層面的依賴,Wine 決定實(shí)現(xiàn)至少 GDI32,KERNEL32,USER32 三個動態(tài)庫,因為其他庫都是建立在這三個庫的基礎(chǔ)之上的。所以理論上來說,除此之外的其他動態(tài)庫是可以直接使用 Windows 上面現(xiàn)有的庫,但由于各種原因,Wine 還是傾向于盡量實(shí)現(xiàn)所有的 API。我們把 Wine 自己實(shí)現(xiàn)的 API 庫稱作 builtin,把 Windows 上現(xiàn)成的庫稱作 native。當(dāng) Wine 在加載 builtin 動態(tài)庫的同時,還會在內(nèi)存中建立 PE header,用來模仿 Windows 上的內(nèi)存布局。更加詳細(xì)的實(shí)現(xiàn),有機(jī)會可以寫一篇 Wine loader 相關(guān)的文章來介紹 Wine 本身、PE 程序和動態(tài)庫是如何被加載的。
除開 loader 的功能外,Wine 還需要解決進(jìn)程間通信(IPC)的問題。Wine 的實(shí)現(xiàn)方式是將所有跨進(jìn)程的對象和機(jī)制,比如 GDI 對象,比如信號量,全部實(shí)現(xiàn)在 Wine server 中。同時 Wine 允許系統(tǒng)運(yùn)行多個 Wine server 的實(shí)例。這樣存在于同一個 Wine server 中的對象自然是可以相互通信,好像在同一個空間內(nèi);而不同 Wine server 下的對象,是相互隔離的,這種架構(gòu)使得不同容器之間的程序相互沒有影響。Wine server 的具體實(shí)現(xiàn)是通過 unix socket,實(shí)現(xiàn)了一套 IPC 機(jī)制,完成和 API 層的交互。
有了以上這些基礎(chǔ),Wine 實(shí)現(xiàn)起各種功能就可以按部就班了,只需理解 Windows 下 API 的行為和含義,然后再重新實(shí)現(xiàn)一遍就行了。聽起來雖然簡單,實(shí)際難度不小,特別是一些未公開的行為,必須對整體有相當(dāng)?shù)牧私夂蟛拍芟率?。甚至一些差異,比?UI 相關(guān)的內(nèi)容,由于 Windows 窗口系統(tǒng)和 X 在設(shè)計哲學(xué)上的不同,實(shí)現(xiàn)上需要有所舍取。目前 Wine 支持的平臺不僅包括 Linux,還包括 BSD、Mac OS X 和 Android。
Part 3 環(huán)境
下面的開發(fā)環(huán)境都以 deepin 為例進(jìn)行說明。
首先獲取代碼。Wine 官方代碼倉庫地址為
git://source.winehq.org/git/wine.git
如果你想方便打包給別人使用,又不太想折騰打包的一些細(xì)節(jié),可以用各個發(fā)行版自己維護(hù)的 Wine。比如 Debian 維護(hù)的 Wine 倉庫地址為
https://salsa.debian.org/wine-team/wine.git
這里以官方的 Wine 為例:
git clone git://source.winehq.org/git/wine.git
然后安裝開發(fā)的依賴。為了簡單起見,我們只編譯 32 位的 Wine,因為 64 位的 Wine 只支持 64 位的 PE 程序,而目前 Windows 上仍有大量的程序只提供了 32 位的版本。
sudo apt install gcc-multilib flex bison libx11-dev:i386 libfreetype6-dev:i386 libxcursor-dev:i386 libxi-dev:i386 libxshmfence-dev:i386 libxxf86vm-dev:i386 libxrandr-dev:i386 libxfixes-dev:i386 libxinerama-dev:i386 libxcomposite-dev:i386 libglu1-mesa-dev:i386 libosmesa6-dev:i386 ocl-icd-opencl-dev:i386 libpcap-dev:i386 libdbus-1-dev:i386 libgnutls28-dev:i386 libncurses-dev:i386 libsane-dev:i386 libv4l-dev:i386 libgphoto2-dev:i386 liblcms2-dev:i386 libpulse-dev:i386 libgstreamer-plugins-base1.0-dev:i386 libudev-dev:i386 libcapi20-dev:i386 libcups2-dev:i386 libfontconfig1-dev:i386 libgsm1-dev:i386 libkrb5-dev:i386 libtiff-dev:i386 libmpg123-dev:i386 libopenal-dev:i386 libldap2-dev:i386 libxrandr-dev:i386 libxml2-dev:i386 libxslt1-dev:i386 libjpeg62-turbo-dev:i386 libusb-1.0-0-dev:i386 gettext libsdl2-dev:i386 libvulkan-dev:i386接著運(yùn)行腳本:
./configure --with-gnutls --without-hal --without-oss
根據(jù)不同的 Wine 版本,此時可能會提示不同的 feature 支持情況。我們可以根據(jù)需求,對上面的依賴庫和傳入的參數(shù)進(jìn)行調(diào)整,具體可以查看 configure.ac 的內(nèi)容。
Wine 的源碼比較大,編譯有些耗時,可以根據(jù) CPU 情況增加并行參數(shù),比如 make -j8,進(jìn)行編譯。
編譯完成后,運(yùn)行:
./wine --version可以查看版本號。如果想安裝到系統(tǒng),可以運(yùn)行:
sudo make install但是注意,安裝后可能會修改一些文件的默認(rèn)打開方式。
Part 4 使用
運(yùn)行:
./wine winecfg可以對默認(rèn)容器進(jìn)行設(shè)置,默認(rèn)的容器位于 HOME 目錄下的 .wine,環(huán)境變量 WINEPREFIX 用來修改當(dāng)前的容器路徑。比如有一個叫 demo.exe 的可執(zhí)行文件,我們想測試能否正常運(yùn)行,可以運(yùn)行。
WINEPREFIX=~/.demo_exe ./wine demo.exeHOME 目錄下的`demo_exe`就會作為其容器目錄。
Part 5 開發(fā)
編譯過后的 Wine 源碼目錄結(jié)構(gòu)如下:
├── aclocal.m4 ├── ANNOUNCE ├── AUTHORS ├── config.log ├── config.status ├── configure ├── configure.ac ├── COPYING.LIB ├── dlls ├── documentation ├── fonts ├── include ├── libs ├── LICENSE ├── LICENSE.OLD ├── loader ├── MAINTAINERS ├── Makefile ├── Makefile.in ├── po ├── programs ├── README ├── server ├── tools ├── VERSION └── wine -> tools/winewrapper
目錄 dlls 按照模塊存放了所有 API 的實(shí)現(xiàn)。
目錄 loader 是和 Wine 啟動、加載相關(guān)的代碼。
目錄 programs 存放了外部程序的代碼,比如注冊表管理工具 regedit 。
目錄 server 顧名思義,是 Wine server 的實(shí)現(xiàn)。
接下來需要做的就和普通開發(fā)沒什么兩樣了。比如說我們發(fā)現(xiàn)某個應(yīng)用存在字體相關(guān)的 BUG,可以首先根據(jù)經(jīng)驗判斷在 Windows 上,該程序是如何實(shí)現(xiàn)的,然后查看對應(yīng)的實(shí)現(xiàn)。例如 GDI 相關(guān)的字體實(shí)現(xiàn),位于 dlls/gdi32/font.c 和 dlls/gdi32/freetype.c 。修改完代碼后,在所在模塊的目錄,比如上例就是 dlls/gdi32 下重新 make 就可以快速驗證了。
對于復(fù)雜的問題,不太好直接定位的,可以通過輸出日志的方式來調(diào)試,環(huán)境變量 WINEDEBUG 指定了需要輸出的日志。
有時我們可能需要把復(fù)雜的情況簡單化,這時候難免會寫一些小的 demo 程序來重現(xiàn)問題。如果不想到 Windows 上面編譯,可以使用 mingw 直接在 deepin 下編譯出 exe 文件。方法很簡單,首先安裝 mingw:
sudo apt install mingw-w64接著正常利用 Windows API 實(shí)現(xiàn)程序,最后利用 mingw 編譯工具鏈生成文件即可,Makefile 示例:
hello.exe: hello.c i686-w64-mingw32-g++ -o hello.exe hello.c -DUNICODE -D_UNICODE -municode -lgdi32
上面的例子,定義了 UNICODE,所以使用的 UNICODE 版本的 API,入口函數(shù)為 wmain,-lgdi32 表示需要鏈接庫 gdi32 。生成出來的 hello.exe,可以同時在 Windows 和 deepin 下運(yùn)行。
Part 6 其他
本文介紹的內(nèi)容只涉及到 Wine 開發(fā)的基礎(chǔ),Wine 本身還有很多東西值得去探索。比如 Wine 是如何使用 driver 機(jī)制讓接口和實(shí)現(xiàn)分離的,再比如 Wine 是如何使用純 C 實(shí)現(xiàn) COM 機(jī)制的。雖然 Wine 的出現(xiàn)已經(jīng)有一些年頭了,但是目前的開發(fā)仍然比較活躍,感興趣的同學(xué)可以加入進(jìn)來,為 Linux 生態(tài)添磚加瓦,讓大家能用到更多的優(yōu)質(zhì)應(yīng)用,也算是曲線救國了。
Part 7 更新
7.1 新的 WOW64
上面編譯的例子中,我們只編譯了 32 位的 Wine,忽略了編譯 64 位 Wine 的細(xì)節(jié)。從 Wine 8 開始,Wine 開始了一個稱為 PE Convertion 的開發(fā)過程,重新實(shí)現(xiàn)了 WOW64 的機(jī)制。此模式下只需要編譯出一份 Wine,既可以運(yùn)行 32 位程序,也能運(yùn)行 64 位程序。同時也不再依賴 32 位的運(yùn)行時庫。雖然此模式還被認(rèn)為處于實(shí)驗階段,但是從 deepin-wine8 開始,我們已經(jīng)默認(rèn)使用此方式。
編譯新的 WOW64 方式的 Wine,步驟如下:
Wine 官方的源碼地址已經(jīng)更改,在https://gitlab.winehq.org/wine/wine.git下載源代碼。
依舊需要安裝編譯時依賴的開發(fā)庫,不同在于我們這次只需要安裝 amd64 的版本,在安裝開發(fā)庫時不再需要指定 :i386 后綴。此外 mingw-w64 在此模式下成為必須項。
在 Wine 源碼目錄的同級目錄下新建 build-wine 目錄,并進(jìn)入此目錄。
運(yùn)行 ../wine/configure --prefix=/opt/wine-newwow64 --enable-archs=i386,x86_64。這一步如果有任何提示,比如缺少編譯期依賴,可以在安裝后再次運(yùn)行。
make -j8,進(jìn)行編譯。
sudo make install 安裝,Wine 會安裝在第 4 步通過 prefix 指定的位置,即 /opt/wine-newwow64 。當(dāng)然也可以選擇不安裝,直接在編譯目錄下運(yùn)行。
7.2 其他架構(gòu)
在關(guān)于原理一節(jié)的描述中我們提到過,x86/x64 機(jī)器的 Linux 系統(tǒng)可以通過 Wine 運(yùn)行 x86/x64 的 PE 程序。實(shí)際上如今通過 DBT(dynamic binary translation)技術(shù),在 ARM 及其他架構(gòu)上已經(jīng)有了運(yùn)行 Wine 的方案。感興趣的讀者可以查看Box64項目。
11月份,微信在 deepin 商店上架了Linux原生版本,功能與 Windows、MacOS 相差無幾。Wine 版本的微信終于可以"功成身退"了,我們也期待今后有更多軟件推出原生版本,讓 Wine 早點(diǎn)完成"歷史使命"。
-
Linux
+關(guān)注
關(guān)注
87文章
11351瀏覽量
210512 -
WINDOWS
+關(guān)注
關(guān)注
4文章
3581瀏覽量
89395 -
應(yīng)用程序
+關(guān)注
關(guān)注
38文章
3297瀏覽量
57947 -
模擬器
+關(guān)注
關(guān)注
2文章
884瀏覽量
43445
原文標(biāo)題:想開啟 Wine 開發(fā)?看這篇就夠了!
文章出處:【微信號:linux_deepin,微信公眾號:深度操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
用Wine運(yùn)行exe軟件的教程
linux下的快捷鍵全面介紹
介紹基于協(xié)議棧外設(shè)的開發(fā)
intel edison 開發(fā)板的開發(fā)平臺介紹
linux下wine的使用
異亮科技發(fā)布新品AIR VALLEY WINE智能凈化落地?zé)?/a>
JEEWeb的開發(fā)相關(guān)技術(shù)介紹
![JEEWeb的<b class='flag-5'>開發(fā)</b>相關(guān)技術(shù)<b class='flag-5'>介紹</b>](https://file.elecfans.com/web1/M00/84/E8/o4YBAFxmhJaATvx-AAWZruivUP4320.png)
盤點(diǎn)一下這些可以通過Wine在Linux上玩的游戲
Wine 5.4版本更新更多新功能
Wine中將提供Windows應(yīng)用程序與USB更好支持
![<b class='flag-5'>Wine</b>中將提供Windows應(yīng)用程序與USB更好支持](https://file.elecfans.com/web1/M00/BA/CF/pIYBAF6brf-AHCtJAATXFAnNBTY636.png)
Wine更新:支持 Linux 運(yùn)行 Windows 應(yīng)用,PE 格式核心模塊
如何在Ubuntu上安裝最新版本的Wine
Wine開發(fā)系列——如何使用Wine日志調(diào)試問題
Wine常用調(diào)試方法
![<b class='flag-5'>Wine</b>常用調(diào)試方法](https://file1.elecfans.com/web3/M00/06/27/wKgZPGeIZs6AHlZGAAAR3HEbRdo539.png)
評論