windows和ubuntu下显式调用dll库文件的异同
除了将dll库文件作为一部分参与主程序编译之外,显式的调用库文件也是一种灵活的使用方式。
调用dll库文件依赖于系统,所以不同的系统下是不同的。
像c++这种静态编译程序就要注意这样的不同,而python这种动态程序由于解释器已经做了处理则可以忽略系统的差异。本文就讨论一下这些内容:
1. c++程序显式调用库文件
c++程序显式的调用库文件,就是在程序中显式的打开库文件,并定位和使用其中的函数。
1.1 windows下的调用
下面的c++源程序是典型的windows系统下dll显式调用程序:
#include <iostream>
#include <stdio.h>
#include <windows.h>
using namespace std;
typedef double (*WinrateFunc)(int, int,int,int, int, int, int, int, int);
typedef void (*Wrlibinit)();
/* main.cpp */
int main(){
//动态加载Dlltest.dll文件
HINSTANCE hDll;
hDll= LoadLibrary(TEXT("libwinrate.so"));
//测试是否能够正确输出
//printf("%s\n","absededeedd");
//cout<<"absededeedd"<<endl;
if (hDll != NULL)
{
WinrateFunc getwinrate = (WinrateFunc)GetProcAddress(hDll, "get_winrate");
Wrlibinit getwrinit = (Wrlibinit)GetProcAddress(hDll, "compinit");
if (getwinrate != NULL) {
getwrinit();
double wr=getwinrate(2,5,24,37,15,18,45,51,34);
cout<<"wr="<<wr<<" true val="<<0.2631<<endl;
wr=getwinrate(2,0,10,52,0,0,0,0,0);
cout<<"wr="<<wr<<" true val="<<0.5672<<endl;
wr=getwinrate(2,4,21,39,29,17,26,1,0);
cout<<"wr="<<wr<<" true val="<<0.4030<<endl;
wr=getwinrate(3,0,29,35,0,0,0,0,0);
cout<<"wr="<<wr<<" true val="<<0.3575<<endl;
}
//卸载Dlltest.dll文件;
FreeLibrary(hDll);
}
return 0;
}
其中:
(1)#include <windows.h>
是调用dll的系统头文件依赖;
(2)hDll= LoadLibrary(TEXT("libwinrate.so"));
则是显式的打开库文件;
(3)typedef void (*Wrlibinit)();
则是声明库文件中函数及其参数的类型;
(4)Wrlibinit getwrinit = (Wrlibinit)GetProcAddress(hDll, "compinit");
则是定位获取库文件中的函数;
(5)getwrinit();
则是使用库文件中的函数。
(6)FreeLibrary(hDll);
则是使用完dll后显式的关闭库文件。
1.2 ubuntu下的调用
linux系统如ubuntu下由于依赖的系统库的不同,所以有所差别,其典型程序如下:
#include <iostream>
#include <stdio.h>
//windows
//#include <windows.h>
//linux
#include <dlfcn.h>
using namespace std;
typedef double (*WinrateFunc)(int, int,int,int, int, int, int, int, int);
typedef void (*Wrlibinit)();
/* main.cpp */
int main(){
//动态加载Dlltest.dll文件
void* hDll;
hDll= dlopen("./libwinrate.so",RTLD_LAZY);
if (hDll != NULL)
{
printf("%s\n","dll loaded!!");
WinrateFunc getwinrate = (WinrateFunc)dlsym(hDll, "get_winrate");
Wrlibinit getwrinit = (Wrlibinit)dlsym(hDll, "compinit");
if (getwinrate != NULL) {
getwrinit();
double wr=getwinrate(2,5,24,37,15,18,45,51,34);
cout<<"wr="<<wr<<" true val="<<0.2631<<endl;
wr=getwinrate(2,0,10,52,0,0,0,0,0);
cout<<"wr="<<wr<<" true val="<<0.5672<<endl;
wr=getwinrate(2,4,21,39,29,17,26,1,0);
cout<<"wr="<<wr<<" true val="<<0.4030<<endl;
wr=getwinrate(3,0,29,35,0,0,0,0,0);
cout<<"wr="<<wr<<" true val="<<0.3575<<endl;
}
//卸载Dlltest.dll文件;
dlclose(hDll);
}
return 0;
}
其中:
(1)#include <dlfcn.h>
是调用dll的系统头文件依赖;
(2)hDll= dlopen("./libwinrate.so",RTLD_LAZY);
则是显式的打开库文件;
(3)typedef void (*Wrlibinit)();
则是声明库文件中函数及其参数的类型;
(4)Wrlibinit getwrinit = (Wrlibinit)dlsym(hDll, "compinit");
则是定位获取库文件中的函数;
(5)getwrinit();
则是使用库文件中的函数。
(6)dlclose(hDll);
则是使用完dll后显式的关闭库文件。
1.3 两个系统下的比较
两个系统下dll调用的差异,如下表所示:
差异项 | windows | ubuntu |
---|---|---|
头文件依赖 | windows.h | dlfcn.h |
库打开 | LoadLibrary | dlopen |
函数获取 | GetProcAddress | dlsym |
库关闭 | FreeLibrary | dlclose |
---- | ---- | ---- |
相同项 | windows | ubuntu |
函数类型声明 | 使用typedef 定义 | 同左 |
库中函数使用 | 直接使用获取的函数 | 同左 |
---- | ---- | ---- |
2. python程序显式调用库文件
而python由于其解释器本身就是跨平台的所以在不同的系统下,其函数的调用是相同的,而且接口更为简单。
其典型程序如下:
#!/usr/bin/env python3
#_*_coding: utf-8 _*_
import sys
import json
import struct
import socket
from ctypes import * #用import *的方式可以把c_float,c_double等类型载入进来,而不用再带一个ctypes.
loadlib = cdll.LoadLibrary
lib = loadlib("./libwinrate.so")
lib.compinit()
getwinrate=lib.get_winrate
getwinrate.argtypes = [c_int,c_int,c_int,c_int,c_int,c_int,c_int,c_int,c_int]
getwinrate.restype= c_double
wr=getwinrate(2,5,24,37,15,18,45,51,34)
print("wr=",wr,' true val=',0.2631313131313131)
wr=getwinrate(2,0,10,52,0,0,0,0,0)
print("wr=",wr,' true val=',0.5672969999999999)
wr=getwinrate(2,4,21,39,29,17,26,1,0)
print("wr=",wr,' true val=',0.40303030303030307)
wr=getwinrate(3,0,29,35,0,0,0,0,0)
print("wr=",wr,' true val=',0.3575082176846212)
其中:
(1)lib = loadlib("./libwinrate.so")
是调用dll;
(2) 库中的函数可以直接使用,比如lib.compinit()
(3) 库中的函数可以赋给一个对象后使用,比如getwinrate=lib.get_winrate
(4) 最好声明一下函数的输入输出类型,比如getwinrate.argtypes
和getwinrate.restype
3. 库文件编译的差异
对于自己用c++编写的库文件,也是需要在不同的系统下编译的,因此对于程序本身可能依赖的部分头文件差异外最大差异是编译命令的差异:
windows 典型为:
g++ -g -std=c++11 -shared -Wall -o libwinrate.so winrate.cpp pokerlib.cpp mtrand.cpp -O3
ubuntu下典型为:
g++ -g -std=c++11 -shared -fPIC -o libwinrate.so winrate.cpp pokerlib.cpp mtrand.cpp -O3 -fno-stack-protector
4. 小结
本文简单介绍了不同系统下程序显式调用dll库文件的差异,为不同系统下的程序迁移提供帮助。