使用visibility
#ifdef __cplusplus //如果是C++語言
#define PASSPORT_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define PASSPORT_EXTERN extern __attribute__((visibility ("default")))
#endif
GNU C 的一大特色就是attribute 機制。
試想這樣的情景,程序調用某函數A,A函數存在於兩個動態鏈接庫liba.so,libb.so中,並且程序執行需要鏈接這兩個庫,此時程序調用的A函數到底是來自於a還是b呢?
這取決於鏈接時的順序,比如先鏈接liba.so,這時候通過liba.so的導出符號表就可以找到函數A的定義,並加入到符號表中,鏈接libb.so的時候,符號表中已經存在函數A,就不會再更新符號表,所以調用的始終是liba.so中的A函數。
爲了避免這種混亂,所以使用
__attribute__((visibility("default"))) //默認,設置爲:default之後就可以讓外面的類看見了。
__attribute__((visibility("hideen"))) //隱藏
設置這個屬性。
visibility
用於設置動態鏈接庫中函數的可見性,將變量或函數設置爲hidden
,則該符號僅在本so中可見,在其他庫中則不可見。
g++在編譯時,可用參數-fvisibility
指定所有符號的可見性(不加此參數時默認外部可見,參考man g++中-fvisibility部分);若需要對特定函數的可見性進行設置,需在代碼中使用attribute設置visibility屬性。
編寫大型程序時,可用-fvisibility=hidden
設置符號默認隱藏,針對特定變量和函數,在代碼中使用attribute ((visibility("default")))
另該符號外部可見,這種方法可用有效避免so之間的符號衝突。
經測試,C++會導出函數參數,C的方式不會,兩者不能通用。
使用version-script
set_target_properties(your_so_or_exe PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/symbol.version")
symbol.version:
{
global:JNI_OnLoad;JNI_OnUnload;Java_*;usedFun;
local:*;
};