1. 程式人生 > >matlab 與c++混合編碼 (matlab .m檔案轉為c++的dll檔案)

matlab 與c++混合編碼 (matlab .m檔案轉為c++的dll檔案)



以前做過matlab7與c++的混合程式設計:將m函式編譯成dll給C++呼叫,從而加快開發的進度。但是今天在matlab2008b下面又做了一遍,發現matlab又改了很多東西,諸如增加了面向物件的的擴充套件mwArray,於是做筆記如下。

(一) 總體概念

matlab提供了豐富的程式介面,除了matlab最初的版本是用fortran寫的之外,後來的版本都是用C寫的,因此matlab很容易和C/C++聯合起來使用。

matlab有著豐富的庫函式,將這些庫函式直接編譯成dll(windows下是dll,linux下是類似於dll的另外一個東西),給C呼叫,可以加快工程進度。

步驟如下:

1. 設定matlab的編譯器,使用外部的VC或者gcc等編譯器。

2. 編譯m檔案成dll

3. 新增環境變數

4. 設定VC等的繼承環境,設定C需要用到的靜態庫和動態庫

5. 編寫C呼叫dll

下面以一個很簡單的加法函式為例,說明在VC6和matlab2008b下,怎麼做混合程式設計

(二) 設定matlab編譯器

過程如下:

1. 在matlab的command window裡面敲入mex –setup,matlab會列出所有電腦上所有的編譯器。

2. 選擇編譯器,這裡選擇2,即VC6

clip_image002

3.完成之後,敲入mbuild –setup,選擇build工具,matlab會列出所有的build工具,同樣選擇VC6

clip_image004

(三) 編譯m檔案

首先,寫出matlab函式,一個很簡單的加法函式,如下:

function [c] = MyAdd(a, b);

c = a + b;

儲存為MyAdd.m

然後,進行編譯,命令如下:

mcc -W cpplib:MyAdd -T link:lib MyAdd

(注,如果在此處提示"compliter"failed 錯誤時,可能是matlab版本沒有破解,我使用的是matlab2014a,後來下載了serial進行對應dll更新,就可以了,對應的serial在資源《matlab2014a混合c++程式設計 mcc提示“compliter”錯誤時,安裝的東東》中)

其中,mcc是matlab提供的編譯命令(可以理解為gcc),對於這一點,matlab的幫助說明如下:

-W lib:string link:lib

其中-W是控制編譯之後的封裝格式,cpplib,是指編譯成C++的lib,cpplib冒號後面是指編譯的庫的名字,-T表示目標,link:lib表示要連線到一個庫檔案的目標,目標的名字是後面的MyAdd,即你寫的m函式的名字。

執行完之後,你的目錄下面,將會出現以下一些檔案:

libMyAdd.cpp

libMyAdd.exp

libMyAdd.dll

libMyAdd.exports

libMyAdd.h

libMyAdd.prj

libMyAdd_mcc_component_data.c

mccExcludedFiles.log

readme.txt

具體每一個檔案的意思,請查幫助,這裡只說其中很有用的幾個:

libMyAdd.dll是編譯好的動態庫,MyAdd這個函式封裝在裡面,libMyAdd.h是對應的標頭檔案,在C裡面呼叫這個函式的時候,需要include這個標頭檔案,在這個標頭檔案的最後,你可以看到下面的內容:

extern LIB_libMyAdd_CPP_API void MW_CALL_CONV MyAdd(int nargout, mwArray& c

, const mwArray& a

, const mwArray& b);

這就是MyAdd的C函式的宣告。

nargout表示輸出變數的個數

a,b,c就是對應了m函式的幾個變數

注意,a,b,c三個變數的型別是mwArray,這是matlab提供的一個特殊的變數型別(在7.0的版本,編譯之後,變數型別是mxArray)。mwArray是一個類,具體可以查幫助,當然後面也會講到。

(四)設定環境變數

在環境變數/系統變數,path中新增matlab的.dll路徑:C:\Program Files (x86)\MATLAB\R2014a\bin\win32

在環境變數/使用者變數,新增新項,Matlab:C:\Program Files (x86)\MATLAB\R2014a\bin\win32

(五) 設定VC環境

有了上面的準備,需要設定VC環境,好讓lib和dll能被成功的呼叫。

1. 首先建立一個控制檯工程(這個我就不詳細講了,太easy了)

2. 然後,在tool-option-directory裡面設定用到的lib和include標頭檔案的位置

首先是include標頭檔案的位置,看最後一行(這個根據每一個人的安裝目錄可能不一樣,自己去找吧)

clip_image006

然後是lib的位置,不盡包括matlab的靜態庫的位置,還包括剛剛編譯出來的lib的位置(可以不用新增,直接在標頭檔案中新增#pragma comment(lib, "MyAdd.lib")  即可),見圖的後面兩個,不用我解釋吧

clip_image007

你可以開啟這兩個目錄,看看裡面到底有哪些標頭檔案和lib,首先來講,我們這裡要用到的標頭檔案包括:

#include "mclmcr.h"

#include "matrix.h"

#include "mclcppclass.h"

#include "libMyAdd.h"

lib包括

mclmcrrt.lib libmx.lib libmat.lib mclmcr.lib

你可以到具體的路徑下看一看,有沒有上面幾個lib和標頭檔案

路徑設好了,需要制定具體用到的lib了,在project Setting-link-Object/library modules裡面加入上面提到的幾個lib(具體幾個lib到底做什麼用的,這裡不講了,看幫助,或者你試驗刪去幾個lib能不能工作,就大概可以猜得到他們是幹什麼的了)

clip_image009

3. 將編譯好的dll複製到VC工程的Debug或者Release目錄下,以使得dll可以被找到。

(五) 寫Cpp呼叫dll

1.將.dll,.h,.lib三個檔案放入工程中。

2.將.h加入到工程中。

所有任務完成之後,開始寫Cpp試驗呼叫編譯之後的函數了。

首先,包含應有的標頭檔案:

#include "mclmcr.h"

#include "matrix.h"

#include "mclcppclass.h"

#include "libMyAdd.h"

#include <stdio.h>

#include <iostream.h>

#pragma comment(lib, "MyAdd.lib") (如果前面沒有將.lib的路徑放入vc屬性/庫目錄中的話,這句是需要的)

然後,寫main函式:

int main(void)

{

double a = 6;

double b = 9;

double c;

// initialize lib,這裡必須做初始化!

if (!MyAddInitializeWithHandlers(NULL, 0))   //首先進行這個東東的初始化,不然libMyAddInitialize()會提示“Initialization error"
{
printf("inintialize With Handlers failed");
return -1;
}

if( !libMyAddInitialize())

{

std::cout << "Could not initialize libMyAdd!" << std::endl;

return -1;

}

// 為變數分配記憶體空間,可以查幫助mwArray

mwArray mwA(1, 1, mxDOUBLE_CLASS); // 1,1表示矩陣的大小(所有maltab只有一種變數,就是矩陣,為了和Cpp變數接軌,設定成1*1的矩陣,mxDOUBLE_CLASS表示變數的精度)

mwArray mwB(1, 1, mxDOUBLE_CLASS);

mwArray mwC(1, 1, mxDOUBLE_CLASS);

// set data,不用我解釋了吧,很簡單的,呼叫類裡面的SetData函式給類賦值

mwA.SetData(&a, 1);

mwB.SetData(&b, 1);

// using my add,掉我自己寫的函式

MyAdd(1, mwC, mwA, mwB);

// get data,不用我解釋了吧,很簡單的,呼叫類裡面的Get函式獲取取函式返回值

c = mwC.Get(1, 1);

printf("c is %f\n", c);

// 後面是一些終止呼叫的程式

// terminate the lib

libMyAddTerminate();

// terminate MCR

mclTerminateApplication();

return 0;

}

執行結果如下:

clip_image010

結論,不行的,根本執行不了,執行到初始化時,有時能通過,有時卻說初始化失敗,原因不明!