SPM/SPM2 在 Windows 上的 MEX 編譯
SPM 華夏公益教科書已遷移至 https://www.fil.ion.ucl.ac.uk/spm/docs/ |
先決條件
| MinGW | www.mingw.org |
| Gnumex | sourceforge.net/projects/gnumex |
| Cygwin | www.cygwin.com |
介紹
SPM mex 檔案的原始碼引用了一些標頭檔案及其各自的編譯庫,這些檔案通常存在於 Unix/Linux 發行版中,但在 Windows 中不存在。為了克服這一限制,可以在 Windows 機器上安裝名為 Cygwin 的 Linux 環境,並在該環境中進行 mex 檔案編譯。僅在 Cygwin 中編譯 mex 檔案將要求 Cygwin DLL 與 mex 檔案一起分發才能使其工作。由於 Cygwin DLL 包含許多編譯後的 Unix 例程,因此它過於龐大。為了避免使用 Cygwin DLL,可以使用 MinGW(Windows 的最小 GNU)包來提供 SPM mex 檔案所需的最小 Unix 功能。
以下是我最終實現的方法(經過一些試錯和線上研究)作為在 Windows XP 上使用 Matlab R2007a 編譯 SPM2 的 mex 檔案的工作設定...
步驟 1: 設定 Gnumex
Matlab 的 mex 命令實際上是一個批處理檔案(在 unix 中是一個 shell 指令碼),它呼叫一個 perl 指令碼來執行所選編譯器以構建適當的 mex 檔案。執行 mex 時,它會諮詢 mexopts.bat 以找到選擇的編譯器及其命令列選項。通常,mexopts.bat 由 Matlab 在您執行 'mex -setup' 並從已安裝的編譯器列表中選擇一個編譯器時生成。Gnumex 代替執行此任務並生成適當的 mexopts.bat,以便 mex 命令在 Cygwin 或 MinGW 中呼叫編譯器(編譯器實際上是 gcc)。
如果您使用的是 Matlab R2007a 或更高版本,您需要編輯 gnumex.m 以適應您的版本。假設 Gnumex 安裝在 c:\gnumex 中,並且您已將其新增到 Matlab 路徑中,請從 Matlab 提示符執行 edit gnumex.m。從 gnumex.m 的第 619 行開始,有一個 if/elseif 塊檢查變數 mlv(從 Matlab 的 version 命令獲得),此檢查僅達到版本 7,我們需要新增一個塊來處理 7.4。在第 648 行,將 end 替換為
else % matlab R2007
mexdefs = {};
engdefs = {};
fmexdefs = {};
fengdefs = {};
end
現在您可以從 Matlab 提示符執行 gnumex 並設定如下所示的選項

以上選項假定您已將 Gnumex 安裝到 c:\gnumex,並將 MinGW 安裝到 c:\mingw。現在點選 Make opts 按鈕。Gnumex 本身使用 2 個 mex 檔案 shortpath.dll 和 getpath.dll(準確地說),因此,如果您收到類似的錯誤
??? Undefined function or method 'shortpath' for input arguments of type 'char'.
Error in ==> gnumex at 567
s = shortpath(s);
Error in ==> gnumex at 591
pps = gnumex('parsepaths', pstruct);
??? Error using ==> gnumex('makeopt')
Undefined function or method 'shortpath' for input arguments of type 'char'.
??? Error while evaluating uicontrol Callback
您可能需要 SPM/Compile the gnumex mex files,以便它們可以與您的 Matlab 版本一起使用,在您使用 gnumex 本身之前。
同樣,如果您使用的是 Matlab R2007a 或更高版本,您現在需要編輯 Gnumex 生成的 mexopts.bat 檔案,以使其與您的 Matlab 版本一起使用。預設情況下,該檔案位於
C:\Documents and Settings\USERNAME\Application Data\MathWorks\MATLAB\R2007a
將以下幾行新增到 mexopts.bat 中 'Added libraries for linking' 部分的正下方,替換現有的 set GM_ADD_LIBS 行
set ML=C:\PROGRA~1\MATLAB\R2007a\extern\lib\win32\micros~1 set GM_ADD_LIBS=%ML%\libmx.lib %ML%\libmex.lib %ML%\libeng.lib %ML%\libmat.lib
步驟 2: 編輯 Makefile
與 SPM2 原始碼一起提供的 Makefile 需要幾個額外的選項,以便編譯器在編譯/連結時知道在哪裡搜尋標頭檔案和庫檔案。在大約第 60 行,您應該看到類似以下內容
make all SUF=dll CC="gcc -mno-cygwin -O3 -funroll-loops -fomit-frame-pointer ...
在 CC= 語句的雙引號內,可能有一些選項,例如
-I/some/path or -L/some/path
可能安全地刪除這些預設值並插入以下內容
-DMINGWPIDT -I./ -I/cygdrive/c/mingw/include -L/cygdrive/c/mingw/lib -L/cygdrive/c/progra~1/matlab/r2007a/extern/lib/win32/micros~1
步驟 3: 編輯 win32mmap.h
開啟 c:\spm2 中的標頭檔案 win32mmap.h。在大約第 23 行,您應該看到
typedef int pid_t;
但對於我們的編譯,我們將使用來自 MinGW 的 pid_t 定義,因此將此行包裝在 #ifndef 語句中
#ifndef MINGWPIDT typedef int pid_t; #endif
這將告訴編譯器,如果定義了 MINGWPIDT(它被定義了,因為添加了 -DMINGWPIDT 選項到 Makefile),則不要使用 SPM 提供的檔案中的 pid_t。
步驟 4: 編譯
啟動 Cygwin 並更改目錄到 SPM2 資料夾。Cygwin 具有類似 Unix 的檔案系統結構,但維護了 /cygdrive 中的驅動器號資料夾列表,因此,如果您將 SPM2 安裝到 c:\spm2 中,那麼
user@localhost~ $ cd /cygdrive/c/spm2
user@localhost/cygdrive/c/spm2 $ make windows
如果您需要重新編譯,最好 'clean' 構建環境,即刪除上次呼叫 'make' 留下的臨時檔案和中間檔案。您可以使用以下命令來執行此操作
user@localhost/cygdrive/c/spm2 $ rm *.o; rm *.a; rm *.dll
希望一切順利,您沒有遇到任何錯誤,您現在應該擁有用於 SPM2 的一組工作的 dll 檔案。