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