跨平台的 plugin 開發函式庫:Boost DLL – 進階

| | 0 Comments| 16:59
Categories:

這篇是延續前一篇《基本使用》,繼續來整理一些 Boost.DLL 的其他功能。


Alias(別名)

首先,是「alias」(別名)的部分。

在前一篇裡面,已經提過基本的匯出、匯入的方法了。在基本的方法中,要匯出和匯入時,都是直接使用本來的變數、函式名稱;但是有的時候,如果不方便直接使用原有的變數、函式名稱,但是又不好直接去改名的時候,就可以透過 alias 的機制,在匯出時採用另一個名字來匯出。

而如果要改用 alias 的形式來匯出一個變數的話,要使用 BOOST_DLL_ALIAS 這個巨集(定義於 boost/dll/alias.hpp),程式碼可以寫成:

std::string sModuleName = "Module A";
BOOST_DLL_ALIAS(sModuleName, NAME)

如此一來,sModuleName 這個變數就會以 NAME 這個別名被匯出。

不過,使用別名和本來的名字匯出,在實作上還是有有所不同的,所以在匯入的時候,使用的函式也必須要從 boost::dll::import<>() 改成 boost::dll::import_alias<>() 才行。

以要匯入 NAME 來說,可以寫成:

boost::shared_ptr<std::string> pVar =
boost::dll::import_alias<std::string>( pathDLL, "NAME" );

基本上,這樣就可以了~

個人覺得比較討厭的,是使用 alias 的時候,import 也要使用不同的函式,算是比較麻煩的…

另外,其實 Boost.DLL 的 alias 還有「section」(應該算是「章節」)的功能,可以幫匯出的東西分類。如果要使用的話,就是在匯出時要改用 BOOST_DLL_ALIAS_SECTIONED 這個巨集;而實際上,Boost.DLL 的 BOOST_DLL_ALIAS 預設會以 boostdll 作為 section 名稱來匯出,所以如果寫成

BOOST_DLL_ALIAS_SECTIONED(sModuleName, NAME, boostdll)

的話,會和前面的匯出方法完全相同。而如果想要改用其他 section 名稱的話,就只要把 boostdll 換掉就可以了。

而有需要的話,也可以透過 BOOST_DLL_SECTION官方文件)來設定存取權限;不過老實說,Heresy 不知道什麼時候會要用到就是了…

另外,看來 Boost.DLL 的 section 設計主要是給 boost::dll::library_info 用的,在使用 boost::dll::import_alias<>() 匯入時,並沒有辦法、也不需要指定 section 名稱。

這邊的範例可以參考:https://github.com/KHeresy/Boost.DLL.Example/tree/AliasExample


library_info

在 Boost.DLL 裡,boost::dll::library_info官方文件)是設計用來讀取一個動態函式庫的資料用的類別。

它的使用非常簡單,只要把 DLL / SO 的路徑傳給他,就可以建立出對應的 library_info 物件了。而之後,只要透過他的 sections()symbols() 這兩個函式,就可以知道所指定的檔案裡面有哪些 section、以及匯出了哪些東西了。

下面是一個簡單的使用範例:

// Load library information
boost::dll::library_info infDLL(pathDLL);
// get all section name
std::cout << "List sectionsn";
std::vector<std::string> vSections = infDLL.sections();
for (const std::string& sSection : vSections)
{
	std::cout << " Section: " << sSection << "n";
	// get all symbol name
	std::vector<std::string> vSymbols = infDLL.symbols(sSection);
	for (const std::string& sSymbol : vSymbols)
	{
		std::cout << "  - " << sSymbol << "n";
	}
}

在上面的例子裡面,首先是先建立了一個 library_info 的物件 infDLL,他會去讀取 pathDLL 這個檔案的內容。而接下來則是先透過 sections() 這個函式、來取得他的 section 列表;之後再透過 for 迴圈,並使用 symbols() 這個函式去讀取裡面每個 section 所匯出的符號、然後再依序輸出。

不過,由於編譯器在建置動態函式庫的時候,似乎是會在裡面建立一些特殊、內建的 section,所以在讀取的時候,應該會看到很多以「.」開頭的 section。像下面就是在 Windows + MSVC 跑的結果:

 Section: .textbss
 Section: .text
 Section: .rdata
 Section: .data
 Section: .pdata
 Section: .idata
 Section: boostdll
  - NAME
 Section: XD
  - GET_NAME
 Section: .gfids
 Section: .00cfg
 Section: .rsrc
 Section: .reloc

而 Heresy 試過,在 Ubuntu 下用 g++ 編譯的話,這類的東西會更多。

另外,在 MSVC 下,想透過 symbols() 去讀取這些 section 中的資訊是會出問題的,所以建議在上面的程式中,建議把這些內建的 section 綠調會比較好。

而如果不想管 section 的話,也可以不指定 section 名稱、直接呼叫 symbols() 來取得所有匯出的東西;他的寫法可以寫成:

std::vector<std::string> vSymbols = infDLL.symbols();
for (const std::string& sSymbol : vSymbols)
{
	std::cout << " " << sSymbol << "n";
}

不過老實說,Heresy 不太確定這樣列出來他匯出了哪些東西,到底該怎麼用?因為實際上,他並沒有告訴使用者,這個符號到底是代表變數、還是函式啊…而如果知道是函式的話,其實也還是不知道她需要那些引數啊… @@

所以感覺上,library_info 這個類別,應該還是只能當作輔助用的吧?例如,如果想確定這個動態函式庫裡面是否有自己需要的符號名稱,就可以透過這個方法來做事前的檢查。

這部分的範例程式,可以參考:https://github.com/KHeresy/Boost.DLL.Example/tree/library_info


shared_library

boost::dll::shared_library 這個類別,是一個可以比較好地用來控制動態函式庫的生命週期的東西,同時他也提供了簡單的檢查功能,可以用來確認所讀取的模組是否有指定的符號。

根據官方文件的說法,它內部的參考計算方法,可以處理得很好、不管使用相對路徑或絕對路徑,都不用擔心會被重複建立,所以在記憶體的管理上、算是非常有效率了。

而它的使用方法,大致上就是先透過指定檔案所在的路徑建立出 boost::dll::shared_library 的物件後,然後再透過 get<>()get_alias<>() 來匯入所需要的東西了~

下面就是一個簡單的範例:

boost::dll::shared_library libDLL(pathDLL);
if (libDLL.has("NAME"))
{
    std::string sVar = libDLL.get_alias<std::string>("NAME");
    std::cout << "Variable: " << sVar << std::endl;
}
if (libDLL.has("GET_NAME"))
{
    std::function<std::string()> funcExt = libDLL.get_alias<std::string()>("GET_NAME");
    std::cout << "Function: " << funcExt() << std::endl;
}
libDLL.unload();

可以看到,這邊的使用方法大致上都和直接使用 boost::dll::import<>()boost::dll::import_alias<>() 相同,不過由於可以在匯入之前,先透過 has() 來檢查是否有要匯入的東西,算是比較方便操作的了~

另外,比較不一樣的地方,則是使用 get<>()get_alias<>() 匯入變數時,所回傳的型別並不是 boost::shared_ptr<>,而是實際的型別;所以如果是指標、會是參考的話,就必須要自己管理他的生命週期了。

這裡的範例可以參考:https://github.com/KHeresy/Boost.DLL.Example/tree/SharedLibrary


這部分就先寫到這裡了,預計關於 Boost.DLL 的部分,之後應該還會有一篇吧?

不過,老實說,自己在寫這篇的時候拖了很久、時間拉得很長,很多地方用語應該有不一致的地方,這點就尚請見諒了。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *