最近在尝试进行java和MatLab的混合编程,主要目的就在于将MatLab中的函数打包为jar,从而可以在Java中进行调用。期间碰到了很多问题,在此记录一下备忘。
关于如何通过MatLab提供的deploytool将.m文件打包为jar,在网上已经可以搜索到很多图文并茂的教程了,官方也都提供了比较详细的说明:
在此要强调一下在这一步需要注意的版本同步和路径添加问题:
version -java
命令即可查看MatLab中java的版本。可以通过配置环境变量MATLAB_JAVA
改变MatLab使用指定的java;\toolbox\javabuilder\jar\\javabuilder.jar
中找到;上述几点在打包后生成的/for_redistribution_files_only/readme.txt
文件中也都有详细的说明。
本人一开始是在Windows上的MatLab中将m文件打包,并且测试也都通过,可以在java程序中正常调用。但是当部署到Linux服务器上运行的时候却报错:
Undefined variable "images" or class "images.internal.imlincombc".
Error in imlincomb (line 74)
Error in rgb2ycbcr (line 104)
就是在调用rgb2ycbcr函数的时候报的错。于是在MatLab中调试发现确实在
中调用了images.internal.imlincombc
函数。在MatLab中使用如下命令发现该函数存在于一个mex文件中:
>> which -all images.internal.imlincombc
D:\software\MatLab2017b\toolbox\images\images\+images\+internal\imlincombc.mexw64 % static method or package function
查看官方文档中对MEX文件的说明了解到MEX文件是一种编译好的C/C++的二进制文件,不像m文件是跨平台的。不同平台中的MEX文件后缀都不一样:
此时就考虑到应该是在Windows上通过deploytool打包的jar并不能在linux上使用。于是尝试在Linux下进行打包。
由于使用的是CentOS系统,并没有图形化用户界面(GUI)。因此在MatLab中运行deploytool时直接报错:
>> deploytool
Error using compiler.internal.launchui (line 20)
Java exception occurred:
java.awt.HeadlessException
at java.awt.GraphicsEnvironment.checkHeadless(Unknown Source)
at java.awt.Window.(Unknown Source)
at java.awt.Frame.(Unknown Source)
at javax.swing.JFrame.(Unknown Source)
at com.mathworks.mwswing.MJFrame.(MJFrame.java:108)
at com.mathworks.mwswing.MJFrame.(MJFrame.java:101)
at com.mathworks.toolbox.compiler.desktop.DeploytoolLaunchPad.(DeploytoolLaunchPad.java:46)
at com.mathworks.toolbox.compiler.desktop.DeploytoolLaunchPad.launch(DeploytoolLaunchPad.java:155)
Error in deploytool (line 38)
compiler.internal.launchui(mfilename,varargin{:})
查看官方文档中对deploytool命令的说明,发现可以使用deploytool -package project_name
直接进行打包。但报错:
>> deploytool -package myproject
Error: The specified project file doesn't exist:/root/myproject.prj
看来还需要新建一个project,而就算在官网上查找到的创建项目文档都还是使用GUI进行的,并未搜索到通过命令行创建项目并配置的方法。
于是就想到是否可以通过修改在Windows上通过deploytool进行打包时保存的prj文件在Linux服务器上使用。使用文本编辑器打开prj文件,就发现该文件类似xml文件,其中就是保存了一系列的配置信息。根据tag基本上也可以猜测出含义。主要进行了如下几处修改:
标签中,将file、location修改为服务器上对应文件的位置;
应该就是应用名称,不作修改;
,
,
,
应该就是在deploytool的settings中各种Output Folders的设置。而这些标签中都使用了变量${PROJECT_ROOT}
,故也不作修改;
这个标签目前还不清楚用处,暂时写空;
中的
子标签中的value,一定要修改为服务器上m文件对应的路径;
中的
子标签中的name属性也就是类名,其中的
子标签中的value,也一定要修改为服务器上m文件对应的路径;
标签中的value也最好修改为服务器上的输出路径;
则是比较重要的配置了,其中
子标签就是MatLab的安装路径,修改为服务器上对应的路径即可。其他的toolbox配置不做修改;
更是重中之重,既然目标平台变为了Linux,则将
,
都设置为true,
也从win64修改为amd64;之后就将修改后的prj文件上传至服务器上,并在matlab中运行deploytool -package myproject
命令。等待数分钟,便成功在prj对应的设置的位置发现了打好的jar包。将该jar包替换之前从Windows平台上打出的jar包,再次运行程序,没有报错,成功运行!
由于本人对事物背后的原理比较纠结,所以又去Matlab官方文档中搜索了一下。发现官网上有对如何确保跨平台使用导出包的详细说明。其中也确实指出了跨平台的问题主要就是由于文件中使用了平台依赖的MEX文件导致的,并给出了解决方案:
https://ww2.mathworks.cn/help/compiler_sdk/java/ensuring-multi-platform-portability.html
可以看到其实MatLab背后主要使用的都是mcc命令进行的编译和打包发布。deploytool只是一个图形化的工具,在通过该工具打包后的日志中也可以发现,其背后实际上也是运行了mcc命令。故看来还是需要对该命令进行深入学习。MCC的官方文档见下:
https://ww2.mathworks.cn/help/compiler_sdk/ml_code/mcc.html
目前Matlab不像Python和TensorFlow那么火爆,所以在网上较难搜索到丰富的资源。在本次尝试MatLab与java混合编程的过程中,发现官方文档已经是比较完整和可靠的资源。比如如何在命令行编译打包java程序,也可以在官网上搜索到教程:
https://ww2.mathworks.cn/help/compiler_sdk/ml_code/compile-a-java-package-from-the-command-line.html