vs2019导出动态链接库(dll)给其他vs项目及python代码使用

通过vs可以导出动态链接库(dll文件)给其他c++项目、c#项目、python项目使用。本案例实现将vs项目导出为动态链接库,给c++项目与python项目使用。涉及全局变量、函数、自定义类的导出。

1、创建动态链接库项目

项目创建完成后会得到以下结构, 可以将核心代码写在dllmain.cpp里面(原先的内容可以不用管),头文件信息写入在pch.h里面

2、编写核心代码 

以下内容可以全部拷贝到pch.h中(博主的代码涉及到了cuda,所以需要配置以下cuda,cuda的配置可以参考libtorch显存管理示例_万里鹏程转瞬至的博客-CSDN博客,各位也可以将cuda相关的代码删掉)。博主在这里定义了导出一个全局变量、两个函数和一个自定义类。

#pragma once

//extern 表示该函数为全局函数,可以在其他地方调用
//“C”表示按照C语言方式进行编译和链接 python下导入dll只支持C函数
//__declspec(dllexport)告诉编译器这是一个导出函数

#ifdef BUILD_MYDLL
#define API_SYMBOL __declspec(dllexport)
#else
#define API_SYMBOL __declspec(dllimport)
#endif // BUILD_MYDLL

// 导入库
#include <iostream>
#include <cuda_runtime_api.h>


// 导出全局变量
extern "C" API_SYMBOL int globa_times;
// 导出函数
extern "C" API_SYMBOL float get_cuda_use();
extern "C" API_SYMBOL int reset_cuda();

//导出类
extern "C" API_SYMBOL class  MyClass
{
public:
    MyClass();
    ~MyClass();
    int FunSub(int a, int b);
private:

};

上述代码中的关键就是extern "C" API_SYMBOL class_type fun_name; 其中API_SYMBOL是一个define的常量,在本项目中的值为 __declspec(dllexport),在其他项目导入本dll库时的值为__declspec(dllimport),这是根据常量BUILD_MYDLL自动判断的。

以下内容可以全部拷贝到dllmain.cpp中。常量BUILD_MYDLL也是定义在以下代码中。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

using namespace std;
#define BUILD_MYDLL // 定义为导出函数

int globa_times = 999;

float get_cuda_use()
{
    size_t free_byte;
    size_t total_byte;
    cudaError_t cuda_status = cudaMemGetInfo(&free_byte, &total_byte);

    if (cudaSuccess != cuda_status) {
        printf("Error: cudaMemGetInfo fails, %s \n", cudaGetErrorString(cuda_status));
        return float(-1.0);
    }
    else {
        double free_db = (double)free_byte;
        double total_db = (double)total_byte;
        float used_db_1 = (total_db - free_db) / 1024.0 / 1024.0;
        std::cout << "Now used GPU memory " << used_db_1 << "  MB\n";
        return float(used_db_1);
    }
}
int reset_cuda() {
    globa_times++;
    cudaDeviceReset();
    float res=get_cuda_use();
    return int(res);
}

MyClass::MyClass()
{
    std::cout << "MyClass init" << std::endl;
}

MyClass::~MyClass()
{
}
int MyClass::FunSub(int a, int b)
{
    return a - b;
}

 点击运行后,即可生成动态链接库(xxx.dll和xxx.lib)。

3、整理为动态链接库

c++项目导入动态链接库通常是需要头文件(.h文件)、库文件(.lib文件)、动态链接文件(.dll文件),上述流程中的xxx.dll和xxx.lib与.h可以单独整理出来形成一个目录。其中,需要注意的是,dll文件要放在可执行文件同级下才行(或者将dll文件的路径添加到系统环境变量path中)。

4、vs c++项目调用

导入自己的动态链接库与正常库是一样的步骤,具体如下图所示。此外,还需要在链接器-》输入-》附加依赖项中配置dll_export.dll。由于博主在构造自己的动态链接库时使用到了cuda,因此这个项目也要配置cuda环境。

 测试代码如下所示

#include <iostream>
#include <pch.h>

int main()
{
    globa_times = 66;

    //print_cuda_use();
    int res= reset_cuda();
    std::cout << "Now CUDA mem = " << res << std::endl;

    MyClass myc;
    int sub = myc.FunSub(100, 10);
    std::cout << "myc.FunSub(100, 10) = " << sub << std::endl;
    return 1;
}

运行结果如下所示,可见一切正常

 5、python导入dll库

 python导入dll库只需要dll文件路径即可,但是当dll文件存在其他依赖的dll时,需要使用os.add_dll_directory补充其他dll的路径。下面代码中lib.reset_cuda(),就是调用最前面写的c函数,释放显存。

import ctypes
import os
#os.environ['Path']+=r'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\bin'
#python3.7版本以上使用下列代码添加依赖项dll的路径
os.add_dll_directory(r'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\bin')
lib = ctypes.cdll.LoadLibrary(os.getcwd()+ "/dll_export.dll")
#win32api.FreeLibrary(libc._handle)   #发现程序运行结束时无法正常退出dll,需要显式释放dll
lib.reset_cuda()

博主使用的是jupyter lab,因此在执行命令中,可以在控制台看到相应的c++代码的输出。 

 更多python调用c++ dll库的用法可以参考C/C++代码生成DLL & Python调用C/C++生成的dll_红颜时光的博客-CSDN博客_c生成dll

猜你喜欢

转载自blog.csdn.net/a486259/article/details/125396626