第14章 编译工具箱
使用MATLAB 7.0的读者在感叹其运算功能强大的同时,往往希望程序可以运行的更快;希望获得可以摆脱MATLAB 7.0环境而独立运行的可执行软件。而MATLAB 7.0推出的编译器Compiler 4.0正是满足用户这些需求的软件。本章将重点向读者介绍MATLAB 7.0编译工具箱的使用。
14.1 编译器概述
MATLAB 7.0 Compiler 4.0是将M文件作为它的输入,而产生可以重新分配的,并且是独立运行的应用程序或相应的软件组件。这些生成的应用程序以及软件组件都是与平台相关的。MATLAB 7.0编译器可以产生下面几种应用程序或软件组件:
· 独立运行的程序:独立运行的程序顾名思义是在其运行的过程中可以不需要MATLAB 7.0软件的同时运行,甚至它们可以在没有安装MATLAB 7.0的机器上运行;
· C和C++共享库(在Windows操作系统中为动态链接库DLL):这些共享库可以在没有安装MATLAB 7.0的用户机器上运行;
· Excel附件:需要MATLAB 7.0 Builder;
· COM对象:需要MATLAB 7.0 Builder。
本章着重介绍前面两种类型的应用程序,而对于后面两种软件附件,在下面的章节进行相关介绍。
在进入正题之前,这里需要说明的是MATLAB 7.0编译器同MATLAB 7.0解释器之间的区别。MATLAB 7.0解释器是指可以执行MATLAB 7.0命令、可执行的M文件以及MEX文件的应用程序,事实上,当我们使用MATLAB 7.0的时候,也就是在使用MATLAB 7.0的解释器。而MATLAB 7.0编译器是指将M文件作为其输入,同时生成独立的可执行文件或相关软件组件的程序,它可以由mcc命令调出。
14.2 编译器的安装和配置
14.2.1 配置MATLAB 7.0编译器的前提准备
MATLAB 7.0在第一次使用其编译器时,将会自动对其进行适当的配置。然而,MATLAB 7.0编译器的最初配置可以随时进行手动更改。下面将对此进行详细介绍。
1.安装ANSI C/C++编译器。
在用户的计算机上,应事先安装以下任何一种与MATLAB 7.0适配的ANSI C/C++编译器:
· Lcc C:由MATLAB 7.0自带,只是一个C编译器,不能用来编译C++;
· Borland C++:版本为5.3、5.4、5.5、5.6;
· Microsoft Visual C/C++(MSVC):版本为6.0、7.0和7.1。
2.安装MATLAB 7.0 Compiler。
MATLAB 7.0 Compiler的安装过程一般包含在安装MATLAB 7.0之中,当用户选择Typical的安装模式时,MATLAB 7.0 Compiler会被自动选为MATLAB 7.0的安装组件。当用户选择Custom安装模式时,在默认情况下,MATLAB 7.0 Compiler选项是被选中的,如图14-1所示。
图14-1 MATLAB 7.0安装选项图
14.2.2 对编译器进行配置
本节将向读者介绍如何配置C或C++编译器,使其可以与MATLAB 7.0编译器一起进行工作。在MATLAB 7.0中,函数命令mbuild可以大大地简化了配置C或C++编译器的过程。一般而言,用户仅仅需要使用mbuild命令中的setup选项就可以轻松的设置好第三方编译器。
说明:在很多数的情况下,当用户将第三方编译器安装到其默认路径下时,是不需要运行mbuild-setup命令的。
当选用一个同MATLAB 7.0编译器相关联的C或C++编译器时,可以使用命令mbuild,同时加上参数-setup,代码设置如下:
命令执行结果代码如下:
选择n,从而手动选择编译器。
这里选择11,即Microsoft Visual C/C++ version 6.0。
选择y,表示接受当前编译器的选择。
再次确认编译器的选择。
14.3 MATLAB 7.0编译器的使用
14.3.1 编译过程
MATLAB 7.0编译器4.0版本采用了MATLAB 7.0 Component Runtime(MCR)技术,它是一组用来保证M文件执行的独立的共享库。MCR提供了对MATLAB 7.0语言的完全支持。除此之外,MATLAB 7.0编译器4.0版本还采用了Component Technology File(CTF)存档来组织配置文件包。所有的M文件均采用了高级加密标准(AES)进行了密钥为1024位的加密,保存位CTF格式。每一个由MATLAB 7.0编译器生成的应用程序或者共享库均有一个与之相对应的CTF存档,其中包括了所有的基于MATLAB 7.0的M文件、MEX文件等。
在MATLAB 7.0编译器中,生成独立文件或软件组件的过程是完全自动的。例如,为了生成一个独立运行的MATLAB 7.0应用程序,用户只需要提供一系列用来构成应用程序的M文件,然后编译器将会自动执行以下操作:
· 依赖性分析:分析判断输入的M文件、MEX文件以及P文件所依赖的函数之间的关系,其中这些函数包括了输入文件所调用的M文件以及MATLAB 7.0提供的函数;
· 代码生成:生成所有用来生成目标组件的代码,其中包括:与从命令行中获得的M函数相关的C或C++接口代码,对于共享库和组件来说,这些代码还包括了所有的接口函数;组件数据文件,其中包含了运行时执行M代码的相关信息,这些信息中有路径信息以及用来载入CTF存档中M代码的密钥;
· 存档生成:在依赖型分析中生成的MATLAB 7.0可执行程序列表被用来生成CTF存档文件,其中包括程序运行时所需组件的数据。存档在加密后被压缩位一个单独的文件,同时路径信息也被保存;
· 编译:编译生成的C或C++文件,得到目标代码。对于那些含有用户提供C或C++代码的目标,这些代码同样会被编译;
· 链接:将生成的目标文件以及相关的MATLAB 7.0库链接起来,并生成最终的组件。
14.3.2 MCR的安装
为了能够使用MATLAB 7.0编译器生成的组件,用户的机器上必须装有MCR。下面介绍其具体的过程。
首先在MATLAB 7.0根目录下的\toolbox\compiler\deploy\win32目录下,将MCRInstaller.exe拷贝到其他路径,然后双击进行安装,如图14-2所示。
图14-2 MCR安装图示
然后选择安装路径,如图14-3所示。
图14-3 选择MCR安装路径
按照提示继续安装,直到提示安装结束。
14.3.3 编译指令mcc
不管是想生成独立外部可执行程序,或者是想创建一个C共享库以及软件组件,只要源码是M文件,那么都可以借助编译命令mcc实现。用户可以在MATLAB 7.0环境中以及DOS或UNIX命令行环境中使用mcc指令。
用户可以声明一种或多种MATLAB 7.0编译器参数给mcc指令。大部分参数的名字由一个字母组成,用户可以独立地使用两个参数,如下面地示例代码:
Macros是MathWorks公式提供的用来简化编译任务编译参数,它使用户在面对一个简单问题的时候可以不再亲自手工组合多种参数来实现某种特定的编译过程,而是仅仅使用参数-m即可。
有了Macros参数,在处理大部分的编译问题时,我们均可以简单地键入下面格式的编译命令:
14.3.4 创建独立的应用程序
为了说明编译的具体过程,下面举两个例子,分别代表不同类型的编译过程。
1.M文件
建立一个脱离MATLAB 7.0环境,并可独立运行的外部程序。该程序的功能是对于给定矩阵A,如果存在S使得S-1AS=,则要求出一个S,否则给出信息说明所给的矩阵不能对角化。
首先编写两个M函数文件,即exm2.m和exm2_f.m(第一个文件是主文件)。
exm2.m的代码如下:
exm2_f.m的代码如下:
把这两个函数文件保存在在用户自己的目录,例如d:\matlab7\work,并在MATLAB 7.0中运行检验,代码设置如下:
得到结果如下:
生成独立的外部可执行程序。在MATLAB 7.0指令窗口中,运行如下指令:
打开DOS窗口,在d:\matlab7\work目录下,运行exm2.exe,得到结果如图14-4所示。
图14-4 在DOS窗口运行生成程序exm2.exe所得的结果
2.M文件和C文件混合
本例给出了如何在C语言文件中调用编译过的M函数。考虑一个由两部分组成的程序:
· multarg.m:其中包含一个函数multarg;
· multargp.c:其中包含一个C语言函数main。
multarg.m中包含的multarg函数包含两个输入参数和两个输出参数。源代码如下:
multargp.c中的main函数调用multarg.m文件中的multarg函数,并显示multarg函数的返回值。源代码如下:
将上述两个程序分别保存到用户工作目录下,在MATLAB 7.0的运行环境中,对两个文件进行编译链接。
可以得到运行结果如图14-5所示。
图14-5 混合源码运行结果
3.包含绘图指令的M文件
由于安装了MCR,因此在编译的过程中可以加入MATLAB 7.0图形库。
定义M文件test_plot.m,源代码如下:
在MATLAB 7.0命令窗口中输入如下代码:
得到编译链接后的文件test_plot.exe。双击执行,可以得到结果如图14-6所示。
图14-6 带绘图指令的M文件编译运行结果
4.由含feval指令的M文件生成EXE文件
feval指令的特殊之处在于它的第一个输入参量是函数名字符串。这里要讨论的是当M源文件包含该指令时,将如何从这个源文件获得EXE文件。在MATLAB 7.0中给出了编译注记(Pragmas)处理feval对函数的调用。其格式为:
编译注记提示MATLAB 7.0编译器在编译的过程中需要将函数列表(function_name-list)中的函数均包含进去,而无论编译器的依赖性分析过程中是否定位到函数列表中的函数。当然,用户也不可将编译注记指向不存在的函数。
下面是一个采用编译注记的例子,由两个函数组成mywindow.m和test1.m。其中test1用来调用mywindow.m文件。
mywindow.m文件的内容为:
test1.m文件的内容为:
对主文件进行编译,可以产生符合要求的独立可执行程序test1.exe。
程序执行结果如图14-7所示。
图14-7 含feval指令的M文件编译运行结果