當在Windows加載共享庫時自動執行功能,LoadLibrary()
調用導致DllMain
庫執行爲每個新進程和線程庫重視,併爲每個進程和線程庫deattaches。加載共享庫
是否有類似的機制,適用於Mac OS X,Linux和其他可能的POSIX兼容的操作系統?
當在Windows加載共享庫時自動執行功能,LoadLibrary()
調用導致DllMain
庫執行爲每個新進程和線程庫重視,併爲每個進程和線程庫deattaches。加載共享庫
是否有類似的機制,適用於Mac OS X,Linux和其他可能的POSIX兼容的操作系統?
您可以定義一個帶載功能使用.init
機制的Linux庫。這與指定二進制文件的加載時間入口點相同(例如,使用除main以外的內容作爲程序的入口點)。
當使用ld
鏈接直接使用:
-init <function name>
,或者如果你正在使用CC/gcc的鏈接,您可以使用:
-Wl,-init,<function name>
這是在它的最簡單的層面。
編輯 對於析構函數/終結器,可以使用.fini
機制。這個工作在相同的方式初始化選項,並使用:
-fini <function name>
調用ld
時。可用性僅限於Mac OSX平臺上的-init
選項。
你也應該能夠使用__attribute__((constructor))
語法GCC:
static void con() __attribute__((constructor));
void con() {
printf("I'm a constructor\n");
}
這可能是一個更便攜的方式,而不是與連接選項擰緊。所有構造函數應在加載時被調用,但不取決於他們的初始化順序,導致精神錯亂和不可再現的錯誤,成本時間和精力去調試上。
編輯2語義的使用__attribute__((constructor))/__attribute__((destructor))
是C/C++編程語言的最佳機制。
對於你真的應該使用靜態模塊構造函數/析構函數D
編程語言:
static this() {
printf("static this for mymodule\n");
}
static ~this() {
printf("static ~this for mymodule\n");
}
還是靜態類的構造函數:
class Foo {
static this() {
printf("static this for Foo\n");
}
}
這是在writing win32 DLLS和強烈暗示語言規範relating to static constructors/destructors。
編輯3您將需要在.o
鏈接導出構造函數/析構函數例程,這將允許使用靜態初始值設定項。因爲它應該做的就是調用Runtime.initialize(),這實際上調用D
代碼中的所有靜態構造函數/析構函數。用於初始化
存根d代碼(在一個名爲myshared.d
):
dmd -m32 -c myshared.d
檢查的附加/分離功能的名稱:
import core.runtime;
extern (C) {
void attach();
void detach();
}
export void attach() {
Runtime.initialize();
}
export void detach() {
Runtime.terminate();
}
這個存根創建的.o: (其他輸出):
用於調用這個(在這種情況下,所謂的export.c)0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv
樣本.C代碼,我們引用了出口程序的名稱從my shared.o
文件:
extern void D8myshared6attachFZv(void);
extern void D8myshared6detachFZv(void);
void __attach(void) __attribute__((constructor));
void __detach(void) __attribute__((destructor));
void __attach(void)
{
D8myshared6attachFZv();
}
void __detach(void)
{
D8myshared6detachFZv();
}
注意,extern void
引用需要使用導出函數的重名名稱。這些必須匹配或代碼不會鏈接。
使用編譯的C代碼:
gcc -m32 -c export.c
鏈接.c.o一起使用.d.o文件:
cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2
假設phobos2庫是在標準連接器的搜索路徑。編譯器和鏈接器的-m32
選項的差異是因爲我在本地構建的D編譯器的版本只支持32位。
這產生了一個可以鏈接到的.dylib。它似乎基於我執行的有限測試工作。看起來對共享對象/動態庫的支持非常有限,所以很有可能會有另一個障礙需要克服。
看來你的解決方案對我來說是最可以接受的,因爲我用D編寫而不用C編寫,而且你的解決方案不涉及GCC特定的東西。在這些構造函數和析構函數中唯一要調用的是D運行時初始化和終止。 – toriningen 2012-03-18 17:18:39
你還可以提示,指定析構函數的ld標誌是什麼? – toriningen 2012-03-18 17:20:13
終結器/析構函數的等價物是使用-fini <函數名稱>選項。 – Petesh 2012-03-18 21:03:41
要具有每當共享庫加載或卸載執行的功能,則可以使用特定GCC-屬性語法標記構造和析構函數:
__attribute__((constructor)) void init(void) { ... }
__attribute__((destructor)) void fini(void) { ... }
因爲一個C環境的各個部分依賴於事被GCC在後臺添加的標準.init
代碼初始化後,直接使用-Wl,-init,<function name>
可能會導致你的程序崩潰。
欲瞭解更多信息,請參閱Library constructor and destructor functions的Libary HOWTO。
GCC和clang AFAIK支持GCC構造函數和析構函數屬性。有關更多詳細信息,請參閱How exactly does __attribute__((constructor)) work?
對於C++,您可以創建一個類並使用其構造函數和析構函數初始化該庫。
之後,你只需要爲這個類定義一個變量。在圖書館
實例初始化的OpenSSL:
class InitLibrary {
public:
InitLibrary() {
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
}
~InitLibrary() {
ERR_remove_state(0);
CRYPTO_cleanup_all_ex_data();
ENGINE_cleanup();
}
};
和只添加這行CPP文件: InitLibrary InitLib;
https://stackoverflow.com/q/2053029/4361073 – parasrish 2018-01-08 10:07:35