该博客为《Ubuntu 相关》系列博客的第三篇,该系列博客主要对Ubuntu安装各种软件或者库进行一个记录,方便重装系统后快速恢复工作。
这是进项目组以来接受的第一个任务,以此记录实现过程。
此篇紧接上篇实现c++调用MATLAB函数。
Ubuntu下用c++调用自己编写的matlab函数
调用自己编写的m函数,只是多了一步将自己的matlab函数编译成动态链接库文件
(也就类似自带的那种eigen.h和libeng.so)。这里练习了一个小例子,展示从c++中调用matlab里面的自己写的函数。
编写matlab函数
编写一个简单的matlab函数,实现加法功能。
function [ C ] = myFunc(A, B)
C = A+B;
end
生成动态链接库
在matlab命令行使用命令生成
设定编译器为gcc,在matlab 命令行依次执行命令mex -setup和mbuild -setup:
>> mex -setup
MEX 配置为使用 'gcc' 以进行 C 语言编译。
警告: MATLAB C 和 Fortran API 已更改,现可支持
包含 2^32-1 个以上元素的 MATLAB 变量。不久以后,
您需要更新代码以利用
新的 API。您可以在以下网址找到相关详细信息:
http://www.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html。
要选择不同的语言,请从以下选项中选择一种命令:
mex -setup C++
mex -setup FORTRAN
MEX 配置为使用 'g++' 以进行 C++ 语言编译。
警告: MATLAB C 和 Fortran API 已更改,现可支持
包含 2^32-1 个以上元素的 MATLAB 变量。不久以后,
您需要更新代码以利用
新的 API。您可以在以下网址找到相关详细信息:
http://www.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html。
>> mbuild -setup
MBUILD 配置为使用 'gcc' 以进行 C 语言编译。
要选择不同的语言,请从以下选项中选择一种命令:
mex -setup C++ -client MBUILD
mex -setup FORTRAN -client MBUILD
MBUILD 配置为使用 'g++' 以进行 C++ 语言编译。
生成myFunc.m的动态链接库(.so)
mcc -W cpplib:libmyFunc -T link:lib myFunc.m -C
等待数秒,完成。可以看到myFunc.m所在的目录下生成了多个文件:
命令解释:
其中-W是控制编译之后的封装格式;cpplib是指编译成C++的lib;cpplib冒号后面是指编译的库的名字;-T表示目标,link:lib表示要连接到一个库文件的目标,目标的名字即是.m函数的名字。-C表明需要生成.ctf文件,比如本例如果不加-C就不会生成“libmyFunc.ctf”。
使用matlab工具生成
- 点击APP栏
-
To open the Library Compiler app, enter the following command at the MATLAB command prompt:
library Compiler
-
选择
C++ Shared Library
4. 点击+
,创建包
- 打包结束,会生成一个
myFunc
的文件夹
该文件夹下会有一下文件,我们要用的文件在for_redistribution_files_only
文件下
- 我们主要使用
myFunc,h
和myFunc.so
文件
readme.txt
文件很重要!很重要!!很重要!!!
我们根据readme.txt
文件的内容来配置我们的环境。
阅读readme.txt文件
Prerequisites for Deployment(部署的前提条件)
Verify the MATLAB Runtime is installed and ensure you have installed version 9.1 (R2016b).
这里要
注意
:MATLAB
Runtime的版本一定要和MATLAB版本对应。如我的MATLAB是2016b我就要装9.1版本的MATLAB Runtime。
If the MATLAB Runtime is not installed, do the following:
1. enter
mcrinstaller
at MATLAB prompt. The MCRINSTALLER command displays the location of the MATLAB Runtime installer.
这里建议
使用这种方法,比较简单,而且不会出现版本不对应的问题。
还有一种方法是:
Or download the Linux 64-bit version of the MATLAB Runtime for R2016b from the MathWorks Web site by navigating to:
http://www.mathworks.com/products/compiler/mcr/index.html
2. run the MATLAB Runtime installer.
准备好一个可写入的安装路径
$ cd /media/al007/a292ab72-a60c-40d7-9058-360e4508bcf7/al007/MATLAB
$ ls
2016b
$ sudo mkdir MATLAB_Compiler_Runtime
$ sudo chmod 777 MATLAB_Compiler_Runtime
$ ls
2016b MATLAB_Compiler_Runtime
安装
$ cd /media/al007/a292ab72-a60c-40d7-9058-360e4508bcf7/al007/MATLAB/2016b/toolbox/compiler/deploy/glnxa64
$ ls
InstallAgent.zip MCRInstaller.zip
unzip MCRInstaller.zip
./install
这里解压时出现错误:提示Parsing filters is unsupported
(当时忘记截图了!!)
解决方法参考大佬博客。
进入图形化安装界面,选好安装路径:/your path/MATLAB/MATLAB_Compiler_Runtime,默认安装就行,部分截图如下(我又忘记截图了!!,借用大佬的图,类似!!!):
下面这张图片会告诉你需要加入环境变量
的路径,每个人的都不一样,在readme.txt文件里面也有。
Appendix
A. Linux x86-64 systems:
In the following directions, replace MCR_ROOT by the directory where the MATLAB Runtime is installed on the target machine.
没太整明白啥意思,估计就是添加路径。
Set the environment variable XAPPLRESDIR to this value:
MCR_ROOT/v91/X11/app-defaults
我没找到这个文件,我就没有设置!!!
set the environment variable LD_LIBRARY_PATH
If the environment variable LD_LIBRARY_PATH is undefined, set it to the concatenation of the following strings:
MCR_ROOT/v91/runtime/glnxa64: MCR_ROOT/v91/bin/glnxa64: MCR_ROOT/v91/sys/os/glnxa64: MCR_ROOT/v91/sys/opengl/lib/glnxa64
大佬把路径加到了这里:
sudo gedit /etc/profile
我也不知道这个是干啥的,我加进去没用!!!(具体忘了,当时表现出来是应该是没有效果的!!!整了一天,可能脑子已经糊了!!!)
我是这样加的
:
sudo gedit ~/.bashrc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v91/runtime/glnxa64:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v91/bin/glnxa64:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v91/sys/os/glnxa64:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v91/sys/opengl/lib/glnxa64
source ~/.bashrc
这样环境就配置好了!!!
编写c++工程
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "mclmcrrt.h"
#include "mclmcr.h"
#include "matrix.h"
#include "mclcppclass.h"
#include "myFunc.h"
using namespace std;
int main() {
// Set up the application state for the MATLAB Runtime instance created in the application.
if (!mclInitializeApplication(NULL,0))
{
std::cerr << "could not initialize the application properly"
<< std::endl;
return -1;
}
// initialize lib,这里必须做初始化!
if( !myFuncInitialize())
{
std::cout << "Could not initialize libmyFunc!" << std::endl;
return -1;
}
// 用户输入2个数值
double a, b;
cout<<"Please input 2 numbers <a b> and then press enter: "<<endl;
cin >> a;
cin >> b;
double c; //used to receive the result
// 为变量分配内存空间, maltab只有一种变量,就是矩阵,为了和c++变量接轨,设置成1*1的矩阵
mwArray mwA(1, 1, mxDOUBLE_CLASS); //1,1表示矩阵的大小, mxDOUBLE_CLASS表示变量的精度
mwArray mwB(1, 1, mxDOUBLE_CLASS);
mwArray mwC(1, 1, mxDOUBLE_CLASS);
// 调用类里面的SetData函数给类赋值
mwA.SetData(&a, 1);
mwB.SetData(&b, 1);
// 调用自己的函数,求和。
myFunc(1, mwC, mwA, mwB);
c = mwC.Get(1, 1);
cout<<"The sum is: "<<c<<endl;
// 后面是一些终止调用的程序
// terminate the lib
myFuncTerminate();
// terminate MCR
mclTerminateApplication();
return EXIT_SUCCESS;
}
下面对程序做一下说明:
初始化
看CSDN上很多大佬没有对应用程序进行初始化,我之前也没有进行初始化,所以就出现段错误(核心已转储)的问题,加上之后就不存在了。
参考文章Creating C++ Shared Libraries and DLLs,做了如下改进:
Initialize the runtime and start the library before calling any functions exported from the runtime or the library. Failure to initialize will cause your program to crash. Always check for success (the initializers return false if they fail) and issue error messages as necessary.
// Set up the application state for the MATLAB Runtime instance created in the application.
if (!mclInitializeApplication(NULL,0))
{
std::cerr << "could not initialize the application properly"
<< std::endl;
return -1;
}
// initialize lib,这里必须做初始化!
if( !myFuncInitialize())
{
std::cout << "Could not initialize libmyFunc!" << std::endl;
return -1;
}
mwArray
mwArray :C++用它向matlab传递输i/o 参数。MATLAB中的参数都是矩阵表示,哪怕是1*1的矩阵。
详细内容请见博客Matlab代码转C++ —— mwArray
mwArray mwA(1, 1, mxDOUBLE_CLASS); //1,1表示矩阵的大小, mxDOUBLE_CLASS表示变量的精度
mwArray mwB(1, 1, mxDOUBLE_CLASS);
mwArray mwC(1, 1, mxDOUBLE_CLASS);
// 调用类里面的SetData函数给类赋值
mwA.SetData(&a, 1);
mwB.SetData(&b, 1);
调用matlab函数
生成的文件中打开“libmyFunc.h”可以看到一行:
extern LIB_libmyFunc_CPP_API void MW_CALL_CONV myFunc(int nargout, mwArray& C, const mwArray& A, const mwArray& B);
这个就是我们的myFunc.c函数待会儿在c++中调用时的接口
。
有4个参数,第一个是参数个数,第二个是用来接收函数返回值的,后面2个是从c++中传递进来的变量。
我们还会用到“libmyFunc.h”中的另外2个函数:libmyFuncInitialize()初始化,和注销libmyFuncTerminate()。
// 调用自己的函数,求和。
myFunc(1, mwC, mwA, mwB);
c = mwC.Get(1, 1);
cout<<"The sum is: "<<c<<endl;
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(main)
add_executable(main main.cpp)
target_link_libraries(main "/home/al007/桌面/matlab/redistribution/libmyFunc.so")
target_link_libraries(main "/media/al007/a292ab72-a60c-40d7-9058-360e4508bcf7/al007/MATLAB/2016b/runtime/glnxa64/libmwmclmcrrt.so")
target_link_libraries(main "/media/al007/a292ab72-a60c-40d7-9058-360e4508bcf7/al007/MATLAB/MATLAB_Compiler_Runtime/v91/bin/glnxa64/libmwmclmcr.so")
include_directories("/media/al007/a292ab72-a60c-40d7-9058-360e4508bcf7/al007/MATLAB/2016b/extern/include")
有关cmake常用的命令请参考文章cmake 添加头文件目录,链接动态、静态库
遇到的问题:
not found libmwmclmcrrt.so
解决方案:
把libmwmclmcrrt.so库的文件路径添加到环境变量
sudo gedit ~/.bashrc
source ~/.bashrc
not found libmwmclmcr.so
解决方案:
在CMakeLists.txt文件中添加下面一句话,这个路径是我们之前装的RCM Install
中的路径。
target_link_libraries(main "/media/al007/a292ab72-a60c-40d7-9058-360e4508bcf7/al007/MATLAB/MATLAB_Compiler_Runtime/v91/bin/glnxa64/libmwmclmcr.so")
编译
mkdir build
cd buile
cmake ..
make
./main
至此我们就成功用c++,调用了自己编写的MATLAB的函数。