动态链接库的使用记录

1. 编译参数

1.1 -fPIC

告诉编译器产生与位置无关代码.如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy。每个copy都不一样,取决于这个.so文件代码段和数据段内存映射的位置。不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码) 如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了。

1.1 -rdynamic

1、是一个链接器选项,当将所有的*.o和库链接到最终可执行文件中就使用了它。该参数的作用是:将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号,但不包括静态符号,比如被static修饰的函数)都添加到动态符号表(即.dynsym表)里,以便那些通过dlopen()或backtrace()(这一系列函数使用.dynsym表内符号)这样的函数使用。

2 动态链接库使用函数如下

//编译时候要加入 -ldl (指定dl库)

//包含的头文件
#include   


void *dlopen(const char *filename, int flag);
//dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄
//参数filename是共享库文件的路径,可以是相对路径或绝对路径。参数flag用于指定打开方式,常用的取值包括RTLD_NOW(立即解析所有符号)、RTLD_LAZY(懒加载,只有当使用时才解析符号)等。
mode: 参数必须包括以下两个值中的一个
RTLD_LAZY 暂缓决定,等有需要时再解出符号 
RTLD_NOW 立即决定,返回前解除所有未决定的符号。 

mode也可以通过以下零或多个值进行或运算设置
RTLD_LOCAL 
RTLD_GLOBAL 允许导出符号 
RTLD_GROUP 
RTLD_WORLD 

void *dlsym(void *handle, const char *symbol);  
//根据动态链接库操作句柄与符号,返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数或全局变量的名称.

int dlclose(void *handle);
//用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

char *dlerror(void);
//当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

3. 动态库函数的使用demo记录

3.1 动态库demo的头文件和源文件 

3.1.1 libdemo.h头文件

#ifndef _LIBDEMO_H_
#define _LIBDEMO_H_

#include 

typedef struct 
{
	int val;
}Val_t;

extern void add(Val_t* addval);
extern int getVal(void);

#endif

3.1.2  libdemo.c 文件

#include "libdemo.h"

int g_libValue = 0;

void add(Val_t *addval) 
{
    g_libValue += addval->val;
}

int getVal(void) 
{
    return g_libValue;
}

3.1.3 makefile 简易编写

src=$(wildcard  ./*.c)  #把所有以.c文件 匹配上,并把文件名提取出来,作为一个列表赋值给src
object=$(patsubst %.c,%.o,$(src)) #将src里的每个文件都由.c替换成.o
target1=libdemo0.so                   #库文件
target2=libdemo1.so
CC=gcc
CFLAGS=-I./ -shared -fPIC                #头文件参数、动态链接编译参数

all:$(target1)

$(target1):$(object)
	$(CC) -o $@ $^ $(CFLAGS)             #生成动态库文件
	cp $(target1) $(target2)             #拷贝一个一样的动态库

#参数解释, $@表示目标文件

#参数解释, $^表示所有的依赖文件

#参数解释, $<表示第一个依赖文件


%.o:%.c
	$(CC) -o $@ -c $< $(CFLAGS)           #生成obj文件

.PHONY:clean

clean:
	rm -f $(target1) $(target2) $(object)  #清除动态库文件和obj文件

3.2 应用层调用头文件和源文件

3.2.1 appldemo.h头文件

#ifndef _APPL_DEMO_H_
#define _APPL_DEMO_H_

#include "libdemo.h"


//调用动态库操作函数
typedef struct
{
	void (*p_add)(Val_t*);
	int (*p_getval)(void);
} SharedObjOps_t;


extern int SharedObjInit(int id, SharedObjOps_t*op);

#endif

3.2.2 appldemo.c源文件

#include 
#include 
#include 
#include 


#define FILE_PATH_NAME	"../lib/libdemo"


/*
* brif :调用动态库初始化函数
*/
int SharedObjInit(int id, SharedObjOps_t*op)
{
	char filePathName[128] = FILE_PATH_NAME;
	char idnum[10]     = {0};
	char filetype[10]  = ".so";
	char file[128]     = {0};
	void *handle;                   //库文件句柄

	strcat(file, filepath);

	sprintf(idnum, "%d", id);
	strcat(file, idnum);
	strcat(file, filetype);

	handle = dlopen(file, RTLD_LAZY); //打开动态库,且为暂缓决定,等有需要时再解出符号 

    if (handle == NULL) 
    {
        return 1; //打不开库
    }

    op->p_add= dlsym(handle, "add");
    op->p_getval= dlsym(handle, "getval");

    if(!op->p_add || !op->p_getval)
    {
    	return 2; //找不到其中的库函数
    }

    return 0;
}



int main() 
{
	SharedObjOps_t op0, op1; //两个动态库操作函数结构体句柄
	Val_t val0 = {0}, val1 = {0};
     
    //分别初始化两个动态库
    if(SharedObjInit(0, &op0)) 
    {
    	return 1; //失败
    }
    if(SharedObjInit(1, &op1))
    {
    	return 1; //失败
    }

    val0.val = 10;
    val0.val = 20;

    op0.p_add(&val0);
    op1.p_add(&val1);

    printf("op0's g_libValue returned: %d\n", op0.p_getval());
    printf("op1's g_libValue returned: %d\n", op1.p_getval());


    val0.val = 1;
    val1.val = 2;

    op0.p_add(&val0);
    op1.p_add(&val1);

    printf("op0's g_libValue returned: %d\n", op0.p_getval());
    printf("op1's g_libValue returned: %d\n", op1.p_getval());

    return 0;
}

3.2.3  Makefile编写

src=$(wildcard  ./*.c)
object=$(patsubst %.c,%.o,$(src))
target=appdemo
CC=gcc
CFLAGS=-I./ -I../lib -ldl

all:$(target)

$(target):$(object)
	$(CC) -o $@ $^ $(CFLAGS)

%.o:%.c
	$(CC) -o  $@ -c $< $(CFLAGS)

.PHONY:clean

clean:
	rm -f $(target) $(object)

你可能感兴趣的:(Linux/MCU/MPU,动态链接,makefile)