Windows环境C++工程的动态库导出与调用


        算法工程师经常与前端对接,一般地,我们不会将源码打包直接发给对方,而是将函数方法编译成库(即:win下的DLL or LIB文件)

一方面是为了保密,另一方面是为方便使用(假如你的算法几十个cpp,别人连带界面cpp编译很费时间)。常用的库打包有如下三个方式,本文采用第一种方式作为范例。

三种方式区别:

1、采用第一种方法时,需要包含文件:.h .lib .dll,有头文件,具有可读性; 

2、第二种和第三种库使用时,需要预编译、预加载等操作,第三种直接连头文件都看不到,

保密性最好,这里不作多讨论。

 

   下文采用第一种导出方式,即:动态链接库(DLL),导出文件有:.h .lib .dll

 

一、创建导出库工程

打开VS2019, 点击:文件 -> 新建 -> 项目->动态连接库(DLL),选中如上图第一项,新建工程;自动生成如下几个文件,我们全部删除。

 

 

项目属性-C/C++-预编译头默认如下图设置

 

将其修改为如下内容: 

 

 最后,别忘记设置工程为Release X64,

二、编写库导出.h .cpp文件

     所谓编写库导出文件,也就是编写代码,告诉编译器,那些函数、类、变量要导出到库文件中。这里给出一个范例,以后用照抄就行(该工程不需要

执行,所以没有main函数);

下面的声明的集合函数,可以改为任何自定义函数,记得:函数和类前面加宏定义:API_SYMBOL(也即:__declspec(dllexport))

,下面MyDll.cpp文件记得要加 #define BUILD_MYDLL

注意:这里给出了C风格函数、C++模板函数、全局变量、类的导出方式,经过多个工程测试,方法有效。

MyDll.h

 1 #pragma once
 2 
 3 #ifdef BUILD_MYDLL
 4 #define API_SYMBOL __declspec(dllexport)
 5 #else
 6 #define API_SYMBOL __declspec(dllimport)
 7 #endif // BUILD_MYDLL
 8 
 9 // OS
10 #include<iostream>
11 // ThirdParty
12 #include<opencv2/opencv.hpp>
13 #include<Eigen/Core>
14 
15 // 导出全局变量
16 extern "C" API_SYMBOL int globa_a;
17 
18 // 导出函数
19 extern "C" API_SYMBOL int FunAdd(int a, int b);
20 
21 extern "C" API_SYMBOL cv::Mat FunMatAdd(const cv::Mat& m1, const cv::Mat& m2);
22 
23 // 导出C++模板函数
24 API_SYMBOL Eigen::Matrix2d FunMatAdd(const Eigen::Matrix2d& m1, const Eigen::Matrix2d& m2);
25 
26 //导出类
27 class API_SYMBOL MyClass
28 {
29 public:
30     MyClass();
31     ~MyClass();
32 
33 private:
34 
35 };

MyDll.cpp

 1 #define BUILD_MYDLL // 由于是导出函数,所以徐娅哦定义.h文件中的BUILD_MYDLL
 2 #include "MyDll2.h"
 3 
 4 int globa_a = 999;
 5 
 6 // 删除宏API_SYMBOL
 7 int FunAdd(int a, int b)
 8 {
 9     std::cout << "globa_a = " << ++globa_a << std::endl;
10     return a + b;
11 }
12 
13 cv::Mat FunMatAdd(const cv::Mat & m1, const cv::Mat & m2)
14 {
15     std::cout << "globa_a = " << ++globa_a << std::endl;
16     return m1 + m2;
17 }
18 
19 Eigen::Matrix2d FunMatAdd(const Eigen::Matrix2d & m1, const Eigen::Matrix2d & m2)
20 {
21     std::cout << "globa_a = " << ++globa_a << std::endl;
22     return m1 + m2;
23 }
24 
25 MyClass::MyClass()
26 {
27     std::cout << "MyClass" << std::endl;
28 }
29 
30 MyClass::~MyClass()
31 {
32 }
View Code

直接编译,可以看到如下信息:

1 1>  正在创建库 D:\VS2017_Project\CameraProjectorCalibration\x64\Release\MyDll.lib 和对象 D:\VS2017_Project\CameraProjectorCalibration\x64\Release\MyDll.exp 2 1>正在生成代码
3 1>All 939 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
4 1>已完成代码的生成
5 1>ExportDLL.vcxproj -> D:\VS2017_Project\CameraProjectorCalibration\x64\Release\MyDll.dll 6 1>已完成生成项目“ExportDLL.vcxproj”的操作。
7 ========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========

 

三、库打包与测试

       现在将上述MyDll.h、MyDll.lib、MyDll.dll三个文件放到一起,我们新建一个控制台工程测试这些库,注意:上述编译库的时候,我使用了第三方库,如:Eigen等,

在测试工程中,也需要将这些库提前包含进来。

        新建好测试工程后,我们引入上面三个文件,这和配置OpenCV没什么区别,不多说。

测试文件,test.cpp

 1 // DemoInvokeDll2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
 2 //
 3 
 4 #include <iostream>
 5 #include<MyDll.h>
 6 
 7 int main()
 8 {
 9     globa_a = 66;
10 
11     cv::Mat m1 = (cv::Mat_<uchar>(3, 1) << 1, 2, 3);
12     cv::Mat m2 = (cv::Mat_<uchar>(3, 1) << 1, 9, 2);
13     cv::Mat m3 = FunMatAdd(m1, m2);
14 
15     Eigen::Matrix2d m4, m5, m6;
16     m4 << 1, 2, 3, 4;
17     m5 << 2, 3, 4, 5;
18     m6 = FunMatAdd(m4, m5);
19     std::cout << m6(0, 0) << ", " << m6(0, 1) << std::endl;
20     std::cout << m6(1, 0) << ", " << m6(1, 1) << std::endl;
21 
22     MyClass mc;
23     return 1;
24 }

 

注意全局变量等,成功调用!

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM