MatLab與Java混合編程

一、概述
最近在嘗試進行java和MatLab的混合編程,主要目的就在於將MatLab中的函數打包爲jar,從而可以在Java中進行調用。期間碰到了很多問題,在此記錄一下備忘。

二、 deploytool打包jar
關於如何通過MatLab提供的deploytool將.m文件打包爲jar,在網上已經可以搜索到很多圖文並茂的教程了,官方也都提供了比較詳細的說明:

官方文檔:https://ww2.mathworks.cn/help/compiler_sdk/gs/create-a-java-application-with-matlab-code.html
CSDN上的一篇博客:https://blog.csdn.net/legendaryhaha/article/details/84887601
在此要強調一下在這一步需要注意的版本同步和路徑添加問題:

一定要確定MatLab使用的JDK版本要和調用該jar包的java程序中使用的JDK版本一致最好。MatLab中使用version -java命令即可查看MatLab中java的版本。可以通過配置環境變量MATLAB_JAVA改變MatLab使用指定的java;
一定要確定使用該jar包的MCR版本也一定要與編譯該jar包的MatLab版本一致;
要使MatLab的javabuilder.jar能夠被正確引用到。最好直接將javabuilder.jar直接添加到CLASSPATH系統變量中。javabuilder.jar可以在MatLab安裝目錄下的<mcr_root>\toolbox\javabuilder\jar\<platform>\javabuilder.jar中找到;
要使編譯出的jar包能夠被正確引用到。若java程序爲web程序,可將jar添加到WEB-INF的lib文件夾下;若java程序爲可執行程序jar,可以打包爲"fatjar"並在MANIFEST.MF文件中指定引用,或在命令行運行時指定在-classpath參數中;最後可以將該jar包位置添加到CLASSPATH系統變量中,全局引用。
上述幾點在打包後生成的/for_redistribution_files_only/readme.txt文件中也都有詳細的說明。

三、 使用jar包時遇到的問題
本人一開始是在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中調試發現確實在<mcr_root>\toolbox\images\images\imlincomb.m中調用了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文件後綴都不一樣:

Linux(64-bit)下後綴爲mexa64;
Windows(64-bit)下後綴爲mexw64;
Mac(64-bit)下後綴爲mexmaci64

此時就考慮到應該是在Windows上通過deploytool打包的jar並不能在linux上使用。於是嘗試在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.<init>(Unknown Source)
        at java.awt.Frame.<init>(Unknown Source)
        at javax.swing.JFrame.<init>(Unknown Source)
        at com.mathworks.mwswing.MJFrame.<init>(MJFrame.java:108)
        at com.mathworks.mwswing.MJFrame.<init>(MJFrame.java:101)
        at com.mathworks.toolbox.compiler.desktop.DeploytoolLaunchPad.<init>(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基本上也可以猜測出含義。主要進行了如下幾處修改:

在<configuration>標籤中,將file、location修改爲服務器上對應文件的位置;
<param.appname>應該就是應用名稱,不作修改;
<param.intermediate>, <param.files.only>, <param.output>, <param.logdir>應該就是在deploytool的settings中各種Output Folders的設置。而這些標籤中都使用了變量${PROJECT_ROOT},故也不作修改;
<param.net.tsa.metadata.assembly>這個標籤目前還不清楚用處,暫時寫空;
<fileset.exports>中的<file>子標籤中的value,一定要修改爲服務器上m文件對應的路徑;
<fileset.classes>中的<entity.class>子標籤中的name屬性也就是類名,其中的<file>子標籤中的value,也一定要修改爲服務器上m文件對應的路徑;
<build-deliverables>標籤中的value也最好修改爲服務器上的輸出路徑;
<matlab>則是比較重要的配置了,其中<root>子標籤就是MatLab的安裝路徑,修改爲服務器上對應的路徑即可。其他的toolbox配置不做修改;
接下來的<platform>更是重中之重,既然目標平臺變爲了Linux,則將<unix>, <linux>都設置爲true,<arch>也從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

原文:https://blog.csdn.net/mrliuzhao/article/details/90261153

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章