[英]How to wrap a Linux library to be used in Wine? I keep getting BAD_IMAGE_FORMAT
我有一個可以通過插件擴展的僅限 Windows 的游戲,以及我想使用的 Linux 庫。 該應用程序(Unity 游戲)在 Wine/Proton 下運行良好。 我發現 Winelib 可以做到這一點,並且我遵循了用戶指南,特別是第 5 節,其中提到了我的確切用例。
經過一些嘗試(比如從釀酒師中刪除 --single-target arg),我到了 Proton 調試日志一直顯示 c000007b 似乎是 STATUS_BAD_IMAGE_FORMAT 的地步。
請注意,我重命名了 Linux 庫(並與之鏈接),以避免它與我的包裝器之間的潛在沖突。
我只有一個 64 位版本的庫,它是使用 cdecl 調用約定從 C# 代碼調用的。 這是我迄今為止嘗試過的(以及這些的組合):
1 cdecl -arch=x86_64 LibraryFunc (long ptr ptr) LibraryFuncWine
#include "library_header.h"
#include <windef.h> /* Part of the Wine header files */
enum ELibResult WINAPI LibraryFuncWine(Version version, struct CreateParams* params, struct ICore** result)
{
enum ELibResult ret = LibraryFunc(version, params, result);
return ret;
}
winemaker --nosource-fix --dll --nomfc -I. -L. -llinux_library.
winemaker --nosource-fix --dll --nomfc -I. -L. -llinux_library.
然后make
--mno-cygwin
添加到編譯器標志-m64
和-fPIC
添加到編譯器/鏈接器標志(基於Wine 規范文件)--nomsvcrt
並運行make
(header 文件包括 string.h)從質子日志(+模塊,其他人沒有為我提供更多信息):
00dc:trace:module:load_dll looking for L"Z:\\D\\a\\library\\path\\library_name" in L"Z:\\D\\gamepath;C:\\windows\\system32;C:\\windows\\system;C:\\windows;C:\\Program Files (x86)\\Steam;.;C:\\windows\\system32;C:\\windows;C:\\windows\\system32\\wbem;C:\\windows\\system32\\WindowsPowershell\\v1.0"
00dc:trace:module:get_load_order looking for L"Z:\\D\\a\\library\\path\\library_name.dll"
00dc:trace:module:get_load_order_value got standard key b for L"library_name"
00dc:trace:module:load_builtin_dll Trying built-in L"library_name.dll"
00dc:trace:module:load_so_dll loading L"\\??\\Z:\\D\\a\\library\\path\\library_name.dll" from so lib "/D/Games/SteamLibrary/steamapps/common/Proton 5.0/dist/bin/../lib64/wine/library_name.dll.so"
00dc:warn:module:load_dll Failed to load module L"Z:\\D\\a\\library\\path\\library_name"; status=c000007b
使用和不使用.dll 並以 lib 開頭(library_name.dll、liblibrary_name 和 liblibrary_name.dll)重復相同的操作。
除了該錯誤代碼之外,我無法獲得更多關於究竟出了什么問題的日志。
在 C# 端(由 Unity 在 Proton 中運行)會導致 DllNotFoundException。
Wine 版本 (winebuild, winegcc): 5.9 (staging) - gcc 9.0.1
質子版本:5.0 - wine-5.0-603-g068dee4
可能有一個僅適用於您的二進制文件的解決方案。 .so
使用 RPC。
但是,由於許多/大多數 linux 庫都有源代碼,那么具體的庫是什么[沒有]? 是否有類似的替代庫? 如果您足夠努力,可能會有二進制庫的源代碼。
但是,我假設您必須使用二進制 linux 庫。
但是,這可能涉及比您願意做的更多的工作。 那么,你有多想要這個? ;-)
這是用於生產還是僅供個人使用? 我假設只是供個人使用,因為您正試圖讓 WinX 游戲在 wine 下工作。
.so
就公共 API 函數[您的 wine 程序需要調用]的數量而言有多大? 涉及多少種不同的結構?
您可能需要為每個 API 調用和結構創建粘合/接口例程。
基本方法是使用[某種] RPC [遠程過程調用]機制(例如) https://en.wikipedia.org/wiki/Remote_procedure_call
您創建了一個 linux 服務器,其中包含所需的 [僅限 linux] 庫。 您編寫將 RPC 調用轉換為庫的 API 調用的包裝例程。
在游戲中,您的插件會發出 RPC 調用,然后發送到服務器,服務器進行處理,然后發回結果。
有一些工具可以幫助您(例如rpcgen
)
通常,RPC 是通過網絡/套接字連接完成的。 出於您的目的,這可以通過 localhost 或使用AF_UNIX
連接。 也許這對您的目的來說已經足夠快了。
否則,您可能必須建立一個共享的 memory 緩沖池並將其添加為 RPC 調用的附件。
更新:
謝謝,但你能提供更多關於為什么使用 Winelib 不可行的信息嗎? 在指南中,我認為我可以將 Linux 庫鏈接到我的庫。
可以編寫一些膠水函數。 這樣做可能會有問題。 但是,根據我在 Discord SDK 中找到的內容,您也許可以繞過 [all] 。 見下文。
ABI 差異:在 WinX 中,前四個 arguments 在 regs 中傳遞,在 linux 中,前六個 arguments 在 regs 中傳遞。 寄存器不同。 這可以通過建立新堆棧幀並將值移動到 linux 的正確寄存器的“thunk”例程來處理。 請參閱: https://en.wikipedia.org/wiki/X86_calling_conventions
但是,至少在我的機器上, wine
最終會轉到/usr/bin/wine32
,這是一個 32 位可執行文件。 但是,您的 linux 庫是 64 位的。 這個問題不容易解決。 請參閱: 是否可以在 64 位 Linux 的同一可執行文件中同時使用 64 位和 32 位指令? 就個人而言,如果我必須這樣做,我會 go RPC 路由。
該庫導出 2 個函數,我只對 1 個感興趣,該功能的 rest 是通過 function 指針(我不確定這些是否適用於 wine,但還沒有)。 該庫實際上是 Discord 的游戲 SDK 所以沒有替代品,但這只是一個愛好。
我剛剛從網站上下載discord_game_sdk.zip
並解壓縮。 它有源代碼示例程序。 並且,必要的.h
文件。
有一個lib/x86
子目錄,其中包含: discord_game_sdk.dll
和discord_game_sdk.dll.lib
,它們是 32 位 PE 格式文件。 而且,還有一個lib/x86_64
子目錄 [其中有一個.so
]
那么,代替 linux .so
,您可以直接鏈接到那些 PE 格式文件嗎? (例如)它們可能可以使用LoadLibrary
加載
如果沒有直接的方法,我可以使用 sockets (但是創建 unix 套接字不會有同樣的問題嗎?我當然可以使用 localhost)。
然后,考慮這是一個后備 position。
對 localhost 的PF_INET
套接字調用非常快,並且 [通過一些“技巧”] 您可以在您的插件 [在wine
下] 和一個服務器程序 [您創建的] 之間建立共享的 memory 空間,該服務器程序具有 linux .so
鏈接到它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.