
问题描述:
有一个c++程序main.cpp,和一个matlab函数myFunc.m。现在要做这件事:
1)从main.cpp中传递2个double类型的数值a和b到myFunc.m中
2)myFunc.m中求和(sum = a+b)
3)main.cpp中接收myFunc.m返回的和并输出。
思路:
1)设置matlab的编译器,使用gcc编译器。编译m文件成.so。
2)编译.cpp文件,编译时调用.so库(添加.so的路径到编译选项)。
步骤:
1)将自己的matlab函数(myFunc.m)编译成动态链接库
(1) 设定编译器为gcc,在matlab 命令行依次执行命令mex -setup和mbuild -setup:
>>mex -setupOptions files control which compiler to use, the compiler and link command options, and the runtime libraries to link against.Using the 'mex -setup' command selects an options file that isplaced in ~/.matlab/R2012a and used by default for 'mex'. An options file in the current working directory or specified on the command line overrides the default options file in ~/.matlab/R2012a. To override the default options file, use the 'mex -f' command(see 'mex -help' for more information).The options files available for mex are: 1: /opt/MATLAB/R2012a/bin/mexopts.sh : Template Options file for building gcc MEX-files 0: Exit with no changesEnter the number of the compiler (0-1):1/opt/MATLAB/R2012a/bin/mexopts.sh is being copied to ~/.matlab/R2012a/mexopts.shcp: cannot create regular file `~/.matlab/R2012a/mexopts.sh': Permission denied************************************************************************** Warning: The MATLAB C and Fortran API has changed to support MATLABvariables with more than 2^32-1 elements. In the near futureyou will be required to update your code to utilize the newAPI. You can find more information about this at:http://www.mathworks.com/help/techdoc/matlab_external/bsflnue-1.html Building with the -largeArrayDims option enables the new API. **************************************************************************>>mbuild -setup Options files control which compiler to use, the compiler and link commandoptions, and the runtime libraries to link against.Using the 'mbuild -setup' command selects an options file that isplaced in ~/.matlab/R2012a and used by default for 'mbuild'. An options file in the current working directory or specified on the command line overrides the default options file in ~/.matlab/R2012a. To override the default options file, use the 'mbuild -f' command (see 'mbuild -help' for more information).The options files available for mbuild are: 1: /opt/MATLAB/R2012a/bin/mbuildopts.sh : Build and link with MATLAB Compiler generated library via the system ANSI C/C++ compiler 0: Exit with no changesEnter the number of the compiler (0-1):1/opt/MATLAB/R2012a/bin/mbuildopts.sh is being copied to ~/.matlab/R2012a/mbuildopts.shcp: cannot create regular file `~/.matlab/R2012a/mbuildopts.sh': Permission denied>>
(2) 在matlab中,编写myFunc.m文件内容如下:
function [ C ] = myFunc(A, B)C = A+Bend
(3) 生成myFunc.m的动态链接库(.so)
>>mcc -W cpplib:libmyFunc -T link:lib myFunc.m -cWarning: MATLAB Toolbox Path Cache is out of date and is not being used.Type 'help toolbox_path_cache' for more info >>
等待数秒,完成。可以看到myFunc.m所在的目录下生成了多个文件:
$ lslibmyFunc.cpp libmyFunc.ctf libmyFunc.exports libmyFunc.h libmyFunc.so main.cpp mccExcludedFiles.log myFunc.m readme.txt
命
令解释:其中-W是控制编译之后的封装格式;cpplib是指编译成C++的lib;cpplib冒号后面是指编译的库的名字;-T表示目
标,link:lib表示要连接到一个库文件的目标,目标的名字即是.m函数的名字。-c表明需要生成.ctf文件,比如本例如果不加-c就不会生成
“libmyFunc.ctf”。
生成的文件中打开“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()。
2)编写main.cpp,代码如下:
#include <iostream>#include "mclmcr.h"#include "matrix.h"#include "mclcppclass.h"#include "libmyFunc.h"#include "mclmcrrt.h"using namespace stdint main() {// initialize lib,这里必须做初始化!if( !libmyFuncInitialize()){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 liblibmyFuncTerminate() // terminate MCRmclTerminateApplication() return EXIT_SUCCESS}
3)编译main.cpp函数,调用libmyFunc.so
$ g++ -o main -I. -I/opt/MATLAB/R2012a/extern/include -L. -L/opt/MATLAB/R2012a/runtime/glnxa64 main.cpp -lmyFunc -lm -lmwmclmcrrt -lmwmclmcr
开始编译时也遇到一些问题,主要是链接库路径问题导致的编译错误,详细错误汇总在另篇笔记里(点此查看)。
编译成功后,需要装一下MCR Installer,步骤点此。
运行结果:
$ ./main Warning: latest version of matlab app-defaults file not found.Contact your system administrator to have this file installedPlease input 2 numbers <a b>and then press enter: 10 100The sum is: 110$ ./main Warning: latest version of matlab app-defaults file not found.Contact your system administrator to have this file installedPlease input 2 numbers <a b>and then press enter: 1 1The sum is: 2
源代码及编译过程中的所有文件已打包,点击这里可以下载。
1:通常export该函数。2:获取结构体指针:在driver设个全局变量。
下面贴出自己写的xenon
flash
driver部分代码。
struct
xenon_flash_chip
{
struct
i2c_client
*xenon_flash_client
}
static
struct
xenon_flash_chip
*xenon_chip
//this
is
just
for
debug
int
xenon_flash_reread(void)
{
int
err
=
0
u8
data
struct
xenon_flash_chip
*chip
if(xenon_chip==NULL)
return
err
chip=xenon_chip
//read
07
err
=
xenon_flash_i2c_read(chip->xenon_flash_client,0x07,&data)
if
(err
<
0)
return
err
CDBG("[xenon_flash]reg_control
reg=0x07
data=0x0%x\n",data)
//read
06
err
=
xenon_flash_i2c_read(chip->xenon_flash_client,0x06,&data)
if
(err
<
0)
return
err
CDBG("[xenon_flash]reg_control
reg=0x06
data=0x0%x\n",data)
//read
04
err
=
xenon_flash_i2c_read(chip->xenon_flash_client,0x04,&data)
if
(err
<
0)
return
err
CDBG("[xenon_flash]reg_control
reg=0x04
data=0x0%x\n",data)
return
err
}
EXPORT_SYMBOL(xenon_flash_reread)
static
int
__devinit
xenon_flash_i2c_probe(struct
i2c_client
*client,
const
struct
i2c_device_id
*id)
{
int
rc
=
0
static
const
u32
i2c_funcs
=
I2C_FUNC_SMBUS_BYTE_DATA
|
I2C_FUNC_SMBUS_WRITE_WORD_DATA
struct
xenon_flash_chip
*chip
struct
xenon_flash_platform_data
*pdata
CDBG("xenon_flash_i2c_probe
called!\n")
/*
check
*/
if
(client->dev.platform_data
==
NULL)
{
dev_err(&client->dev,
"xenon_flash
platform
data
is
NULL.
exiting.\n")
return
-ENODEV
}
/*
Copy
to
global
variable
*/
pdata
=
client->dev.platform_data
/*check
i2c
func*/
if
(!i2c_check_functionality(client->adapter,
i2c_funcs))
return
-ENOSYS
/*
Allocate
memory
for
driver
data
*/
chip
=
kzalloc(sizeof(struct
xenon_flash_chip),
GFP_KERNEL)
if
(!chip)
return
-ENOMEM
xenon_chip
=
chip
i2c_set_clientdata(client,chip)
chip->xenon_flash_client
=
client
rc
=
xenon_flash_init_hw(chip,pdata)
if
(rc
<
0)
CDBG("xenon_flash_init_hw
initlised
failed!\n")
return
0
}
在driver调试过程中,通常需要将关键函数export出来,在其他地方extern声明再调用调试。
注意看这个文件sysdeps/unix/sysv/linux/syscalls.list
里面记录着系统调用的名字和一些属性,具体我也没有研究过,不懂。
再看select的实现,很让人惊讶,一旦使用,结果就是“报错“。
int
__select (nfds, readfds, writefds, exceptfds, timeout)
int nfds
fd_set *readfds
fd_set *writefds
fd_set *exceptfds
struct timeval *timeout
{
__set_errno (ENOSYS)
return -1
}
libc_hidden_def (__select)
stub_warning (select)
weak_alias (__select, select)
这是因为glibc并没有实现系统调用,而是调用系统调用,
更进一步,连调用系统调用都没有一个个实现,而是使用了通用的办法,
理由很简单,所有的系统调用在linux内核头文件里都能找到,
所有的系统调用参数类型就那么几种,参数个数也是有限的,
因此没有必要针对所有的系统调用一一封装,
于是就有了这个list文件,自动生成调用系统调用的函数,
如果生成失败,也就是你看到的“报错”。
符号是有强弱的,当自动生成成功的时候,“报错”的弱符号就被忽略了。
当你在glibc中找到一个系统调用的封装源码,是以下原因,
1. 编译的目标系统不支持这个系统调用,所以自己用另一种方式实现了。
2. 这个系统调用无法使用通用的自动生成方式生成,用特化的方式覆盖。
3. 针对这个系统调用做了特别的优化。
4. 其它可能的原因。
具体可以留意
SYSCALL, PSEUDO, DO_CALL, INLINE_CALL 等名字
这两个文件是重点所在
sysdeps/unix/i386/sysdep.h
sysdeps/unix/i386/sysdep.S
要搞清楚具体的自动生成过程,恐怕得研究glibc自身的编译过程了
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)