在Visual Studio中使用C++中調用MATLAB程序
在matlab中可以通過mbuild工具將.m文件編譯成dll文件供外部的C++程序調用,這樣就可以實現matlab和C++混合編程的目的。
預先提示:這樣編出的程序仍要調用Matlab底層DLL庫,擺脫不了DLL底層庫的支持,如果移植到無matlab環境的機器,需要安裝MCR進行運行環境的支持。
本文檔記錄了Matlab 2019b,windows 10 x64, Visual studio 2015(解決方案平台為x64)的環境下的配置情況。
經過測試,本文檔的方法對R2016a Runtime環境不可用,會報錯.
准備matlab程序
編好matlab程序,例如,頂層應為如下格式:
function [c] = myAdd(a,b)
c=a+b;
return;
end
使用matlab生成dll(Dynamic Linked Library)文件
- 需要帶有mcc編譯器的matlab軟件,這個可以通過在matlab命令行中輸入:
!mcc
命令來查看: 仔細閱讀打印信息之后,可以看到mcc編譯器的命令使用方法。然后輸入mex -setup
設置語言為C++
。 - 然后在命令窗口輸入
mbuild -setup
選中要使用的 C++ 編譯器,而不是 C 編譯器,在這里請選擇你需要的C++編譯器,盡量與C++程序開發使用的編譯器保持一致。比如可以使用Visual Studio自帶的Microsoft Visual C++ 2015 Professional編譯器,或者其他IDE中的MINGW編譯器。 - 選好編譯器后在命令窗口輸入
deploytool
進入編譯窗口,在彈出的窗口中選擇 Library Compiler ,即生成dll動態鏈接庫的形式,之后會彈出如下窗口。 - 在
MATLAB Complie
對話框中的左上角APPLICATION TYPE
中選擇C++ Shared Library
類型,在旁邊的白色框中點擊加號將需要編譯成dll的.m文件添加到當前項目中,選擇API 類型為默認的Create all interfaces
,在Samples部分選擇Create New Sample
,然后點擊myAdd.m
可以看到生成了一個樣例文件。然后可以點擊右上角的package按鈕生成dll文件了。 - 等待一段時間之后就可以在指定的目錄下
for_redistribution_files_only
文件夾內看到生成dll以及相應的.h
和.lib
文件。
mwArray API interface對應
.h
,.dll
和.lib
; Matlab數據格式API對應v2
文件夾下的.ctf
等。
samples根據樣例.m文件,例化了可用的應用程序樣例文件.
在VS中調用matlab程序中的函數
- 使用Visual Studio新建一個win32的空的控制台項目,同時將剛剛生成的
myAdd.h
存放在當前項目目錄下,建立lib
文件夾(專門用來存放.lib
文件),將myAdd.lib
拷貝到該文件夾下,將myAdd.dll
存放在x64/Debug
目錄下。然后輸入C++的應用程序代碼:
#include <iostream>
#include "mclmcr.h"
#include "mclcppclass.h"
#include "matrix.h"
#include "myAdd.h"
//環境變量在安裝有matlab的機器上的設置為PATH: D:\Program\MATLAB\R2016a\bin\win64時可以正常運行。
//在Runtime環境下報錯
//
using namespace std;
int main()
{
if (myAddInitialize())//必須要初始化,格式為 [名字]Initialize()
{
cout << "初始化完成!" << endl;
}
else
{
cout << "初始化失敗!" << endl;
}
//定義3個mwArray類型變量,用於存放矩陣
mwArray a(2, 3, mxDOUBLE_CLASS);
mwArray b(2, 3, mxDOUBLE_CLASS);
mwArray c(2, 3, mxDOUBLE_CLASS);
double x[] = { 2,3,1,5,4,5 };
double y[] = { 8,8,7,9,11,12 };
double *sum = new double[6]; //注意這個是指針
// 給輸入 mxArray 對象賦值
a.SetData(x, 6);
b.SetData(y, 6);
//調用DLL函數
myAdd(1, c, a, b);
//獲取結果
c.GetData(sum, 6);
//輸出結果
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
cout << sum[j * 2 + i] << " ";
cout << endl;
}
cout << "it is successful !" << endl;
return 0;
}
- 然后點擊菜單欄下的項目->屬性,在項目屬性對話框VC++選項中,設置
包含目錄
為mylib.h
的存放目錄,以及matlab環境的包含目錄D:\Program Files (x86)\Matlab2018a\extern\include
。庫目錄
為mylib.lib
的存放目錄及MATLAB環境的庫目錄,如D:\Program Files (x86)\Matlab2018a\extern\lib\win64\microsoft
。鏈接器->輸入選項中,附加依賴項:
libmat.lib
libmex.lib
mclmcr.lib
mclmcrrt.lib
mclbase.lib
myAdd.lib
並拷貝matlab的lib文件到lib目錄中。
8. 依賴MATLAB環境運行:
環境變量中還要添加D:\Program Files (x86)\Matlab2018a\bin\win64
等才可以正常運行。如果沒有安裝matlab,還需要安裝MCR,並設置環境變量.
- 將上面生成的可執行文件
.exe
拷貝到你的Qt工程release/debug后生成的exe文件的同一目錄下,並在Qt中運行該.exe
程序即可。
補充知識:靜態編譯與動態編譯
- 靜態編譯:編譯器在把源文件(.cpp文件)編譯可執行文件(.exe文件)時,主程序中調用的函數接口通過查詢包含的頭文件(.h),把源文件中要調用的函數代碼,翻譯為庫文件(.lib),然后鏈接到可執行文件中去,使可執行文件在運行時不需要依賴於動態鏈接庫(.dll文件)。
- 動態編譯:編譯器在把源文件(.cpp文件)編譯可執行文件(.exe文件)時,主程序中調用的函數接口通過查詢包含的頭文件(.h),把源文件中要調用的函數代碼,翻譯為動態鏈接庫文件(.dll),然后鏈接到可執行文件(.exe)中,在運行時,可執行文件通過查詢導出庫(.lib)文件,在動態鏈接庫(.dll)中查找函數命令。所以其優點一方面是縮小了執行文件本身的體積,另一方面是加快了編譯速度,節省了系統資源。缺點一是哪怕是很簡單的程序,只用到了鏈接庫中的一兩條命令,也需要附帶一個相對龐大的鏈接庫;二是如果其他計算機上沒有安裝對應的運行庫,則用動態編譯的可執行文件就不能運行。
文件后綴名 | 文件名稱 | 作用 | 文件所在目錄的名稱 |
---|---|---|---|
.c ,.cpp ,.cc |
源文件 | 開發者用來寫程序的 | 源代碼目錄 |
.h |
頭文件 | 聲明應用程序的函數接口 | 包含目錄 |
.lib |
庫文件-附加依賴項 | 動態庫中的lib包括函數在DLL中的位置信息;靜態庫中不止包含位置信息,還有函數代碼 | 庫目錄 |
.dll |
動態鏈接庫文件 | 動態庫中的DLL文件包含了所有庫函數 | 庫目錄 |