1. 程式人生 > >Qt與matlab混合程式設計實現過程

Qt與matlab混合程式設計實現過程

最近專案需要,matlab的一些演算法需要工程用,因此需要直接轉成Qt能夠呼叫的形式,之前也做過類似的,但那個時候是使用vs2012,而且也沒怎麼做記錄,一些坑坑繞繞也都忘了,現在用Qt呼叫,感覺區別還是很大的。

環境:

Qt5.9 mingW(32位)

matlab2015b(32位)

vs2015

這裡要注意Qt官方釋出的qt安裝都是32位的,如果想要64位需要自己編譯,所以能做取捨的只有選擇32位的matlab,好在matlab不同版本可以完美相容。

vs2015是由於matlab的mbuild命令需要,要想使用編譯dll檔案就要使用mcc命令,要想使用mcc命令就必須配置好matlab的編譯配置,具體命令:

mbuild -setup

mex -setup

選擇vs2015的就行了。

當然這裡有其他的選擇,mbuild的時候也可以選擇window自帶的microsoft SDK,一般是7.1版本,你會發現它的版本和windows的版本是對應的7.1 8.1 10畢竟SDK中文就是software development kit(軟體開發包)嘛,版本號一一對應也是情理之中。

mex的時候也可以選擇matlab自帶的lcc,有時候需要自己手動安裝,但其實裝vs的效率是最高的,裝完mbuild和mex都有了,而且博主發現matlab2015b作為matlab最後一個32位版本似乎……不識別微軟的SDK10版本,emmmmmm這一點我沒法解決,有讀者解決了的話希望可以在評論區反饋給我。

第一步:將matlab程式寫成函式形式

第二步:將函式的.m檔案轉換成動態連結庫形式

matlab mcc命令:mcc -W cpplib:svm -T link:lib svm.m

將生成的.h.lib.dll檔案三個一起拷到程式碼所在的資料夾。

這裡就會有好奇寶寶問了,dll檔案不應該放到debug路徑下嘛?由於我採用的是動態呼叫,往後看你就知道了。

第三步:qt呼叫

這一步尤為關鍵,分步說:

1、巨集定義:

.pro檔案中一般需要新增很多很多

首先:

DEFINES += __MW_STDINT_H__

這個東西是針對matlab的mclmcr.h標頭檔案中第170行到第190行中編譯器的一些巨集的設定,一般來說如果是mingW編譯器我們一般寫+= __MING_W__,但是這個標頭檔案中並沒有給出mingW編譯器的情況,所以一般選擇加上上面這行程式碼,選擇一個編譯器的型別,如果不加,則會報錯如下:

D:\matlab2015b32\extern\include\mclmcr.h:278: error: 'mxUint64' has not been declared
     virtual int get_numeric(mxUint64* x, mwSize len) = 0;
                             ^

大致意思就是說64位的mxUint64沒有定義,你不要一看matlab的標頭檔案就慌,你好好看一看就會發現其實就是幾個if else而已,不要慌對不對。

還有大佬加上這一句

DEFINES += QT_DEPRECATED_WARINGS

這句我真沒發現有什麼用,我刪掉了……好像也沒報錯,emmmmmm字面意思似乎是遮蔽一些警告……我真不知道所以大家有知道什麼意思的希望可以在評論區告訴我一哈,相互交流嘛。

2.新增外部庫:

這裡要尤其感謝csdn上的這位友好的大佬ID qq657863206,這裡和下面一部分都是由這位大佬教會我的,當我順著他的id加他的qq的時候還在想會不會被拒絕,結果這位大佬友好負責地教會了我呼叫方法,他本人的一篇博文也是說這件事的,大家可以去看下,連結:https://blog.csdn.net/qq657863206/article/details/82354874

新增外部庫的方法:按照圖片一步一步走即可

點選下一步,你就會發現你的.pro檔案中多了幾行:

win32: LIBS += -L$$PWD/./ -lsvm

INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.

自己直接寫也可以,但前提是你得寫對哦~

3、新增matlab依賴以及標頭檔案

這個就相對簡單粗暴了,首先確認你的matlab路徑,然後複製貼上即可

LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -lmclmcrrt
LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -lmclmcr
LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -llibmx
LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -llibmat
INCLUDEPATH += D:/matlab2015b32/extern/include
DEPENDPATH += D:/matlab2015b32/extern/include

我的……就這麼多就夠了,網上有不少恨不得把所有的庫都填進去的……也沒差,反正這年頭你也不會一個字母一個字母地往上打,但這裡就涉及到一個問題,應該放多少呢……不知道,我真地不知道,反正我的就這麼幾行,程式好使,沒報錯,嗯。

當然還要注意,在你的標頭檔案中剛才你拷進去的.h檔案

4.動態呼叫

QLibrary myLib("svm.dll");
typedef bool MW_CALL_CONV(*Fun)(int,class mwArray &,class mwArray const &,class mwArray const &,class mwArray const &);
Fun svm = (Fun)myLib.resolve("[email protected]@[email protected]@[email protected]@Z");

這裡需要注意,加粗上紅字,嗯,emmmmmmmmmm

分條說:

1、我之前說過dll檔案和程式碼放一起吧,就是這樣,不放一起找不到

2、你需要一個軟體 dependency walker,這個軟體是幹嘛用的呢……看dll檔案中的函式用的,別慌,你別慌,別關網頁,這個真不難,咱都是用matlab的,都不是計算機科班出身,我都學會了你還能學不會?

這玩意就幾M,介面是這樣的

你唯一需要的就是左上角的開啟按鈕,使用它開啟dll檔案就這麼簡單,開啟你生成dll檔案你會發現

你會發現亂碼中夾著你寫的函式,我的是svm,什麼你的不是亂碼?那你右鍵點一下選擇取消修飾C++函式看看,必亂碼。

這是由於matlab使用vs的msvc編譯器生成的dll檔案,生成後我們使用mingW呼叫,mingW和msvc可是死對頭呀,一個開源一個閉源,不搞點事都不舒服斯基,使用vs呼叫matlab生成的dll時我記得就沒有這個問題,同時msvc編譯器一個媽生的,親兄弟當然不會亂碼。

但現在既然亂碼了我們怎麼處理呢,你看我上面那幾行就完事,其實就是用Qlibrary的resolve函式把亂碼換個函式名,僅此而已,亂碼可以從dependency walker中直接複製過來,函式原型當然也要對應著你自己的修改一下。

剩下的,完事了,再不完事這個代價就有點大了,講道理我費這麼大力氣(其實也沒……還好)做出dll,實際執行速度什麼的我還沒測試,這玩意……確實有點麻煩。

emmmmmmmmmmm總結

感謝大佬qq657863206是他將以上方法總結出來,由我總結髮出來的。

那麼回過頭來,qt呼叫matlab動態連結庫好處在哪?

1、qt做介面,matlab做演算法,二者相得益彰

2、相對於將演算法C++化,這樣做當然節約時間和成本

缺點:

1、程式執行速度尚未測試,儘管轉換為dll,我個人認為matlab甚至是官方並不重視這一需求,畢竟你不能對指令碼語言期望太高,因此我對其執行效率表示擔憂,不知道有沒有人瞭解這一塊,看在我碼了這麼多字的面子上能在評論區指點我一下。