动态链接库的生成和使用(二)
1、生成动态库文件libtest.so
Demo目录下创建testso文件夹,在下面创建test.cpp、test.h和Makefile文件
test.cpp:
#include <stdio.h>
#include <stdlib.h>
extern "C"
double calc_pi()
{
double x = 0;
double y = 0;
double pi = 0;
int num = 0;
int iter = 0;
const int try_times = 10000000;
const double max_val = 32767.0;
while (iter++ <= try_times)
{
x = (double)(rand() % 32768) / max_val;
y = (double)(rand() % 32768) / max_val;
if ((x * x + y * y) <= 1)
num++;
}
pi = (4.0 * num) / try_times;
return pi;
}
test.h
extern "C"
double calc_pi();
Makefile文件
EXECUTABLE:= libtest.so
LIBDIR:=
LIBS:=
INCLUDES:=.
SRCDIR:=
CC:=g++
CFLAGS:= -g -fPIC -Wall -O0
CPPFLAGS:= $(CFLAGS)
CPPFLAGS+= $(addprefix -I,$(INCLUDES))
CPPFLAGS+= -I.
CPPFLAGS+= -MMD
RM-F:= rm -f
SRCS:= $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS:= $(patsubst %.cpp,%.o,$(SRCS))
DEPS:= $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS:= $(filter-out $(wildcard $(DEPS)),$(DEPS))
.PHONY : all deps objs clean
all:$(EXECUTABLE)
deps:$(DEPS)
objs:$(OBJS)
clean:
@$(RM-F) *.o
@$(RM-F) *.d
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS):
@$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
$(CC) -shared -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))
这个Makefile文件定义了一个用于构建共享库(libtest.so
)的构建系统。下面是对Makefile中各个部分的解释:
-
变量定义:
EXECUTABLE
:定义了最终生成的动态库文件的名称,这里是libtest.so
。LIBDIR
:库文件搜索目录,这里没有指定,默认为空。LIBS
:链接时需要的库,这里没有指定,默认为空。INCLUDES
:头文件搜索目录,这里设置为当前目录(.
)。SRCDIR
:源文件搜索目录,这里没有指定,默认为空。CC
:编译器,这里设置为g++
。CFLAGS
:编译器标志,包括调试信息(-g
)、生成位置无关代码(-fPIC
)、开启所有警告(-Wall
)、优化等级为0(-O0
)。CPPFLAGS
:预处理器标志,这里包括了CFLAGS
和头文件搜索路径。
-
模式规则:
RM-F
:定义了一个删除文件的命令,使用rm -f
。SRCS
:定义了所有源文件(.cpp
),包括当前目录和SRCDIR
目录下的源文件。OBJS
:定义了所有目标文件(.o
),由源文件名转换而来。DEPS
:定义了所有依赖文件(.d
),由目标文件名转换而来。MISSING_DEPS
:找出缺失的依赖文件。
-
目标规则:
.PHONY
:声明了all
、deps
、objs
和clean
为伪目标。all
:默认目标,依赖于$(EXECUTABLE)
,即构建最终的库文件。deps
:依赖于$(DEPS)
,即生成所有依赖文件。objs
:依赖于$(OBJS)
,即编译所有源文件生成目标文件。clean
:清理目标,删除所有生成的目标文件和依赖文件。
-
条件判断:
ifneq ($(MISSING_DEPS),)
:如果存在缺失的依赖文件,则对每个缺失的依赖文件执行删除对应目标文件的操作。
-
包含依赖:
-include $(DEPS)
:包含所有依赖文件,这样Makefile就可以根据这些文件来确定何时需要重新编译。
-
最终构建命令:
$(EXECUTABLE)
:构建目标,依赖于所有目标文件$(OBJS)
。使用$(CC)
编译器,-shared
标志来生成共享库,链接时可能还会包含库目录和库文件。
Demo目录下执行make命令,可以生成libtest.so 动态库文件。
2、使用动态库文件libtest.so
Demo目录下创建testexe目录,在下面创建testexe.cpp和makefile文件
testexe.cpp:
#include <iostream>
#include "test.h"
using namespace std;
int main()
{
printf("1:call calc_pi 2:exit\n");
while(true)
{
int number = 0;
cin >> number;
switch(number)
{
case 1:
{
double pi = calc_pi();
cout << "pi is " << pi << endl;
break;
}
case 2:
return 0;
default:
break;
}
}
return 0;
}
makefile文件
EXECUTABLE:= testexe
LIBDIR:=../testso
LIBS:=test
INCLUDES:=../testso
SRCDIR:=
CC:=g++
CFLAGS:= -g -Wall -O0
CPPFLAGS:= $(CFLAGS)
CPPFLAGS+= $(addprefix -I,$(INCLUDES))
CPPFLAGS+= -I.
CPPFLAGS+= -MMD
RM-F:= rm -f
SRCS:= $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS:= $(patsubst %.cpp,%.o,$(SRCS))
DEPS:= $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS:= $(filter-out $(wildcard $(DEPS)),$(DEPS))
.PHONY : all deps objs clean
all:$(EXECUTABLE)
deps:$(DEPS)
objs:$(OBJS)
clean:
@$(RM-F) *.o
@$(RM-F) *.d
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS):
@$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))
相比前面生成动态库的makefile,这里的
EXECUTABLE
:定义了最终生成的可执行文件testexe
,
LIBDIR
:库文件搜索目录,设置为../testso目录
LIBS
:链接时需要的动态库名称,设置为test
INCLUDES
:头文件搜索目录,这里设置为../testso
生成testexe文件编译命令:
$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))
将动态库所在路径testso添加到LD_LIBRARY_PATH中
export LD_LIBRARY_PATH = ../testso:$LD_LIBRARY_PATH
3、调用动态库文件libtest.so
在Demo目录下创建dtest目录,其中创建t.cpp文件和Makefile文件
t.cpp
#include <dlfcn.h>
#include <iostream>
using namespace std;
typedef double (*CALC_PI)();
int main()
{
void* handle = dlopen("../testso/libtest.so",RTLD_NOW);
if(!handle)
{
cout << "can't open the dll libtest.so" <<endl;
return 0;
}
CALC_PI calc_pi =(CALC_PI) dlsym(handle,"calc_pi");
if(!calc_pi)
{
cout << "can't get the calc_pi" <<endl;
return 0;
}
double pi = calc_pi();
cout << "pi is " << pi << endl;
dlclose(handle);
return 0;
}
makefile
EXECUTABLE:= test
LIBDIR:=
LIBS:=dl
INCLUDES:=
SRCDIR:=
CC:=g++
CFLAGS:= -g -Wall -O0
CPPFLAGS:= $(CFLAGS)
CPPFLAGS+= $(addprefix -I,$(INCLUDES))
CPPFLAGS+= -I.
CPPFLAGS+= -MMD
RM-F:= rm -f
SRCS:= $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS:= $(patsubst %.cpp,%.o,$(SRCS))
DEPS:= $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS:= $(filter-out $(wildcard $(DEPS)),$(DEPS))
.PHONY : all deps objs clean
all:$(EXECUTABLE)
deps:$(DEPS)
objs:$(OBJS)
clean:
@$(RM-F) *.o
@$(RM-F) *.d
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS):
@$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))