日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/10 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】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;
  • matlab函數編譯dll,vs調用該dll的方法, https://blog.csdn.net/a15216111693/article/details/79232288???

  • 填坑VS2017與MATLAB2016b混合編程(生成dll方式), https://blog.csdn.net/qq_20515461/article/details/81229726???

  • mxArray數據類型, https://blog.csdn.net/snowfoxmonitor/article/details/79121178???

  • Linux下c++調用自己編寫的matlab函數:通過mcc動態鏈接庫.so實現, https://www.it610.com/article/5486435.htm???

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

  • 總結

    以上是生活随笔為你收集整理的【转】matlab与C/C++混合编程——在Windows/Linux上调用Matlab编译的动态库文件的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。