最近需要将py文件转为dll,特此记录。
操作步骤来自于:将Python文件发布成DLL并调用
写一个py文件
文件名:test_numpy.py
import numpy as np
def func(my_list1, my_list2):
list_np1 = np.array(my_list1)
list_np2 = np.array(my_list2)
return list(list_np1 + list_np2)
测试确认能运行成功。
生成DLL
vs2017新建dll项目:
项目名:Dll1
创建后,可以看到资源管理器,只需要用到pch.h和pch.cpp。
配置项目属性
在菜单里”调试“-》”Dll1属性“
分别添加python.exe所在的目录下的include文件夹路径和libs文件夹。
添加python依赖项:
注意要与版本对应,如果不知道版本可以在python中输入
import sys
print(sys.version)
查看版本。
在pch.h输入:
#ifndef PCH_H
#define PCH_H
// 添加要在此处预编译的标头
#include "framework.h"
extern "C" _declspec(dllexport) long* listAdd(int a[], int b[], int n); // 将两个数组相加,并返回新数组
#endif //PCH_H
在pch.cpp输入:
// pch.cpp: 与预编译标头对应的源文件
#include "pch.h"
// 当使用预编译的头时,需要使用此源文件,编译才能成功。
// pch.cpp: 与预编译标头对应的源文件
#include <Python.h>
#include <iostream>
using namespace std;
// 当使用预编译的头时,需要使用此源文件,编译才能成功。
long* listAdd(int a[], int b[], int n)
{
Py_SetPythonHome(L"C:/Users/AppData/Local/Programs/Python/Python310-32/"); //这里地址一定要写对啊!
// 这里要写和在设置属性时的python.exe一样的路径,不然会出现错误
//***python调用***//
//初始化python模块
Py_Initialize();
// 检查初始化是否成功
if (!Py_IsInitialized())
{
cout << "初始化失败" << endl;
Py_Finalize();
}
PyObject* pModule;
PyObject* pFunc = NULL;
PyObject* pArg = NULL;
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");//设置python模块,搜寻位置,文件放在.cpp文件一起
pModule = PyImport_ImportModule("test_numpy");//Python文件名
if (!pModule) {
cout << "py文件导入失败" << endl;
Py_Finalize();
return NULL;
}
else {
pFunc = PyObject_GetAttrString(pModule, "func");//Python文件中的函数名
if (!pFunc) {
cout << "函数导入失败" << endl;
Py_Finalize();
return NULL;
}
PyObject *pyParamsA = PyList_New(n), *pyParamsB = PyList_New(n); //c++类型转python类型
for (int i = 0; i < n; i++) {
PyList_SetItem(pyParamsA, i, PyLong_FromLong(a[i]));
PyList_SetItem(pyParamsB, i, PyLong_FromLong(b[i]));
}
long *result = new long(n);
pArg = PyObject_CallFunction(pFunc, "OO", pyParamsA, pyParamsB); //调用函数
for (int i = 0; i < n; i++) { // python类型转C++数组
result[i] = PyLong_AsLong(PyList_GetItem(pArg, i));
cout << result[i] << " ";
}
cout << endl;
return result;
}
}
点击运行,或者点击生成-》生成Dll1,
即可生成dll
红框是生成的dll所在路径。
错误1:无法打开文件“python310_d.lib”
需要安装PythonDebug版本
安装Python,如果已经安装Python,需要修改Python的安装设置,将Debug版本一起安装进来。
如果用anaconda安装的环境,需要重新下载python安装。
具体见https://www.jianshu.com/p/28291e95bed3和
https://blog.csdn.net/weixin_43788499/article/details/84933210
红框内要勾上。
警告:warning LNK4272: 库计算机类型“x86”与目标计算机类型“x64”冲突
使用的库是32位的而写的代码目标机器是64位的,所以报错产生冲突。
解决:下载使用32位的python
python官网:https://www.python.org/downloads/windows/
调用DLL
vs建立空项目:
在这个.cpp里写入
#include<iostream>
#include <Windows.h>
using namespace std;
int main()
{
// 加载DLL文件
HINSTANCE hDllInst;
hDllInst = LoadLibrary(TEXT("DLL1.dll")); //调用DLL
if (hDllInst) {
typedef long* (*PLUSFUNC)(int* a, int* b, int n); //后边为参数,前面为返回值
PLUSFUNC plus_str = (PLUSFUNC)GetProcAddress(hDllInst, "listAdd"); //GetProcAddress为获取该函数的地址
int a[3] = { 1, 2, 3 }, b[3] = { 4, 5, 6 };
long* result = plus_str(a, b, 3);
cout << "调用完成" << endl;
}
else {
cout << "DLL加载失败" << endl;
}
return 0;
}
配置一下项目属性,将之前生成的lib文件加入到链接器里面。
加入生成的lib的路径。
点击运行,输出
5 7 9
调用完成
错误1:已加载“C:\Windows\SysWOW64\ntdll.dll”。无法查找或打开 PDB 文件
解决:https://blog.csdn.net/u011251940/article/details/89521518
1、点 调试
2、然后 选项和设置
3、右边勾上 启用源服务器支持
4、左边点 符号
5、把微软符号服务器勾
6、确定保存。
再重新运行程序
错误2:找不到dll
要把dll文件放在debug文件夹里
错误2:找不到.py
把py文件放入
错误3:you should not try to import numpy from its source directory
我们进入python的路径里,
打开python.exe,输入import numpy 不报错,
打开python_d.exe,输入import numpy 报错。
说明,要尽可能让vs调用的是python.exe。
回到生成dll的步骤,在添加python依赖项:
一定要有python310.lib,如果只有python310.lib报错,
将python310_d.lib加入,但不要删除python310.lib。