Ubuntu下用c++调用自己编写的matlab函数

该博客为《Ubuntu 相关》系列博客的第三篇,该系列博客主要对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++的libcpplib冒号后面是指编译的库的名字-T表示目标,link:lib表示要连接到一个库文件的目标,目标的名字即是.m函数的名字-C表明需要生成.ctf文件,比如本例如果不加-C就不会生成“libmyFunc.ctf”。

使用matlab工具生成

  1. 点击APP栏

在这里插入图片描述

  1. To open the Library Compiler app, enter the following command at the MATLAB command prompt: library Compiler

  2. 选择C++ Shared Library

在这里插入图片描述
4. 点击+,创建包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 打包结束,会生成一个myFunc的文件夹

在这里插入图片描述
该文件夹下会有一下文件,我们要用的文件在for_redistribution_files_only文件下
在这里插入图片描述

  1. 我们主要使用myFunc,hmyFunc.so文件

在这里插入图片描述

  1. 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的函数。

Ubuntu系统中,如果你想用Python调用C++编写函数,你需要创建一个C++的共享库(动态链接库),然后通过Python的`ctypes`库或者`cffi`库来调用这个库中的函数。下面是一个简单的示例来说明这个过程: **步骤 1: 编写C++函数** 首先,你需要有一个C++源文件,比如`add.cpp`,它包含你想要在Python中调用函数: ```cpp // add.cpp extern "C" { #include <Python.h> } extern "C" { PyObject* add(PyObject* /*self*/, PyObject* args) { int a, b, result; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL; result = a + b; return PyLong_FromLong(result); } static PyMethodDef AddMethods[] = { {"add", add, METH_VARARGS, "Add two integers"}, {NULL, NULL, 0, NULL} // Sentinel }; static struct PyModuleDef addmodule = { PyModuleDef_HEAD_INIT, "addmodule", NULL, -1, AddMethods }; PyMODINIT_FUNC PyInit_addmodule() { return PyModule_Create(&addmodule); } } ``` **步骤 2: 编译C++代码为共享库** 接下来,使用g++编译器编译这个C++文件为共享库: ```sh g++ -shared -fPIC -o libadd.so -I/usr/include/python3.x add.cpp ``` 这里的`-I/usr/include/python3.x`是指定Python头文件的路径,`x`是你当前Python版本的主版本号(例如,对于Python 3.8,使用`3.8`)。 **步骤 3: 在Python中使用ctypes调用C++函数** 现在,你可以在Python脚本中导入并使用这个共享库了: ```python import ctypes # 加载共享库 lib = ctypes.CDLL('./libadd.so') # 调用函数 result = lib.add(4, 5) print(result) # 输出: 9 ``` 确保将`./libadd.so`替换为你的共享库文件的正确路径。 **步骤 4: 清理工作** 在每次修改C++代码并重新编译后,需要重启Python进程,或者在Python中使用`ctypes.cdll.Reload`来重新加载共享库,以便使用新的修改。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值