存在不相容的函式
控制linux動態庫的匯出函式
使用linux動態庫
靜態載入
其他問題
第一次嘗試匯出linux動態庫,包裝log4cpp,遇到的問題做個記錄。
在官網上下下來包過後,官網的安裝說明不全:
// stdcall & cdecl
#if defined(_msc_ver) || defined(_win32) || defined(_win64)
#define tce_api __stdcall
// tcelogger_dll_exports
#ifdef tcelogger_dll_exports
#define dll_api __declspec(dllexport)
#else
#define dll_api __declspec(dllimport)
#endif
#else
#define tce_api
#define dll_api
#endif
主要是linux:
args… 對應 ##args // qt會提示這種表示是gnu擴充套件
windows:
… 對應 ##__va_args__
// linux下:
#define info(logformat, args...) info(__function__, __line__, logformat, ##args)
// windows下:
#define info(logformat, ...) info(__function__, __line__, logformat, ##__va_args__)
參考:
發現有的函式是windows平台的。sprint_s是windows平台下執行緒安全的格式化字串函式並非標準c函式,因此linux下無法使用,但可以使用snprintf函式代替。
int
snprintf
(char
*dest, size_t n,
const
char
*fmt,..
.);// 函式原型相同,替換即可
#define sprintf_s snprintf
windows下通過__declspec(dllexport)來宣告dll動態庫匯出的介面(函式或類),__declspec(dllimport)來宣告為動態庫載入的介面。linux下不可用。
linux下,gcc幫助文件 -fvisibility=default|internal|hidden|protected 引數下有這麼一段話:
總結是:
linux下原始檔中的所有函式都有乙個預設的visibility屬性,預設為public,即預設匯出。如果要隱藏,則在gcc編譯指令中加入-fvisibility=hidden引數,會將預設的public屬性變為hidden。
隱藏函式匯出後,所有的匯出都隱藏,再在原始碼中,在需要匯出的函式前新增 __attribute__ ((visibility(「default」))) ,使其仍按預設的public屬性處理。
檢視檔案屬性:
檢視匯出函式:
linux提供4個庫函式、乙個標頭檔案dlfcn.h以及兩個共享庫(靜態庫libdl.a和動態庫libdl.so)支援動態鏈結。
dlsym:返回鎖請求的入口點的指標
dlerror:返回null或者指向描述最近錯誤的字串
dlclose:關閉動態共享檔案
使用linux的庫,使用方法和windows下一致。
#include
#include
#include
"tcelogger.h"
using
namespace std;
using
namespace tce;
// declare function pointer
typedef tcelogger&
(*type_pso_tlgi)
(void);
intmain()
// use dlsym to get function address (in windows getprocaddress)
type_pso_tlgi pso_tlgi =
(type_pso_tlgi)
dlsym
(pso_handle,
"tceloggergetinstance");
if(!pso_tlgi)
// use function to get instance
tcelogger& logger =
pso_tlgi()
; logger.
info
("ok");
return0;
}
動態載入cmakelist
動態載入時,需要使用dl庫,在cmakelist中新增鏈結dl庫。
cmake_minimum_required
(version 2.8
)project
(socaller)
// 設定debug模式
set(cmake_build_type debug)
//設定c++11
set(cmake_cxx_flags "$ -std=c++11"
)// qt工程中顯示**件
file
(glob_recurse libfiles "tcelogger.h"
)add_custom_target
(headers sources $
)// 設定include目錄
include_directories($)
// 設定庫目錄
link_directories($)
// 設定生成內容
add_executable
($"socaller.cpp"
)// 設定要鏈結的庫
target_link_libraries
($ dl
tcelogger //當靜態載入時直接鏈結
)
參考:
在cmakelist中設定鏈結該動態庫後,幷包含標頭檔案,可以直接使用。
// 使用動態庫匯出的c介面函式獲取例項
tcelogger& tcelogger =
tceloggergetinstance()
;tcelogger.
crit
("ok");
return
0;
在cmakelist中新增set(cmake_build_type debug)
在用測試demo debug時發現,dlopen失敗報錯是沒有找到log4cpp.so,原來是生成so時,鏈結的log4cpp庫沒有字尾:
target_link_libraries
($ log4cpp)
這樣會預設鏈結動態庫log4cpp.so,修改為
target_link_libraries
($ log4cpp.a)
修改鏈結log4cpp.a靜態庫後,報錯relocation r_x86_64_32 against `.rodata』 can not be used when ****** a shared object。
原因是如果將編譯的靜態庫鏈結進動態庫使用,也就是我的應用情景,需要在編譯靜態庫時,加上編譯指令 -fpic 。
因此在log4cpp原始碼的cmakelist中,增加指令:
set
(cmake_cxx_flags "$ -fpic"
)
然後不使用configure,直接cmake make,生成靜態庫,解決。
參考:cmakelist 編寫規則:
target_link_libraries
($ pthread)
解決問題。 so動態庫的成及測試
so檔案是是elf格式檔案,共享庫 動態庫 類似於dll。節約資源,加快速度,公升級簡化。例子中測試檔案的生成 gcc g ts.c o ts l.ls 一下是例子 先寫乙個c檔案 s.c 1.include 2.int count 3.void out msg const char m 4.6.測...
靜態庫 a和動態庫 so生成及呼叫
gcc編譯器工具一般位於 usr bin或者 usr local bin目錄,但它會從其它位置執行各種編譯器支援的應用程式,這個位置可能是 usr lib gcc lib 目錄,gnu c c 編譯器的各個工具和gnu專用標頭檔案都儲存在這裡。標頭檔案,一般位於 usr include,包含標頭檔案...
so檔案動態替換方法及Linux動態庫的用法
在替換so檔案時,如果在不停程式的情況下,直接用 cp new.so old.so 的方式替換程式使用的動態庫檔案會導致正在執行中的程式崩潰。解決的辦法是採用 rm cp 或 mv cp 來替代直接 cp 的操作方法。linux系統的動態庫有兩種使用方法 執行時動態鏈結庫,動態載入庫並在程式控制之下...