前面我們在編譯可執行文件時,如果可執行文件要依賴某個so。必須要通過-L指定so路徑,並且-l指定so名字。
而且在可執行文件運行時,要先加載so的load部分到進程地址空間。
有一種方式可以在編譯時不需要link so, 而且程序運行過程中去加載so。
dlopen函數可以在進程運行過程中,打開so,將其加載到進程的地址空間,並完成初始化過程。
如果dlopen中指定的路徑是相對路徑,那么按照LD_LIBRARY_PATH,/etc/ld.so.cache,/lib,/usr/lib順序查找。否則直接打開so。
dlsym返回so的符號的值,如果符號是函數和變量,返回符號和變量的地址;如果符號是常量,就返回常量的值。
我們在前面寫的消息隊列msgsnd.c代碼中稍作修改,以運行時加載libmsg.so。代碼如下:
#include <sys/prctl.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include "msg.h"
#define MSG_CREAT_PATH "/mnt/hgfs/share/test/list"
#define MSG_RCV_ID 4
#define MSG_SND_ID 3
typedef int (*create_msg_queue)(const char *path, int proj_id);
typedef int (*rcv_msg)(int id, FellowMsg *msg);
typedef int (*snd_msg)(int id, FellowMsg *msg);
typedef struct _MsgIf{
create_msg_queue create;
rcv_msg rcv;
snd_msg snd;
}MsgIf;
MsgIf msgIf;
void *fellow_listenning_msg(void *arg)
{
if(0 != prctl(PR_SET_NAME, (unsigned long)"fellow_process_msg"))
{
printf("prctl fail, errno:%d", errno);
}
int msg_q_id = msgIf.create(MSG_CREAT_PATH, MSG_RCV_ID);
FellowMsg _fellowMsg;
while (1)
{
memset(&_fellowMsg, 0, sizeof(FellowMsg));
msgIf.rcv(msg_q_id, &_fellowMsg);
if (CTRL_FEEDBACK ==_fellowMsg._msgType)
{
switch (_fellowMsg._ctlInfo.u._ctlFeedback)
{
case OPEN_DONE:
printf("rcv OPEN_DONE:%d\n", _fellowMsg._ctlInfo.param);
break;
case CLOSE:
printf("rcv CLOSE_DONE:%d\n", _fellowMsg._ctlInfo.param);
break;
case PLAY:
printf("rcv PLAY_DONE:%d\n", _fellowMsg._ctlInfo.param);
break;
default:
break;
}
}
}
}
void main(void)
{
void *handle = dlopen("/mnt/hgfs/share/test/msg/libmsg.so", RTLD_NOW);//打開libmsg.so
if (NULL == handle)
{
printf("dlopen fail:%s\n", dlerror());
return;
}
msgIf.create = (create_msg_queue)dlsym(handle, "fellow_create_msg_queue");//獲取符號的值。
msgIf.rcv = (rcv_msg)dlsym(handle, "fellow_rcv_msg");
msgIf.snd = (snd_msg)dlsym(handle, "fellow_send_msg");
pthread_t thread_id;
int snd_msg_q_id = msgIf.create(MSG_CREAT_PATH, MSG_SND_ID);
printf("msgid:%d\n",snd_msg_q_id);
FellowMsg _fellowMsg;
_fellowMsg._msgType = CTRL_CMD;
_fellowMsg._ctlInfo.u._ctlCmd = OPEN;
_fellowMsg._ctlInfo.param = 1;
printf("create:%p, snd:%p, rcv:%p\n", msgIf.create, msgIf.snd,msgIf.rcv);
msgIf.snd(snd_msg_q_id, &_fellowMsg);
pthread_create(&thread_id, NULL, fellow_listenning_msg, NULL);
while (1)
{
}
dlclose(handle);
}
那么在編譯時我們不需要link so: gcc msgsnd.c -o msgsnd -ldl -pthread