【转】matlab与C/C++混合编程——在Windows/Linux上调用Matlab编译的动态库文件

转自:matlab与C/C++混合编程——在Windows/Linux上调用Matlab编译的动态库文件_sinat_18131557的博客-CSDN博客

dateversioncomments
2019/9/9V0.1Init
2019/9/27V0.2添加报错信息写入log的实现

文章目录

      • MATLAB生成Dll文件调用
          • 生成dll文件
          • 调用dll文件
      • MATLAB生成.so文件调用
          • Linux安装Matlab
          • 生成.so文件
          • 调用.so在Linux实现matlab代码内容
          • 添加调试的写入log文件的功能


主要是想使用MATLAB的m文件,生成可以使用C/C++调用的文件,两种方式

  • 生成dll文件,在Windows下调用,使用VS构建调用的工程
  • 生成so文件在Linux下调用,调用代码使用g++编译

MATLAB生成Dll文件调用

生成dll文件

在Windows上安装Matlab过程略,在Matlab中创建函数:

function myplot(y,mytitle)
%UNTITLED 此处显示有关此函数的摘要plot(y);title(mytitle);saveas(gcf,'myplot.jpg');
end

这样写的好处在于传递了数组类型,还传递了字符串类型,使用了绘图功能,能全面看下变量怎么传递的。
然后在APP栏目下找到Library Compiler进去,或者在命令行中输入deploytool1:
在这里插入图片描述
得到如下界面:
在这里插入图片描述
上方选择C/C++ Shared Library,EXPORTED FUNCTIONS的加号点一下,选中要输出的文件,Library Name可以更加需要选择改或者不改,另外这里只有一个文件需要转化,如果这个文件中调用了另外一个自己写的函数中的内容,需要把这个函数放在Files required for your library to run中,当右边的Package变为绿色就可以点击Package,选择保存目录,等待一会让就好了。完成后会得到三个文件,选择for_redistribution_files_only进入就有了如下文件:
在这里插入图片描述

调用dll文件

打开vs创建一个新的C++的控制台工程。第一步将解算方案平台改为x64,不然后面可能会报错:
在这里插入图片描述然后配置2:
项目-> 项目属性-> VC++目录->包含目录添加…\MATLAB\R2016a\extern\include
库目录添加…C:\Program Files\MATLAB\R2016a\extern\lib\win64\microsoft
在这里插入图片描述
在链接器里面添加这几项(这里只用到了myplot.lib 和mclmcrrt.lib,资料上其他应用有用到其他几个):
myplot.lib (自己的lib文件)
mclmcr.lib (以下都是matlab的文件)
mclmcrrt.lib
libmx.lib
libmex.lib
libmat.lib
libeng.lib
在这里插入图片描述
把Matlab生成的.dll,.h,.lib文件复制到项目的源文件的目录下(放到存放cpp文件目录里面),在项目里包含.h文件。首先打开.h文件看下:

...
extern LIB_myplot_C_API 
bool MW_CALL_CONV myplotInitialize(void);extern LIB_myplot_C_API 
void MW_CALL_CONV myplotTerminate(void);extern LIB_myplot_C_API bool MW_CALL_CONV mlfMyplot(mxArray* y, mxArray* mytitle);
...

主要是这3个函数是需要使用的。

  • myplotInitialize 初始化
  • myplotTerminate 关闭函数
  • mlfMyplot(mxArray* y, mxArray* mytitle) 运行函数

由于C/C++没有mxArray*这样的数据类型,需要进行数据转化,y是数组(一维矩阵),mytitle是个字符串 所以可以用这样的方式创建,(可参考3):

mxArray *dest_ptr =mxCreateDoubleMatrix(rows,cols, mxREAL);
mxArray* mytitle = mxCreateString(const char *str)

同时含有必要的初始化,调用代码如下:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include "myplot.h"
#include "string.h"int main()
{// 初始化mclmcr,如果没有这两句可能会有访问错误的问题mclmcrInitialize();if (!mclInitializeApplication(NULL, 0)){return -1;}printf("mclmcr Initialized!\n");//初始化应用if (!myplotInitialize()){return -1;}printf("myplot Initialized!\n");// 初始化数据并做数据转化double data[5] = { 1,2,3,4,5 };mxArray *y = mxCreateDoubleMatrix(5, 1, mxREAL);memcpy((void*)mxGetPr(y), (void*)data, sizeof(data));const char *title = "mytile";mxArray* mytitle = mxCreateString(title);printf("data  Initialized!\n");//调用主函数mlfMyplot(y, mytitle);// 关闭应用myplotTerminate();system("pause");return 0;
}

如果发生这样的异常:
在这里插入图片描述

  • mclmcr一定要初始化mclmcrInitialize();if (!mclInitializeApplication(NULL, 0)){return -1;}
  • 按Ctrl+Alt+E将Win32 Exceptions的异常取消勾选。

如果没有异常,能在工程目录下看到myplot.jpg文件。
在这里插入图片描述

MATLAB生成.so文件调用

生成.so文件需要在Linux环境下安装MATLAB。

Linux安装Matlab

Matlab下载地址:https://ww2.mathworks.cn/downloads/web_downloads/?s_iid=hp_ff_t_downloads
在Linux下尽量选择MATLAB版本与MATLAB Runtime的版本一致,如都是2019a,不然可能在编译时候或者编译以后有libstdc++.so的版本错误问题,选择版本以后可以直接选择Linux系统进行下载,我使用的学校邮箱注册,可以直接使用学术license。下载完成,解压出来后,cd到文件夹下直接

sudo ./install

就可以像Windows上安装软件一样点下一步下一步了。
如果只需要跑代码,不用这个写/调试的机器,只需要安装Matlab Runtime就可以了。在官网下载,安装方式同Matlab一样,使用sudo ./install命令就可以,安装完成以后,提示将几个变量添加到环境变量里面去:
我的是这样的:
在这里插入图片描述
/usr/local/MATLAB/MATLAB_Runtime/v96/runtime/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/sys/os/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/extern/bin/glnxa64,不同机器与版本,这个路径不一样,按照显示的添加就行。
使用terminal输入:

sudo gedit /etc/profile

输入密码后,在打开的文件最后添加:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/MATLAB/MATLAB_Runtime/v93/runtime/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v93/bin/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v93/sys/os/glnxa64

由于libmyplot.h文件中还包含了一个mclmcrrt.h文件,使用g++编译时候,还需要把这个文件的路径添加到CPLUS_INCLUDE_PATH中,所以还要打开/etc/profile文件在最后添加一行:

export CPLUS_INCLUDE_PATH=/usr/local/MATLAB/MATLAB_Runtime/v96/extern/include:$CPLUS_INCLUDE_PATH

这个文件在…/extern/include里面,前面的路径是安装地址。
到这里,Linux安装完成~

生成.so文件

生成.so的文件必须要为函数,不能是脚本,假设现在需要转化的函数为:

function myplot(y,mytitle)
%UNTITLED 此处显示有关此函数的摘要plot(y);title(mytitle);saveas(gcf,'myplot.jpg');
end

就是把输入的y通过plot绘图出来,并且,这个图的title是mytitle这个字符串。写成这样是为了说明2种数据类型的转化关系。
在matlab的APP栏中,找到Library Compiler进去,或者在命令行中输入:deploytool然后选择Library Compiler进入到如下界面:
在这里插入图片描述
上方选择C/C++ Shared Library,EXPORTED FUNCTIONS的加号点一下,选中要输出的文件,Library Name可以更加需要选择改或者不改,当右边的Package变为绿色就可以了。
在这里插入图片描述
点击Package。选择保存工程的文件夹,等待一会儿就好了。打开所在目录得到了:
在这里插入图片描述
打开for_redistribution_files_only就可以看到.h和.so文件了。
在这里插入图片描述
另外也可在matlab中使用mcc命令生成.so文件4。

mcc -W cpplib:myplot -T link:lib myplot.m -c

但是这样生成的代码函数名不一样,参数类型也不一样,需要自己研究研究。

调用.so在Linux实现matlab代码内容

同样地,写一个cpp文件:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//#include "myplot.h"
#include "string.h"int main()
{// 初始化mclmcr,如果没有这两句可能会有访问错误的问题mclmcrInitialize();if (!mclInitializeApplication(NULL, 0)){return -1;}printf("mclmcr Initialized!\n");//初始化应用if (!libmyplotInitialize()){return -1;}printf("myplot Initialized!\n");// 初始化数据并做数据转化double data[5] = { 1,2,3,4,5 };mxArray *y = mxCreateDoubleMatrix(5, 1, mxREAL);memcpy((void*)mxGetPr(y), (void*)data, sizeof(data));const char *title = "mytile";mxArray* mytitle = mxCreateString(title);printf("data  Initialized!\n");//调用主函数mlfMyplot(y, mytitle);// 关闭应用libmyplotTerminate();return 0;
}

要注意初始化应用,关闭应用,主程序的函数名,在libmyplot.h文件中能找到对应的函数名字。

在打开一个terminal,输入使用g++编译的指令:

g++ sotest.cpp -o sotest -L. -lmyplot

g++使用g++编译方式编译,sotest.cpp编译的源文件为sotest.cpp,-o sotest输出sotest文件作为可执行文件,-L. -lmyplot指定需要链接的库,也就是当前文件目录下的libmyplot.so文件。按理说能成功,结果:

/usr/bin/ld: /tmp/ccXUI6xA.o: undefined reference to symbol 'mxCreateDoubleMatrix_800_proxy'
/usr/local/MATLAB/MATLAB_Runtime/v96/runtime/glnxa64/libmwmclmcrrt.so.9.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

网上找资料定位到error adding symbols: DSO missing from command line这个问题是libmwmclmcrrt.so.9.6文件没找到,可是已经添加了LD_LIBRARY_PATH,有点不明所以,既然你说你没找到,那就给你指定文件吧5:

g++ sotest.cpp -o sotest -L. -lmyplot -L/usr/local/MATLAB/R2019a/runtime/glnxa64/ -lmwmclmcrrt

运行成功,没有报错,但是也什么都没有输出,这个时候能看到多了一个sotest文件:
在这里插入图片描述
这时候运行sotest文件能得到结果:
在这里插入图片描述
在这里插入图片描述
如果libmyplotInitialize()初始化失败的话,切换到sudo权限运行。

sudo -s

添加调试的写入log文件的功能

由于在Linux上跑,通常需要记录下出错的问题,把错误信息写到log文件中。写了一个写入log文件的函数,每一个月的信息存放一个文件,如果文件不存在,就创建一个:

#include "time.h"
#include <fstream>
#include <iostream>void WriteLog(const char* text)
{char LOG_FILE[1024]={0};// get the time nowtime_t now=time(0);tm *ltm = localtime(&now);snprintf(LOG_FILE,1024,"./log/log_%04d%02d.txt", ltm->tm_year+1900,ltm->tm_mon+1);// if LOG file not exist, then create it!fstream f1;f1.open(LOG_FILE,ios::in);if(!f1){f1.close();f1.open(LOG_FILE,ios::out);f1.close();}// write info in log file!FILE *fp;fp=fopen(LOG_FILE, "a+");if (fp != NULL){char ltime[1024] = { 0 };strftime(ltime,1024,"%Y-%m-%d %H:%M:%S ", ltm);		fwrite(ltime, sizeof(char), strlen(ltime), fp);fwrite(text, sizeof(char), strlen(text), fp);fwrite("\r\n", sizeof(char), 2, fp);fclose(fp);printf("%s\n",text);}}

并且,有参数传进来的话,也希望把出错时候的参数保存下来,所以主函数需要接受参数:

int main(int argc, char **argv)
{...
}

argc表示参数的个数,argv表示参数,其中argv[0]是命令本身,从1开始表示参数。把参数信息整合出来:

void formatLogInfo(int argc, char **argv, char * info)
{for (int i=1;i<argc;i++){char tmp[1024]={0};snprintf(tmp,1024,"%s parameter[%d]=%s",info,i,argv[i]);snprintf(info,1024,"%s",tmp);}
}

所以最终的运行CPP文件:

#include "myplot.h"
#include "string.h"#include "time.h"
#include <fstream>
#include <iostream>using namespace std;void WriteLog(const char* text)
{char LOG_FILE[1024]={0};// get the time nowtime_t now=time(0);tm *ltm = localtime(&now);snprintf(LOG_FILE,1024,"./log/log_%04d%02d.txt", ltm->tm_year+1900,ltm->tm_mon+1);// if LOG file not exist, then create it!fstream f1;f1.open(LOG_FILE,ios::in);if(!f1){f1.close();f1.open(LOG_FILE,ios::out);f1.close();}// write info in log file!FILE *fp;fp=fopen(LOG_FILE, "a+");if (fp != NULL){char ltime[1024] = { 0 };strftime(ltime,1024,"%Y-%m-%d %H:%M:%S ", ltm);		fwrite(ltime, sizeof(char), strlen(ltime), fp);fwrite(text, sizeof(char), strlen(text), fp);fwrite("\r\n", sizeof(char), 2, fp);fclose(fp);printf("%s\n",text);}}void formatLogInfo(int argc, char **argv, char * info)
{for (int i=1;i<argc;i++){char tmp[1024]={0};snprintf(tmp,1024,"%s parameter[%d]=%s",info,i,argv[i]);snprintf(info,1024,"%s",tmp);}
}int main(int argc, char **argv)
{// 初始化mclmcr,如果没有这两句可能会有访问错误的问题mclmcrInitialize();if (!mclInitializeApplication(NULL, 0)){char info[1024]="mclInitializeApplication failed!";formatLogInfo(argc,argv,info);WriteLog(info);return -1;}printf("mclmcr Initialized!\n");//初始化应用if (!libmyplotInitialize()){char info[1024]="libmyplotInitialize failed!";formatLogInfo(argc,argv,info);WriteLog(info);return -2;}printf("myplot Initialized!\n");// 初始化数据并做数据转化double data[5] = { 1,2,3,4,5 };mxArray *y = mxCreateDoubleMatrix(5, 1, mxREAL);memcpy((void*)mxGetPr(y), (void*)data, sizeof(data));const char *title = "mytile";mxArray* mytitle = mxCreateString(title);printf("data  Initialized!\n");//调用主函数if(!mlfMyplot(y, mytitle)){char info[1024]="mlfMyplot function failed! Please check the parameter(s)!";formatLogInfo(argc,argv,info);WriteLog(info);return -3;}// 关闭应用libmyplotTerminate();return 0;

  1. matlab函数编译dll,vs调用该dll的方法, https://blog.csdn.net/a15216111693/article/details/79232288 ↩︎

  2. 填坑VS2017与MATLAB2016b混合编程(生成dll方式), https://blog.csdn.net/qq_20515461/article/details/81229726 ↩︎

  3. mxArray数据类型, https://blog.csdn.net/snowfoxmonitor/article/details/79121178 ↩︎

  4. Linux下c++调用自己编写的matlab函数:通过mcc动态链接库.so实现, https://www.it610.com/article/5486435.htm ↩︎

  5. error adding symbols: DSO missing from command line(在CMakeList中的解决方法), https://blog.csdn.net/lzRush/article/details/84579692 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WinCE中的RAM-Based Registry与HIVE-Based Registry

WinCE支持两种类型注册表&#xff1a;RAM-BasedHIVE-Based&#xff0c;默认使RAM-Based注册表。 1.RAM-Based注册表 RAM-Based注册表所有注册表数据存储象存储(object store)&#xff0c;就存放RAM里面。般有电池备份RAM系统面&#xff0c;就说&#xff0c;当系统掉电以&#…

验证日期时间的正则表达式

可以不要秒数的: ^((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][123…

【转】Linux下c++调用自己编写的matlab函数:通过mcc动态链接库.so实现

转自&#xff1a;Linux下c调用自己编写的matlab函数&#xff1a;通过mcc动态链接库.so实现_Jaster_wisdom的专栏-CSDN博客 之前在这里和这里调用了matlab自带的一些函数&#xff0c;是通过matlab引擎来实现的。那里调用的是matlab自带的函数&#xff0c;那么如果想调用自己写的…

C#连接数据库SQL(2005)

首先来总结一下进行数据库编程的全过程,这里用的是SQL SERVER(1) 建立SqlConnection对象以连接数据库SqlConnection mysqlconnectionnew SqlConnection("Serverlocalhost; databaseyourdatabase;uidsa;pwdsa");(2) 建立SqlCommand对象SqlCommand mysqlcommandmysqlco…

MULTI BIN的wince 5.0,smdk2440下的实现

原本早就要发出来了&#xff0c;但是看到king_sundi网友已经发过一个帖子了&#xff0c;所以犹豫了没有发&#xff0c;相对而言&#xff0c;我这个总结更具有实用性&#xff0c;基本上照着这个步骤来就能成功&#xff0c;我给我几个朋友试过了&#xff0c;他们一开始对这个基本…

【转】gcc/g++ 链接库的编译与链接

转自&#xff1a;gcc/g 链接库的编译与链接_Surge-CSDN博客_g 链接 gcc/g 链接库的编译与链接 surgewonggmail.com Surge_surgewong_CSDN博客 程序编译一般需要经预处理、编译、汇编和链接几个步骤。在实际应用中&#xff0c;有些公共代码需要反复使用&#xff0c;就把这些代…

常用WebServices返回数据的4种方法比较

以前经常在群里听到朋友们说WebServices的性能特别的慢&#xff0c;说的如何如何。说实话&#xff0c;WebServices的确比调用本地数据要慢一些&#xff0c;可是究竟有多慢&#xff0c;真的如朋友们说的那么难以忍受吗&#xff1f;我个人感觉&#xff0c;多半原因在处理的方式上…

让S3c2410里拥有HIVE注册表的 全部步骤

首先&#xff0c;我是花了几天的时间才搞好的&#xff0c;当然我也在网上找了很多资料&#xff0c;可是网上朋友说可行的方法&#xff0c;我试来试去就是不行&#xff0c;这我也不清楚为什么&#xff0c;一开始有说用到BINFS格式的[指NandFlash分区格式]&#xff0c;后来又看到…

【转】vscode下编译告警“undefined reference”?三步教你如何解决

转自&#xff1a;vscode下编译告警“undefined reference”&#xff1f;三步教你如何解决_squall0984的博客-CSDN博客 近些年来&#xff0c;由于VS Studio体积庞大、价格昂贵等原因&#xff0c;越来越多的C/C开发者转投VSCode的怀抱。VSCode有着免费1、开源2、多平台支持、占…

写在S3C2440A平台+winCE5.0+NAND +HIVE注册表的实现

最近一直弄这个注册表的永久保存&#xff0c;在网上看到很多相关的贴子&#xff0c;就像大部分人说的一样&#xff0c;很少有人照着做就可以成功的。 今天总算成功了&#xff0c;总结经验如下&#xff0c;但愿对后来者有所帮助。 首先&#xff0c;要实现注册表的永久保存&…

非常实用的Asp.net常用的51个代码

1.弹出对话框.点击转向指定页面 Code: Response.Write("<script>window.alert(该会员没有提交申请,请重新提交&#xff01;)</script>");Response.Write("<script>window.location http://www.msproject.cn/index.asp</script>");…

【转】VScode tasks.json和launch.json的设置

转自&#xff1a;VScode tasks.json和launch.json的设置 - 知乎 目录 C&#xff08;方法1&#xff1a;不使用VSCode插件&#xff0c;较繁琐&#xff09;C&#xff08;方法2&#xff1a;使用Native Debug插件&#xff09;C&#xff08;方法3&#xff1a;使用C/C Compile Run插…

小处见大问题

如果有以下几种很简单的需求&#xff0c;可是小需要中隐藏着大问题。 给页面添加4个web按钮&#xff0c;点击4个按钮分别实现 &#xff08;1&#xff09;打开一个摸态对话框 &#xff08;2&#xff09;页面在客户端转向 &#xff08;3&#xff09;页面转向并且进行一个服务器端…

巧手定制Windows CE系统

嵌入式系统正在日益广泛的应用于各个方面&#xff0c;嵌入式系统的最大特点在于其精简和实时性。公司近期委派我负责一个新的嵌入式系统项目&#xff0c;因为是小型设备&#xff0c;所以我面临的第一个难题是需要找一个体积少&#xff0c;但非常灵活添加外围接口的嵌入式系统。…

【转】vscode配置C/C++环境

转自&#xff1a;vscode配置C/C环境 - 知乎 VS Code配置作者&#xff1a;谭九鼎 链接&#xff1a;Visual Studio Code 如何编写运行 C、C 程序&#xff1f; - 知乎 有改动。个人按照步骤后&#xff0c;做到复制上三个json那一步&#xff0c;就可以运行了。 我将settings.json…

Boot Loader的启动流程和开发经验总结

Windows CE最大程度继承了桌面版Windows的丰富功能&#xff0c;但是Windows CE并不是一个通用的安装版操作系统。在形形色色的嵌入式设备世界里&#xff0c;一款CE系统通常只会针对某一种硬件平台生成。 一般来说&#xff0c;Windows CE的开发过程可以分为&#xff1a;0AL…

c# 相对路径的一些文献

1.获取和设置当前目录的完全限定路径。string str System.Environment.CurrentDirectory;Result: C:\xxx\xxx2.获取启动了应用程序的可执行文件的路径&#xff0c;不包括可执行文件的名称。string str System. Windows .Forms.Application.StartupPath;Result: C:\xxx\xxx3.获…

【转】dicom网络通讯入门(1)

转自&#xff1a;dicom网络通讯入门&#xff08;1&#xff09; - assassinx - 博客园 如果只看标准就会越看越糊涂&#xff0c;根本原因就是因为dicom抽象得太严重&#xff0c;是“专家”弄的。没办法。 那么到底服务类是什么&#xff1f;sop 又是什么&#xff1f;&#xff0…

三种嵌入式操作系统的分析与比析

1.1 嵌入式系统 嵌入式系统是以嵌入式计算机为技术核心&#xff0c;面向用户、面向产品、面向应用&#xff0c;软硬件可裁减的&#xff0c;适用于对功能、可靠性、成本、体积、功耗等综合性能有严格要求的专用计算机系统。 嵌入式系统应具有的特点是&#xff1a;高可靠性&#…

用WebORB实现flex + .net后台的Remoting

实现flex与后台通信最简单的方式是采用httpServic的方式&#xff0c;或webservice。但这两种方式都是基于文本的传输&#xff0c;传输效率低&#xff0c;采用RemoteObject的方式&#xff0c;传输的内容采用AMF3格式的二进制编码&#xff0c;效率较高&#xff0c;并且能实现远程…