最近看到許多linux的新一點的project許多都使用dynamic linking來架構其C程式,其中dlopen這個系列雖然是很lightweight但是卻十分好用,幾年前看到dlopen的使用便覺得很酷,因此寫一個粗淺的文章來談談dlopen library。

不了解dynamic linking library嗎?我想一個例子便是Microsoft的COM架構,這類的方式有許多好處,首先是對於軟體設計人員可以更自由的與其他人開發的library獨立開發。這裡要知道的是他確實是dynamic的來連結,一般的library的linking多是在linker的階段完成,也就是說在你執行ld的時候(或是由gcc呼叫ld)便將library與執行檔的symbol link完成。因此就算你是用shared library依然在link stage後便會與特定的library有連結。

原本這樣的做法很OK,但是隨著軟體設計的彈性需求越來越被重視,一個問題開始出現:我們是不是可以在程式執行時期再來決定library的symbol link。因此一堆相對應的方式開始產生,Microsoft的COM元件便是很成功的一個方案,然而早期在linux卻苦無解決方案,直到dlopen這個library的出現。

其實他很簡單,大多數的動作都可以只用3個function便可以做完,分別是dlopen、dlsym與dlclose。dlopen當然是用來開啟一個動態連結的library,dlsym用來載入相關的symbol link,dlclose用來關閉library。我想這樣應該是有點難以了解,因此我們用一個簡單的例子來說明吧。假設我們有些情況需要求出一個連續整數的平方和,有時候卻要求立方和,現在假設求完和後的程式就跟求平方和或立方和的運算無關了,而且或許未來有4次方和或更高次方的需求,我想這是個可以考慮用dlopen來解決的狀況(好啦...這個例子太殺雞用牛刀...不過只是為了說明....睜隻眼閉隻眼吧)。

首先我們必須先定義好我們的dynamic linking library的interface,因此我們寫下了定義的include檔如下
struct integer_list {
struct integer_list *next;
int num;
};

typedef void(*show_info)();
typedef int(*begin_calc)(struct integer_list *l);

typedef struct _func_plugin
{
show_info info;
begin_calc calc;
} func_plugin;

typedef func_plugin*(*get_plugin_interface)();
首先,因為我們要有一串未定長度的整數,因此我們用linked list來儲存他(這時候就會很懷念C++ STL的vector),這個介面只需要一個計算的function,但為了說明清楚一點,我們再給他一個秀出自己訊息的function。將他包在一個結構中後,在定義一個回傳symbol的function就可以。

當我們要用到這些動態的library的時候,我們可以用剛剛提到的3個function來處理,這裡我定義一個function來計算如下
int use_plugin(char *plugin_file, struct integer_list *n)
{
void* plugin;
func_plugin *f;
int result=-1;

plugin = dlopen(plugin_file, RTLD_NOW);
if (!plugin)
{
printf("Open plugin error\n");
return -1;
}
get_plugin_interface get_func;
get_func = (get_plugin_interface) dlsym(plugin, "get_plugin");

if (!get_func)
{
printf("dlsym error\n");
dlclose(plugin);
return -1;
}

f = get_func();
f->info();
result = f->calc(n);

dlclose(plugin);

return result;
}
你可以看到這個函數接受兩個參數,一個是我們要使用的library的位置,另一個是我們要計算的整數列,軟體開發者在開發階段已經可以利用dl library將程式編譯成執行檔而不用去在意library的實作,當然你在程式要去輸入你要使用的library位置(command-line參數或設定檔....隨你高興吧)。

最後是我們怎麼完成一個獨立的library的時候了,一個簡單的做法如下
#include 
#include
#include
#include "func_plugin.h"

void sqar_sum_info()
{
printf("This plugin is about square sum\n");
}

int sqar_sum_calc(struct integer_list *l)
{
int result=0;
struct integer_list *tmp = l;

while(tmp != NULL)
{
result += (tmp->num * tmp->num);
tmp = tmp->next;
}

return result;
}

func_plugin square_sum_plugin =
{
sqar_sum_info,
sqar_sum_calc
};

func_plugin *get_plugin()
{
return &square_sum_plugin;
}
很簡單吧,你只要去真正實作介面定義的函式便好,因此假設我們這個程式檔叫作square_sum.c,我們可以這樣製造出我們要的library
gcc -shared -fPIC -W1,-soname,libsqr_sum.so -o libsqr_sum.so square_sum.c 
這樣一來我們的簡單示範就完成啦,因此你可以發現你可以任意替換掉計算的部份,只要你傳入不同的library進去。下次要開始你的project之前或許先想想是否有一些部份也是有這方面需求,試試dl library來完成你複雜的架構吧。不過.....台灣的軟體開發好像最不給開始的規劃時間....ㄏㄏ.....算了,engineer們,玩的高興就好。

轉貼自:http://sites.google.com/site/joepasscheng/dynamiclink
arrow
arrow
    全站熱搜

    cloudfly 發表在 痞客邦 留言(0) 人氣()