記得Support Packages要添加。
然後有一點比較重要的是,目前在包裝成C++ dll的API上有兩種方式,分別是:
MATLAB Data API(C++11) (since R2018a)
mwArray API(C++03)
mwArray API是比較舊也早期的用法,但也是目前大多數人所使用的方式,不過官方有列出一系列使用MATLAB Data API的好處,可以參考以下連結:
在Library Compiler的APP上要更改的話,會在下面那的API selection列中
關於MATLAB Data API(C++11) (since R2018a)與mwArray API(C++03)
大多人比較常使用,也是比較長年下來的使用方式都是使用mwArray居多,這是基於在C++03框架下發展出來的API,如果使用的話會產生出來的檔案如下:
而在較新一點的版本後提供的則是MATLAB Data API的方式,是基於在C++11的情況下所發展,所以實際上是比傳統的mwArray在整合上擁有更多的優勢,尤其是在管理runtime的生命週期上來得更加容易。
以下是將官網的介紹機翻:
MATLAB Compiler SDK 提供了兩種將 MATLAB 函式部署到 C++ 應用程式中的方式:
- 使用 MATLAB Data API 部署到 C++ 應用程式(C++11)
- 使用 mwArray API 部署到 C++ 應用程式(C++03)
由於 MATLAB Compiler SDK 使用兩種不同的 C++ 應用程式 API 與已部署的 MATLAB 函式進行交互,這兩種部署選項基於用於在 C++ 應用程式和已部署的 MATLAB 函式之間交換資料的 API 有所不同。
選擇 C++ 部署選項的關鍵在於了解每個選項的功能,並認識這些功能如何滿足你的開發需求。兩個選項都提供了一套完整的 API,用於處理應用程式管理和資料操作。
MATLAB Data API 相對於 MWArray API 的優勢
MathWorks 建議使用更現代的 MATLAB Data API,而不是 MWArray API 部署到 C++ 應用程式。使用 MATLAB Data API 相對於 MWArray API 的優勢包括:
- 減少資料複製操作。
- 無需顯式管理 MATLAB Runtime 實例和函式庫的生命週期,因為 C++ API 提供了安全的終止方式。
- Runtime 實例可以在 C++ 應用程式的進程中或外部運行,已部署的 MATLAB 函式可以同步或異步執行。
- 支援 C++11 功能、型別安全性和多線程安全性。
- 支援 MATLAB 代碼中的強型別。
- 自 R2018a 開始,複雜資料以 MATLAB 內部和 C++ 語言共用的交錯格式存儲,無需進行內部轉換。
產生的工件差異
當你將 MATLAB 函式或類別提供給 compiler.build.cppSharedLibrary
函式或 Library Compiler 應用程式時,對於兩種部署選項,生成的主要成果是不同的。
假設你有一個名為 calculateDistance
的 MATLAB 函式,儲存在一個名為 calculateDistance.m
的檔案中,並且希望在 C++ 應用程式中部署,讓我們來檢查這兩種部署替代方案的結果。
Visual Studio整合
在此段落會介紹兩種不同的API方式如何在Visual Studio上做整合,詳細的文件可以參考以下的段落:
https://www.mathworks.com/help/compiler_sdk/cxx/cpp-development-environment.html
- 基於MWArray API進行整合:
首先先創建專案,選擇C++並選擇Console APP來做創建。
切換成64位元環境
在專案的參數中做設定(點選紅圈處)
C/C++ > General > Additional Include中加入以下資訊
如果是有MATLAB環境:
C:\Program Files\MATLAB\R2023b\extern\include
如果是Runtime環境
C:\Program Files\MATLAB\MATLAB Runtime\R2023b\extern\lib\win64\microsoft
然後也要將轉出來的h檔放進這個路徑中(例如)
D:\Fred\CompilerSDK\yolo_c_mwarray
Linker > General > Additional Library Directories中加入以下資訊
在MATLAB環境:
C:\Program Files\MATLAB\R2023b\extern\lib\win64\microsoft
在Runtime環境
C:\Program Files\MATLAB\MATLAB Runtime\R2023b\extern\lib\win64\microsoft
將轉出來的h檔放進這個路徑中(例如)
D:\Fred\CompilerSDK\yolo_c_mwarray
Linker > Input > Delay Loaded Dlls 中加入以下資訊
<compilerSDKGeneratedLibrary>.lib
mclmcrrt.lib
Solutiom Explorer中加入.h與.dll & .lib等檔案。
建置好以上環境後,就可以撰寫一下的範例程式碼, 來呼叫dll中的function來做執行,而這邊的操作方式是在main function中先初始化啟動mcr,
"mclmcrInitialize();",並將主要調用dll的功能放在mclRunMain中做啟動,最後在使用mclTerminateAPPlocation,來關掉mcr的功能。
#include <iostream>
#include "YOLOv4DetectvC_04.h"
int run_main(int argc, const char** argv)
{
if (!mclInitializeApplication(nullptr, 0))
{
std::cerr << "Could not initialize the application." << std::endl;
return -1;
}
std::cout << "run mcr " << std::endl;;
if (!YOLOv4DetectvC_04Initialize())
{
std::cerr << "Could not initialize the YOLOV4." << std::endl;
return -2;
}
mwArray num;
try
{
YOLOv4Detect(1, num);
std::cout << "end" << std::endl << num << std::endl;
}
catch (const mwException & e)
{
std::cout << e.what() << std::endl;
}
mclTerminateApplication();
return 0;
}
int main(int argc, const char** argv)
{
mclmcrInitialize();
std::cout << "in try" << std::endl;
return mclRunMain((mclMainFcnType)run_main, argc, argv);
}
2. 基於MATLAB Data API進行整合:
在使用新版的MATLAB Data API進行整合時,在C++的環境設置上會跟先前的mwArray有所不一樣,以及在做相關變數的設定與呼叫上也不太相同,因此可以當作是兩者不同的技術來做使用。
本文後續會使用以下的範例來做操作,並且將環境設定與範例參考放在下方連結。
環境設定:Setting Up C++ Development Environment
範例參考:Deploy to C++ Applications Using MATLAB Data API (C++11)
首先先創建專案,選擇C++並選擇Console APP來做創建。
切換成64位元環境
在專案的參數中做設定(點選紅圈處)
C/C++ > General > Additional Include中加入以下資訊
如果是有MATLAB環境:
C:\Program Files\MATLAB\R2023b\extern\include
如果是Runtime環境
C:\Program Files\MATLAB\MATLAB Runtime\R2023b\extern\include
Linker > General > Additional Librry Directories中加入以下資訊
如果是有MATLAB環境:
C:\Program Files\MATLAB\R2023b\extern\include
如果是Runtimae環境
C:\Program Files\MATLAB\MATLAB Runtime\R2023b\extern\lib\win64\microsoft
Linker > Input> Additional Dependencies中加入以下資訊
delayimp.lib
libMatlabCppSharedLib.lib
libMatlabDataArray.lib
Linker > Input> Delay Loaded中加入以下資訊
libMatlabDataArray.dll
以下是在MATLAB中所使用的程式碼:
function distance = calculateDistance(p1, p2)
% This function calculates the Euclidean distance between two points
% Inputs:
% p1 - a two-element vector [x, y]
% p2 - a two-element vector [x, y]
% Output:
% distance - the Euclidean distance between p1 and p2
% Use arguments block to map C++ type to corresponding MATLAB type
% std::vector<int32_t> <--> (1,2) int32 {mustBeReal}
arguments (Input)
p1 (1,2) int32 {mustBeReal}
p2 (1,2) int32 {mustBeReal}
end
arguments (Output)
distance (1,1) int32 {mustBeReal}
end
% Calculte Euclidean distance
diff = p1 - p2;
diffSq = diff.^2;
sumSq = sum(diffSq);
distance = sqrt(sumSq);
end
使用MATLAB Data API include的情況請加入以下
#include “MatlabCppSharedLib.hpp”
接下來就是完整在C++中所建立的程式碼內容:
#include <iostream>
#include "MatlabCppSharedLib.hpp"
#include "D:\Fred\CompilerSDK\calculateDistance\for_redistribution_files_only\v2\generic_interface\calculateDistancev2.hpp"
std::shared_ptr<matlab::cpplib::MATLABApplication> setup()
{
auto mode = matlab::cpplib::MATLABApplicationMode::IN_PROCESS;
std::vector<std::u16string> options = { u"-nojvm" };
std::shared_ptr<matlab::cpplib::MATLABApplication> matlabApplication =
matlab::cpplib::initMATLABApplication(mode, options);
return matlabApplication;
}
// Initialize the code archive (.ctf file), specify input arguments, call the MATLAB function,
// and print the result
int mainFunc(std::shared_ptr<matlab::cpplib::MATLABApplication> app, const int argc, const char* argv[])
{
try {
auto libPtr = matlab::cpplib::initMATLABLibrary(app, u"calculateDistance.ctf");
std::shared_ptr<MATLABControllerType> matlabPtr(std::move(libPtr));
// Specify inputs using std::vector; no need to create matlab::data::Array objects
std::vector<int32_t> p1 = { 0, 0 };
std::vector<int32_t> p2 = { 3, 4 };
// Specify output type as int32_t, call MATLAB function, and print result
int32_t distance = calculateDistance(matlabPtr, p1, p2);
std::cout << "Euclidean distance between ["
<< p1[0] << ", " << p1[1] << "] and [" << p2[0] << ", " << p2[1] << "] is: "
<< matlabPtr << "\n";
}
catch (const std::exception& exc) {
std::cerr << exc.what() << std::endl;
return -1;
}
return 0;
}
// Call setup() to initialize MATLAB Runtime, use runMain() to run mainFunc(),
// and reset MATLAB Runtime after completion
int main(const int argc, const char* argv[])
{
int ret = 0;
try
{
auto matlabApplication = setup();
ret = matlab::cpplib::runMain(mainFunc, std::move(matlabApplication), argc, argv);
matlabApplication.reset();
}
catch (const std::exception& exc)
{
std::cerr << exc.what() << std::endl;
return -1;
}
return ret;
}
執行後就可以得到輸出的數值如下圖:
細部拆解整體的用法,在MATLAB階段就需要將變數的格式先做好定義,在C++環境中則是先啟動Runtime,所以設置了setup的函式,設定相關的runtime啟動方式與參數,以及下方mainFunc則是設定如何建立變數,以及呼叫Fnc做使用,詳細的一些變數設置與內容,未來可能再開一篇文章做深度介紹。