Python 调用 .so / .dll

python 调用 .so 文件

GCC编译参数解析

-shared: 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

-fPIC: 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

1. 调用 C 动态链接库

通过C语言编写一个简单 max 函数:max.c

/*
 * # -shared 为链接库  让编译器知道是要编译一个共享库
 * # -fPIC(Position Independent Code)   编译生成代码与位置无关
 */
int max(int a,int b)
{
    return a>b?a:b;
}
/*
 * gcc -Wall -g  -fPIC -c max.c -o max.o
 * gcc -shared max.o -o max.so
 * -g -Wall 供调试使用,不是必须的<br> * 或者<br> * gcc max.c -fPIC -shared -o max.so
 */

编译生成 libmax.so

gcc -fPIC -shared max.c -o libmax.so

使用 Python 语言调用 libmax.so 链接库中的 max 函数

from ctypes import cdll
 
cur = cdll.LoadLibrary('./libmax.so')
a = cur.max(1, 2)
 
print(a)

2. 调用 C++ 动态链接库

通过C++编写 display.cpp

class TestLib  
{  
    public:  
        void display();  
        void display(int a);  
};  
void TestLib::display() {  
    cout<<"First display"<<endl;  
}  
  
void TestLib::display(int a) {  
    cout<<"Second display:"<<a<<endl;  
}  

//C++想要编译成python可以调用的.so文件,必须加以下代码:
extern "C" {  
    TestLib obj;  
    void display() {  
        obj.display();   
      }  
    void display_int(int a) {  
        obj.display(a);   
      }  
}

编译生成 libdisplay.so

g++ -fPIC -shared display.cpp -o libdisplay.so

python调用 生成的 libtest.so

demo.py

import ctypes

so = ctypes.cdll.LoadLibrary   
lib = so("./libpycallclass.so")   

print('display()')  
lib.display()  

print('display(100)')  
lib.display_int(ctypes.c_int(100))

运行 :

python demo.py


python 调用 .dll 文件

暂时先填上一个链接

https://blog.csdn.net/zmnbehappy/article/details/78697185

Prefrence

Python实例浅谈之三Python与C/C++相互调用

<think>好的,我现在需要解决用户的问题:如何在Python调用包含.h头文件定义的.so动态链接库,特别是如何处理.h头文件的依赖。用户之前提到过使用C扩展、封装成.so文件以及相关工具如ctypes、cmake等。我需要结合这些信息,给出清晰的步骤和示例。 首先,回忆一下Python调用C库的常见方法。常见的有ctypes和C扩展模块。用户提到的是.so文件,通常ctypes可以直接加载.so调用其中的函数,但如果有头文件依赖,可能涉及到结构体、宏定义等,这些在ctypes中需要手动处理。另外,C扩展模块(如通过Python.h编写)可能需要更深入的集成,但用户的问题可能更偏向于直接调用现有的.so,而非自己编写扩展。 用户的问题中的引用提到使用dlopen和dlsym来加载.so,这可能是在C代码中,但用户现在是想在Python调用。所以重点可能在ctypes的使用上。然而,.h头文件中的结构体和函数声明需要在Python中重新定义,比如使用ctypes的结构体类来映射C的结构体,或者声明函数的参数和返回类型。 接下来,处理头文件依赖的问题。如果.so中的函数依赖于其他头文件中的结构体或宏,那么在Python中需要模拟这些结构体的布局。例如,如果C函数接收一个指向结构体的指针,那么在Python中需要用ctypes.Structure来定义相同的结构,并确保字段顺序和类型匹配。此外,函数原型需要使用argtypes和restype正确设置,以便ctypes能正确传递参数和解析返回值。 另外,用户提到的引用中涉及通过包装C代码使用Python.h来创建扩展模块,这可能涉及到将C代码编译成.so,并在Python中导入。这种情况下,头文件的依赖会在编译阶段处理,即编译时链接所需的库和包含头文件路径。例如,使用distutils或setuptools的Extension模块来指定include_dirs和libraries等参数。 因此,解决方案可能分为两种情况: 1. 使用ctypes直接调用.so,手动处理头文件中的类型和函数声明。 2. 编写C扩展模块,编译时处理头文件依赖,生成可在Python中导入的模块。 需要详细说明这两种方法的步骤,并给出示例代码。例如,对于ctypes,展示如何定义结构体,声明函数参数类型;对于C扩展,展示如何编写包装函数,使用Python.h,并在setup.py中配置编译选项。 还要注意,如果.so依赖其他的.so文件,可能需要设置LD_LIBRARY_PATH或在代码中明确加载依赖库。此外,编译时的头文件路径可能需要通过include_dirs参数指定。 在示例部分,可能需要给出一个具体的例子,比如一个C函数使用了某个结构体,然后在Python中用ctypes模拟该结构体,并正确调用函数。同时,对于C扩展方法,展示如何编写包装代码,并编译生成模块。 最后,生成相关问题,如性能比较、处理复杂结构体的方法、调试技巧等。</think>### Python调用C扩展.so文件处理头文件依赖的方法 在Python调用包含.h头文件定义的.so动态链接库,需根据具体情况选择**直接调用**或**封装扩展模块**两种方式处理头文件依赖。 --- #### 方法一:使用ctypes直接调用(手动映射数据结构) 适用于已有编译好的.so文件且需要快速集成的情况,需手动在Python中重建C结构体定义。 1. **定义等效数据结构** ```python from ctypes import CDLL, Structure, c_int, c_float, POINTER # 映射C头文件中的结构体 class MyStruct(Structure): _fields_ = [("a", c_int), ("b", c_float)] # 加载.so文件 lib = CDLL("./mylib.so") # 声明函数参数类型 lib.my_function.argtypes = [POINTER(MyStruct), c_int] lib.my_function.restype = c_int ``` 2. **调用示例** ```python data = MyStruct(a=10, b=3.14) result = lib.my_function(data, 5) ``` --- #### 方法二:通过Python C扩展封装(自动处理依赖) 适用于需要长期维护的复杂项目,可在编译阶段自动处理头文件依赖[^3]。 1. **编写包装代码(wrapper.c)** ```c #include <Python.h> #include "mylib.h" // 依赖的.h头文件 static PyObject* wrapped_func(PyObject* self, PyObject* args) { int arg1; float arg2; if (!PyArg_ParseTuple(args, "if", &arg1, &arg2)) return NULL; // 调用C库函数 int result = mylib_function(arg1, arg2); return Py_BuildValue("i", result); } static PyMethodDef methods[] = { {"wrapped_func", wrapped_func, METH_VARARGS, "Description"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "mymodule", NULL, -1, methods }; PyMODINIT_FUNC PyInit_mymodule(void) { return PyModule_Create(&module); } ``` 2. **编译配置(setup.py)** ```python from setuptools import setup, Extension module = Extension( 'mymodule', sources=['wrapper.c'], include_dirs=['/path/to/headers'], # 指定.h文件路径 libraries=['mylib'], # 链接的库名 library_dirs=['/path/to/libs'] # 指定.so路径 ) setup(name='mymodule', ext_modules=[module]) ``` 3. **编译并导入** ```bash python setup.py build_ext --inplace ``` ```python import mymodule mymodule.wrapped_func(10, 3.14) ``` --- #### 关键差异对比 | 方法 | 优点 | 缺点 | |------------|-------------------------------|-------------------------------| | ctypes | 无需编译,直接调用动态库 | 需手动处理数据结构,调试复杂 | | C扩展封装 | 自动处理依赖,性能更优 | 需编写C代码并重新编译 | ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值