Mex функция не обновляется после перекомпиляции - PullRequest
6 голосов
/ 10 августа 2011

У меня есть простая функция 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, чтобы увидеть обновленную функцию. Даже если я удаляю скомпилированный файл mex и перекомпилирую, я все равно получаю старую версию функции mex (не на диске, а в памяти).

Все в порядке, если я не ссылаюсь на mylib, но я понятия не имею, что может быть виновником, препятствующим обновлению. Библиотека, к сожалению, слишком велика и слишком переплетена, чтобы удалять отдельные модули один за другим.

Существуют ли известные условия, которые могут вызвать такие проблемы?

Пояснение:

Я обновляю только содержимое функции mex, а не библиотеки.

Обновление:

Работает под Ubuntu 11.04 с Matlab R2011a! Я пытался воспроизвести ту же среду на моей машине OpenSUSE (R2011a, Boost 1.42, OpenCV 2.2, динамически связанная, ...), но все же не повезло. Таким образом, я пришел к выводу, что на самом деле с моей библиотекой все в порядке (иначе она не будет работать под Ubuntu), но это должно быть некоторое столкновение зависимостей и внутренних библиотек Matlab. Я официально сдаюсь. Преториан и амро, спасибо за помощь!

Ответы [ 2 ]

4 голосов
/ 10 августа 2011

Команда mex автоматически очищает функцию mex, если она в данный момент загружена в память. Вы уверены, что ваша mex-функция закрывает любой дескриптор другой библиотеки? Если такой дескриптор существует, это может помешать ОС выгружать mex-файл.

Я использовал следующий набор команд для очистки mex-функций вручную, и, исходя из моего опыта, использование полного пути к mex-файлу при вызове clear работает. Так что попробуйте, и если он все еще не выгружен, вы можете начать искать код для загрузки и выгрузки другой библиотеки.

[~,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).

Конечно, если это вызвано ошибкой в ​​другой библиотеке, ничто из этого не поможет.

3 голосов
/ 11 августа 2011

Пытаясь воспроизвести проблему, я написал минимальный рабочий пример для вашего случая: MEX-файл, который ссылается на динамическую библиотеку и использует одну из ее открытых функций.Я протестировал следующее на 32-битной WinXP с использованием MATLAB R2010b с VS2010 в качестве компилятора (как для DLL, так и для MEX).

В примере просто добавляются числа с плавающей запятой.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 ++ для этой работы.На Unix-системах с GCC я думаю, что этот шаг выглядит следующим образом (поправьте меня, если я ошибаюсь):

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

Используя ProcessИнструмент Explorer от Sysinternals, мы можем просматривать загруженные библиотеки DLL с помощью процесса MATLAB, функции MEX и нашей пользовательской динамической библиотеки:

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 ... В противном случае я подозреваю, что в вашем коде должны быть неосвобожденные ресурсы, вызывающие модульостаться в памяти?

...