zoukankan      html  css  js  c++  java
  • 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_ProjectCameraProjectorCalibrationx64ReleaseMyDll.lib 和对象 D:VS2017_ProjectCameraProjectorCalibrationx64ReleaseMyDll.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_ProjectCameraProjectorCalibrationx64ReleaseMyDll.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 }

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

    CV&DL
  • 相关阅读:
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/winslam/p/14413348.html
Copyright © 2011-2022 走看看