(一):介紹
出於某些原因,你可能會發現你想要和使用Windows DLL一樣使用你的Linux庫.對於這有一些原因如下:
你正在支持一個使用多個第三方庫的大應用.該項目在Linux中是可用的,但是你還沒有準備直接鏈接到他作爲一個Linux共享庫.
有一個定義好的可用的接口,並且有很多用於接口的解決辦法.
你僅僅有一個二進制Windows應用,他可以通過插件擴展,例如文本編輯器或IDE.
處理這些問題的過程是非常簡單的.你需要編寫一個spec文件,該文件以相同的格式描述庫接口作爲一個DLL.當然,你可能希望爲庫編寫一個小的封裝.你組合他們形成一個Wine內置的鏈接到Linux庫的DLL.然後你在wine配置中修改theDllOverrides來確保這個新內置的DLL被調用,而不是任何的Windows版本.
在這個小節中,我們將會看到兩個例子程序.第一個例子是非常簡單的,並且在”baby steps”中引入主題.都二個例子是在Wine中ODBC的接口代理.我們將要位ODBC例子引用的文件位於Wine源碼的dlls/odbc32目錄中.
第一個例子是基於一個情況(例如,函數的名稱已經被改變了來保護無辜的函數).大量的Windows應用包含鏈接到第三方DLL的DLL.出於一些原因,第三方DLL在Wine中運行不是很好.然後,第三方庫在Linux環境中也是可用的.方便的是,DLL和Linux共享庫只有一小部分功能,並且應用只用使用其中的一個.
特別的,應用調用一個函數:
signed short WINAPI MyWinFunc (unsigned short a, void *b, void *c,unsigned long *d, void *e, int f, char g, unsigned char *h);
linux庫包含一個相應的函數:
signed short MyLinuxFunc (unsigned short a, void *b, void *c,unsigned short *d, void *e, char g, unsigned char *h);
(二):編寫spec文件
通過編寫spec文件開始.這個文件描述接口,好像他是DLL一樣.
在這個簡單的例子中,我們想要一個Wine內置的DLL和MyWin DLL相對應.spec文件是MyWin.dll.spec,並且看上去像這:
#
# File: MyWin.dll.spec
#
# some sort of copyright
#
# Wine spec file for the MyWin.dll built-in library (a minimal wrapper around the
# linux library libMyLinux)
#
# For further details of wine spec files see the Winelib documentation at
# www.winehq.org
2 stdcall MyWinFunc (long ptr ptr ptr ptr long long ptr) MyProxyWinFunc
# End of file
注意,參數被標記成了long,即使他們比那個要小.通過這個例子,我們將直接鏈接到Linux共享庫,而通過ODBC這個例子,我們將動態加載Linux共享庫.
在ODBC例子中,你可以在文件odbc32.spec中看到這些.
(三):編寫一個封裝
首先,我們將要看一個簡單的例子.這個例子主要的問題就是優點不同的參數列表.f參數不必傳遞給Linux函數,並且d參數理論上需要從unsigned long *
和unsigned short *
之間轉換.這麼做是爲了確保高位的返回值被正確設置.也不像ODBC例子一樣,我們將要直接鏈接到Linux的共享庫上.
/*
* File: MyWin.c
*
* Copyright (c) The copyright holder.
*
* Basic Wine wrapper for the Linux 3rd party library so that it can be
* used by the application
*
* Currently this file makes no attempt to be a full wrapper for the 3rd
* party library; it only exports enough for our own use.
*
* Note that this is a Unix file; please don't go converting it to DOS format
* (e.g. converting line feeds to Carriage return/Line feed).
*
* This file should be built in a Wine environment as a Winelib library,
* linked to the Linux 3rd party libraries (currently libxxxx.so and
* libyyyy.so)
*/
#include <3rd party linux header>
#include <windef.h> /* Part of the Wine header files */
/* This declaration is as defined in the spec file. It is deliberately not
* specified in terms of 3rd party types since we are messing about here
* between two operating systems (making it look like a Windows thing when
* actually it is a Linux thing). In this way the compiler will point out any
* inconsistencies.
* For example the fourth argument needs care
*/
signed short WINAPI MyProxyWinFunc (unsigned short a, void *b, void *c,unsigned long *d, void *e, int f, char g, unsigned char *h)
{
unsigned short d1;
signed short ret;
d1 = (unsigned short) *d;
ret = 3rd party linux function (a, b, c, &d1, e, g, h);
*d = d1;
return ret;
}
/* End of file */
對於一個更廣泛的情況,我們可以使用ODBC例子.這個被實現位一個頭文件(proxyodbc.h)和一個C源碼文件(proxyodbc.c).雖然文件非常長,但是在結構上非常簡單.
DllMain函數用於初始化DLL.在過程附加事件中,函數動態鏈接到期望的Linux ODBC庫中(因爲有若干個可用的),並且構建一系列的函數指針.在過程解附加事件中,他解除鏈接.
然後每一個函數通過在初始化過程中設置的函數指針調用適當的Linux函數.
(四):構建
那麼我們如何構建一個Wine內置的DLL呢?最簡單的方法就是使winemaker來爲我們做這些複雜的工作.舉個簡單例子,我們有兩個源碼文件(封裝和spec文件).我們也有第三方頭文件和庫文件.
將這兩個源文件放到一個合適的目錄中,然後使用winemaker來創建構建框架,包括配置腳本,makefile等等.你可能希望使用下面的選項:
--nosource-fix
(需要winemaker的版本爲0.5或更新)來確保兩個文件未被修改(如果使用了一個較低版本,使這兩個文件只讀,並且忽略不能修改他們的投訴).--dll --single-target MyWin --nomfc
來指定目標--DMightNeedSomething -I3rd_party_include -L3rd_party_lib -lxxxx -lyyyy
這些頭文件的位置等
在運行winemaker之後,我可以僅僅在定義之前編輯Makefile,向其中添加一行CEXTRA = -Wall
.
然後就是簡單的運行confugure和make即可.
(五):安裝
那麼我們如何安裝代理,並且確保每個事物都連接正確呢?在這個事情上有很大的靈活性,所以需要遵循的不是唯一可行的選項.
確保Linux共享對象放到了Linux系統能夠找到的地方.這就意味着他應該被放在在/etc/ld.so.conf文件中提及的目錄中的一箇中或者是在LD_LIBRARY_PATH指定的路徑下面.如果你能從Linux程序中鏈接到他,應該也是可以的.
講代理共享對象(MyWin.dll.so)放到相同的位置作爲內置DLL的其他部分.確保WINEDLLPATH包含有代理共享對象的目錄.
如果你既有Windows DLL也有一個Linux DLL/代理對,那麼你必須確保有正確的一個得到調用.最簡單的方法就是重命名Windows版本,使他不被檢測到.你可以使用winecfg設置一個DLL重寫,這樣內置版本就會被使用.
一旦你這樣做了,你就應該成功的使用Linux共享對象了.如果你有問題,然後在運行wine之前設置 WINEDEBUG=+module
環境變量來查看真正發生了什麼.
(六):轉換文件名
假設你想要轉換傳入的DOS格式的文件名稱到他們等效的Unix格式.當然,在微軟的Windows API中沒有合適的函數,但是wine提供了一個用於這個工作的函數,並且從kernel32 DLL的拷貝中導出的.這個函數就是wine_get_unix_file_name
(定義在winbase.h)中.