大家都知道
在WINDOWS系統中有很多的動態鏈接庫(以
DLL為後綴的文件
DLL即Dynamic Link Library)
這種動態鏈接庫
和靜態函數庫不同
它裡面的函數並不是執行程序本身的一部分
而是根據執行程序需要按需裝入
同時其執行代碼可在多個執行程序間共享
節省了空間
提高了效率
具備很高的靈活性
得到越來越多程序員和用戶的青睐
那麼
在LINUX系統中有無這樣的函數庫呢?
答案是肯定的
LINUX的動態鏈接庫不僅有
而且為數不少
在/lib目錄下
就有許多以
so作後綴的文件
這就是LINUX系統應用的動態鏈接庫
只不過與WINDOWS叫法不同
它叫so
即Shared Object
共享對象
(在LINUX下
靜態函數庫是以
a作後綴的) X
WINDOW作為LINUX下的標准圖形窗口界面
它本身就采用了很多的動態鏈接庫(在/usr/X
R
/lib目錄下)
以方便程序間的共享
節省占用空間
著名的APACHE網頁服務器
也采用了動態鏈接庫
以便擴充程序功能
你只需將PHP動態鏈接庫拷到其共享目錄
修改一下配置
APACHE就可以支持PHP網頁了
如果你願意
可以自己編寫動態鏈接庫
讓APACHE支持你自己定義的網頁格式
這就是動態鏈接的好處
LINUX下動態鏈接庫的創建
在LINUX系統下
創建動態鏈接庫是件再簡單不過的事情
只要在編譯函數庫源程序時加上
shared選項即可
這樣所生成的執行程序即為動態鏈接庫
從某種意義上來說
動態鏈接庫也是一種執行程序
按一般規則
程序名應帶
so後綴
下面舉個例子說說
我准備編寫兩個函數
一個用於查詢當前日期getdate
一個用於查詢當前時間gettime
並將這兩個函數存於動態鏈接庫my
so中
為此
需要做以下幾項工作
編寫用戶接口文件datetime
h
內容如下(每行前面的數字為行號)
/* datetime
h : 縱橫軟件制作中心雨亦奇編寫
*/
#ifndef __DATETIME_H
#define __DATETIME_H
/* 日期結構 */
typedef struct
{
int year;
int mon;
int day;
}DATETYPE;
/* 時間結構 */
typedef struct
{
char hour;
char min;
char sec;
}TIMETYPE;
/* 函數原型說明 */
#ifdef SHARED
int (*getdate)(DATETYPE *d);
#else
int getdate(DATETYPE *d);
#endif
#ifdef SHARED
int (*gettime)(TIMETYPE *t);
#else
int gettime(TIMETYPE *t);
#endif
#endif
這個用戶接口文件中
先定義了日期與時間結構
接著定義一下函數的原型
動態函數與靜態函數的原型說明不同的是
動態函數應使用(*函數名)的形式
以便引用其指針
若要引用文件中的動態函數說明
用戶應該定義一下SHARED宏
這樣才能使用
編寫getdate
c
源程序如下
/* getdate
c : 縱橫軟件制作中心雨亦奇編寫
*/
#include
time
h
#include
datetime
h
int getdate(DATETYPE *d)
{
long ti;
struct tm *tm;
time(&ti);
tm=localtime(&ti);
d
>year=tm
>tm_year+
;
d
>mon=tm
>tm_mon+
;
d
>day=tm
>tm_mday;
}
在getdate函數中
先調用time取得以秒計的系統時間
再用localtime函數轉換一下時間結構
最後調整得到正確的日期
編寫gettime
c
源程序如下
/* gettime
c : 縱橫軟件制作中心雨亦奇編寫
*/
#include
time
h
#include
datetime
h
int gettime(TIMETYPE *t)
{
long ti;
struct tm *tm;
time(&ti);
tm=localtime(&ti);
t
>hour=tm
>tm_hour;
t
>min=tm
>tm_min;
t
>sec=tm
>tm_sec;
}
gettime函數與getdate函數相仿
先用time函數取得以秒計的系統時間
再用localtime函數轉換一下時間結構
最後返回當前的時間(不需調整)
編寫維護文件makefile
lib
內容如下
# makefile
lib : 縱橫軟件制作中心雨亦奇編寫
all : my
so
SRC = getdate
c gettime
c
TGT = $(SRC:
c=
o)
$(SRC) : datetime
h
@touch $@
%
o : %
c
cc
c $?
# 動態函數庫(my
so)生成
my
so : $(TGT)
cc
shared
o $@ $(TGT)
編寫維護文件的目的
在於方便程序員維護程序
尤其是維護比較大的工程項目
一個素質良好的程序員應該學會熟練地編寫維護文件makefile
定義了文件間的依賴關系後
一旦源文件發生變化
僅需make一下
其目標文件維護代碼會自動執行
從而自動更新目標文件
減少了許多工作量
注意: 每行維護代碼必須以TAB(跳格鍵)開始
不是的話make時將出錯
本維護文件第
行是注釋行
以#號開頭
文件第
行定義所有需要維護的函數庫
第
行定義相關源程序文件
第
行定義目標文件
第
行說明所有源程序依賴於datetime
h頭文件
並有相應維護代碼
即touch一下
更新一下源文件的時間
第
行定義
o文件依賴於相應的
c文件
並指定了維護代碼
即用cc編譯一下
第
行定義共享庫my
so依賴的目標文件
維護代碼中用
shared編譯選項
以生成動態鏈接庫my
so
運行make
f makefile
lib 命令
make運行後
動態鏈接庫my
so就產生了
我們就可以在程序中調用了
如果想讓系統所有用戶都可以使用
則應以root用戶登錄系統
將這個庫拷貝到/lib目錄下(命令
cp my
so /lib)
或者在/lib目錄下建個符號連接即可(命令
ln
s `pwd`/my
so /lib)
LINUX下動態鏈接庫的使用
重要的dlfcn
h頭文件
LINUX下使用動態鏈接庫
源程序需要包含dlfcn
h頭文件
此文件定義了調用動態鏈接庫的函數的原型
下面詳細說明一下這些函數
dlerror
原型為: const char *dlerror(void);
當動態鏈接庫操作函數執行失敗時
dlerror可以返回出錯信息
返回值為NULL時表示操作函數執行成功
dlopen
原型為: void *dlopen (const char *filename
int flag);
dlopen用於打開指定名字(filename)的動態鏈接庫
並返回操作句柄
filename: 如果名字不以/開頭
則非絕對路徑名
將按下列先後順序查找該文件
(
) 用戶環境變量中的LD_LIBRARY值
(
) 動態鏈接緩沖文件/etc/ld
so
cache
(
) 目錄/lib
/usr/lib
flag表示在什麼時候解決未定義的符號(調用)
取值有兩個:
) RTLD_LAZY : 表明在動態鏈接庫的函數代碼執行時解決
) RTLD_NOW : 表明在dlopen返回前就解決所有未定義的符號
一旦未解決
dlopen將返回錯誤
dlopen調用失敗時
將返回NULL值
否則返回的是操作句柄
dlsym : 取函數執行地址
原型為: void *dlsym(void *handle
char *symbol);
dlsym根據動態鏈接庫操作句柄(handle)與符號(symbol)
返回符號對應的函數的執行代碼地址
由此地址
可以帶參數執行相應的函數
如程序代碼: void (*add)(int x
int y); /* 說明一下要調用的動態函數add */
add=dlsym(
xxx
so
add
); /* 打開xxx
so共享庫
取add函數地址 */
add(
); /* 帶兩個參數
和
調用add函數 */
dlclose : 關閉動態鏈接庫
原型為: int dlclose (void *handle);
dlclose用於關閉指定句柄的動態鏈接庫
只有當此動態鏈接庫的使用計數為
時
才會真正被系統卸載
在程序中使用動態鏈接庫函數
程序范例
下面的程序裝載了動態鏈接庫my
so
並用getdate
gettime取得當前日期與時間後輸出
/************************************/
/* 文件名稱: dy
c */
/* 功能描述: 動態鏈接庫應用示范程序 */
/* 程序編寫: 縱橫軟件制作中心雨亦奇 */
/* 編寫時間:
*/
/************************************/
#include
stdio
h
/* 包含標准輸入輸出文件 */
#include
From:http://tw.wingwit.com/Article/program/Oracle/201311/17429.html