Python
调用动态链接库
ctypes
是Python
调用c
的动态链接库的一个内置模块。
通过 CMake
构建动态链接库
项目结构
├── CMakeLists.txt # CMake 构建配置文件
├── library.h # 动态链接库头文件
└── library.cpp # 动态链接库源文件
CMakeLists.txt
配置内容如下:
cmake_minimum_required(VERSION 3.10)
project(excapp)
set(CMAKE_CXX_STANDARD 11)
set(EXCAPPLIB library.cpp library.h)
add_library(excapp SHARED ${EXCAPPLIB})
CMakeLists.txt
是cmake
的配置文件。相关详细配置请参考官方文档。
动态链接库头文件 library.h
内容如下:
#ifdef __cplusplus
extern "C" {
#endif
#ifndef EXCAPP_LIBRARY_H
#define EXCAPP_LIBRARY_H
#include <string>
typedef void (*FUNP)();
typedef void (*FUNP1)(char *ch);
void hello();
void echo(char *text);
void printUser(char *user, unsigned int age);
char *getName(char *userName);
int sum(int a, int b);
void *getVoidData(void *data);
void *getVoidData1(void *data, int *addr);
void callback(FUNP funp);
void callback1(FUNP1 funp1, char *text);
#endif
#ifdef __cplusplus
}
#endif
动态链接库源文件 library.cpp
内容如下:
#include <string>
#include "library.h"
typedef void (*FUNP)();
typedef void (*FUNP1)(char *ch);
void hello() {
printf("%s\n", "Hello, World!");
}
void echo(char *text) {
printf("%s\n", text);
}
void printUser(char *user, unsigned int age) {
printf("His name is %s and is %d years old.\n", user, age);
}
char *getName(char *userName) {
return userName;
}
int sum(int a, int b) {
return a + b;
}
void *getVoidData(void *data) {
return data;
}
void *getVoidData1(void *data, int *addr) {
char *tmp = static_cast<char *>(data);
*addr = strlen(tmp);
return data;
}
void callback(FUNP funp) {
(*funp)();
}
void callback1(FUNP1 funp1, char *text) {
(*funp1)(text);
}
构建编译,命令如下:
$ cmake .
$ make
注:上述命令是在
Ubuntu
系统下执行的。如果是其他操作系统平台,请自行适配相应平台操作方法。本人平台是Ubuntu
,所以生成的动态链接库名称为libexcapp.so
。Linux
系统生成libexcapp.so
文件,Windows
系统生成excapp.dll
文件。
注意:Python
不支持调用C++
编译生成的动态链接库。需要添加如下内容:
#ifdef __cplusplus
extern "C" {
#endif
// 您的逻辑内容在这
#ifdef __cplusplus
}
#endif
加载动态链接库
下面代码是最简单的加载动态链接库
import ctypes
lib = ctypes.CDLL("libexcapp.so")
更严谨的加载方式是判断当前运行平台,并根据当前平台加载相应的动态链接库。
import platform
if 'linux' in str(platform.system()).lower():
lib = ctypes.CDLL("libexcapp.so")
elif 'windows' in str(platform.system()).lower():
lib = ctypes.WinDLL("excapp.dll")
elif 'darwin' == str(platform.system()).lower():
lib = ctypes.CDLL("libexcapp.dylib")
调用库的接口
简单的调用接口。
lib.hello()
调用带参数的接口
调用带有一个参数为 char *
类型的接口:
lib.echo("This is echo method.".encode("utf8"))
更严谨的调用方式是指定参数列表中各个参数的类型,代码如下:
lib.echo.argtype=ctypes.c_char_p
lib.echo("This is echo method.".encode("utf8"))
调用具有多个参数的接口
调用接口需要传递多个参数的接口:
lib.printUser.argtypes = (ctypes.c_char_p, ctypes.c_uint)
lib.printUser("小宝".encode("utf-8"), 12)
调用基友多个参数并有返回值的接口
注:指定参数类型,并且指定返回类型
样例1:
lib.getName.argtype = ctypes.c_char_p
lib.getName.restype = ctypes.c_char_p
res = lib.getName("小宝".encode("utf-8"))
print(res)
print(type(res))
print(res.decode("utf-8"))
样例2:
res = lib.sum(1, 2)
print(res)
调用void *
参数或返回类型的接口
样例1:
返回数据类型为 void *
接口,在 Python
中需要使用 ctypes.cast(obj,type)
强制转相关类型。
lib.getVoidData.argtype = ctypes.c_void_p
lib.getVoidData.restype = ctypes.c_void_p
res = lib.getVoidData("中国".encode("utf-8"))
ccharp = ctypes.cast(res, ctypes.c_char_p)
print(res)
print(ccharp)
print(ccharp.value)
print(ccharp.value.decode("utf-8"))
样例2:
该样例的接口有指针类型参数,并且返回 void *
的数据接口。指针的传递需要 ctypes.byref()
传入接口。返回的 void *
数据类型,通过 ctypes.string_at(obj,int)
获取指定长度的数据流,这个在流处理的时候非常重要,比如获取音频数据流。
lib.getVoidData1.argtypes = (ctypes.c_char_p, ctypes.POINTER(ctypes.c_int))
lib.getVoidData1.restype = ctypes.c_void_p
lenth = ctypes.c_int(0)
res = lib.getVoidData1("您好呀".encode("utf-8"), ctypes.byref(lenth))
data = ctypes.string_at(res, int(lenth.value))
print(res)
print(data)
print(lenth)
调用有回调函数的接口
样例1:
调用有回调函数的接口,通过 ctypes.CFUNCTYPE()
指定回调函数的返回类型和参数列表中各个参数的类型。即使没有任何的返回值,也需要指定返回类型为 None
。
def callback():
print("您好呀")
callback_type = ctypes.CFUNCTYPE(None)
lib.callback.argtype = callback_type
cal = callback_type(callback)
lib.callback(cal)
样例2:
调用有回调函数的接口,指定参数列表的参数类型。
def callback(text):
print(text)
callback_type = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
lib.callback.argtypes = (callback_type, ctypes.c_char_p)
cal = callback_type(callback)
lib.callback1(cal, "你好呀".encode("utf-8"))
注意
在 Python3
中,ctypes
传递的数据类型都是 byte
流。
如果需要demo样例代码,请留言。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/34826.html