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 文件。