重新编译后Mex功能未更新

时间:2011-08-10 14:27:39

标签: matlab dynamic-linking mex

我有一个简单的mex函数,它从库中调用另一个C ++函数。我用

编译源代码
mex -cxx mymexfunction.cpp -I/some/include -L/some/lib -lmylib

mylib库是动态的(.so),并且与其他一些库(boost,OpenCV等)相关联。

我遇到的问题是,一旦我调用函数mymexfunction一次,当我重新编译源代码时它将不会更新。我试过了

clear
clear all
clear mex
clear functions
clear fun('mymexfunction')
munlock('mymexfunction')
unloadlibrary('mymexfunction')

......但没有任何帮助!我必须重新启动Matlab才能看到更新的mexfunction。即使我删除已编译的mex文件并重新编译,我仍然会获得旧版本的mex函数(不在磁盘上,但在内存中)。

如果我没有链接到mylib,一切都很好,但我不知道阻止更新的罪魁祸首是什么。遗憾的是,图书馆太大而且交织在一起,无法逐个删除单个模块。

是否存在可能导致此类问题的已知条件?

澄清:

我只更新mex功能的内容,而不是库。

更新

它在Ubuntu 11.04下使用Matlab R2011a工作!我试图在我的OpenSUSE机器上重现相同的环境(R2011a,Boost 1.42,动态链接的OpenCV 2.2 ......)但仍然没有运气。所以我得出结论,我的库没有任何问题(否则它在Ubuntu下不起作用),但它必须是依赖项和Matlab内部库的一些冲突。我正式放弃了。 Praetorian和Amro,谢谢你的帮助!

2 个答案:

答案 0 :(得分:4)

mex命令会自动清除mex函数(如果它当前已加载到内存中)。你确定你的mex函数正在关闭它对其他库的任何句柄吗?如果存在这样的句柄,则可能会阻止操作系统卸载mex文件。

我已经使用以下命令集手动清除mex函数,根据我的经验,在调用clear时使用mex文件的完整路径。所以尝试一下,如果它仍然没有被卸载,你可能想要开始查看加载和卸载其他库的代码。

[~,f] = inmem( '-completenames' );
result = strfind( f, ['mymexfile' '.' mexext] );
result = f(cellfun( @isempty, result, 'UniformOutput', true ) == 0);
clear( result{:} )

尝试在上面的命令之后再次运行inmem命令,看看你的mex文件是否仍然列出。

可能有助于确保其他库被卸载的东西可能是使用std::shared_ptr来保存此库的句柄。然后,在mexFunction()入口点的开头加载库并将句柄粘贴到shared_ptr中。 shared_ptr还需要使用自定义删除工具来卸载库(在Windows上,自定义删除工具会调用FreeLibrary)。

当然,如果这是由其他库中的错误引起的,这一切都无济于事。

答案 1 :(得分:3)

尝试重现这个问题,我为您的案例编写了一个最小的工作示例:一个链接动态库的MEX文件,并使用其公开的函数之一。我使用MATLAB R2010b和VS2010作为编译器(对于DLL和MEX)在WinXP 32位上测试了以下内容。

该示例仅添加浮点数。 MEX文件接受矩阵/向量,并在每对上从库调用add()函数的元素上循环。

Adder.h

#ifndef ADDER_H
#define ADDER_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#   ifdef BUILDING_DLL
#       define DLL_IMPORT_EXPORT __declspec(dllexport)
#   else
#       define DLL_IMPORT_EXPORT __declspec(dllimport)
#   endif
#else
#   define DLL_IMPORT_EXPORT
#endif

DLL_IMPORT_EXPORT double add(double x, double y);

#ifdef __cplusplus
}
#endif

#endif

Adder.c

#include "Adder.h"

double add(double x, double y)
{
    return x+y;
}

mymexfunction.c

#include "mex.h"
#include "Adder.h"

#define X_IN    input[0]
#define Y_IN    input[1]
#define Z_OUT   output[0]

void mexFunction(int output_size, mxArray *output[], int input_size, const mxArray *input[])
{
    double *inX, *inY, *outZ;
    mwSize m,n;
    int i;

    /* check for proper number of arguments */
    if (input_size != 2) {
        mexErrMsgTxt("Two input arguments required.");
    }
    if (output_size > 1) {
        mexErrMsgTxt("Too many output arguments.");
    }

    /* check input argument sizes */
    m = mxGetM(X_IN);
    n = mxGetN(X_IN);
    if ( !mxIsDouble(X_IN) || !mxIsDouble(Y_IN) ) {
        mexErrMsgTxt("Input arguments must be matrices/vectors of doubles.");
    }
    if ( mxGetM(Y_IN)!=m || mxGetN(Y_IN)!=n ) {
        mexErrMsgTxt("X and Y must be of same size.");
    }

    /* Create a matrix for the return argument */
    Z_OUT = mxCreateDoubleMatrix(m, n, mxREAL);

    // get pointers to data
    inX =  (double *) mxGetPr(X_IN);
    inY =  (double *) mxGetPr(Y_IN);
    outZ = (double *) mxGetPr(Z_OUT);

    // compute and store result
    for(i=0; i<m*n; ++i) {
        outZ[i] = add(inX[i], inY[i]);
    }

    return;
}

首先我们构建动态库,正如我所提到的,我正在使用VC ++来完成工作。在使用GCC的基于Unix的系统上,我认为这一步就像(如果我错了,请纠正我):

gcc -c -DBUILDING_DLL Adder.c -o Adder.o -I.
gcc -shared -o libAdder.so Adder.o -Wl,--out-implib,libAdder.a

然后在MATLAB中,我们编译MEX文件:

>> mex mymexfunction.c -I. -L. -lAdder

(注意:我将所有内容放在同一文件夹中以避免处理路径问题。)

接下来,我们可以在MATLAB中测试函数:

>> mymexfunction([1 2;3 4], [5 6; 7 8])
ans =
     6     8
    10    12

使用Sysinternals的Process Explorer工具,我们可以通过MATLAB过程,MEX函数和我们的自定义动态库查看加载的DLL:

sysinternals

如果我们发出命令clear mex,则按预期卸载两个模块(使用Process Explorer验证)。 INMEM也证实了这一点,@Praetorian表明:

clear mex
[~,m] = inmem('-completenames');
any( ismember(m,fullfile(pwd,['mymexfunction.' mexext])) )

最后,如果我们对mymexfunction.c进行一些更改:

// add 10 to all results
outZ[i] = add(inX[i], inY[i]) + 10.0;

重新编译MEX,然后再次测试(全部在同一个会话中,不重启)。结果将反映您所看到的变化:

>> mymexfunction([1 2;3 4], [5 6; 7 8])
ans =
    16    18
    20    22

请尝试在Mac / Linux计算机上重复上述步骤。如果您仍然收到旧的金额,那么它必须是特定于非Windows平台的错误,并且应该向MathWorks报告...否则我怀疑在您的代码中,必须有一些未释放的资源导致模块留在记忆中?