2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки





Начать новую тему Ответить на тему На страницу Пред.  1, 2
 
 Re: использование DLL в Matlab
Сообщение16.04.2017, 01:42 
Экс-модератор


12/07/07
2920
Донецк, Украина
GAA в сообщении #1209499 писал(а):
Компилировать из командного окна см. mex.
В простейшем случае
>> mex имя_файла.c
(Тут предполагается, что файл в текущей директории. В этой же директории появится имя_файла.mexw64. Будет работать в R2913 и выше.)

-- Вс 16.04.2017 00:47:20 --

["см. mex" означало см. help (>> help mex) или справку (>> doc mex) или документацию ("MATLAB® External Interfaces" pdf)]

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение16.04.2017, 12:51 
Аватара пользователя


07/10/15
239
Сделал так как Вы написали, добавил в текущую папку всё из папки
'C:\Program Files\MATLAB\R2013a\extern\examples\mex'
ну и разумеется файлы проекта (исходник и заголовочные файлы), но всё равно выдаёт ошибку:
LINK : error LNK2001: неразрешенный внешний символ "mexFunction"
C:\Users\User\AppData\Local\Temp\mex_BLjGLN\templib.x : fatal error LNK1120: 1 неразрешенных внешних элементов

я так понимаю что то у меня не подключено, что то связано с mexFunction,
но mexfunction.c в текущем каталоге есть, ну и всё что связано с mex я скопировал

к тому же файл .mexwin64 уже появляется в рабочей папке, правда у него размер 0 байт, т.е. он пустой

пробовал разные исходники на С++, в конце концов, получается одно и тоже LINK : error LNK2001: неразрешенный внешний символ "mexFunction"

подскажите пожалуйста как это можно исправить

я так понимаю в сложившейся ситуации, даже если я и напишу всю функцию в нативном коде С++, она у меня в matlab не запустится всё равно ...

_________________
Вот код QF.h
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
//
// MATLAB Compiler: 4.18.1 (R2013a)
// Date: Sat Apr 15 23:48:48 2017
// Arguments: "-B" "macro_default" "-W" "cpplib:QF" "-T" "link:lib" "-d"
// "C:\Users\User\Documents\MATLAB\QF\src" "-w"
// "enable:specified_file_mismatch" "-w" "enable:repeated_file" "-w"
// "enable:switch_ignored" "-w" "enable:missing_lib_sentinel" "-w"
// "enable:demo_license" "-v"
// "C:\Users\User\Documents\MATLAB\Cardi\стат_тесты\Q_filt.m"
//


#ifndef __QF_h
#define __QF_h 1

#if defined(__cplusplus) && !defined(mclmcrrt_h) && defined(__linux__)
#  pragma implementation "mclmcrrt.h"
#endif
#include "mclmcrrt.h"
#include "mclcppclass.h"
#ifdef __cplusplus
extern "C" {
#endif

#if defined(__SUNPRO_CC)
/* Solaris shared libraries use __global, rather than mapfiles
 * to define the API exported from a shared library. __global is
 * only necessary when building the library -- files including
 * this header file to use the library do not need the __global
 * declaration; hence the EXPORTING_<library> logic.
 */


#ifdef EXPORTING_QF
#define PUBLIC_QF_C_API __global
#else
#define PUBLIC_QF_C_API /* No import statement needed. */
#endif

#define LIB_QF_C_API PUBLIC_QF_C_API

#elif defined(_HPUX_SOURCE)

#ifdef EXPORTING_QF
#define PUBLIC_QF_C_API __declspec(dllexport)
#else
#define PUBLIC_QF_C_API __declspec(dllimport)
#endif

#define LIB_QF_C_API PUBLIC_QF_C_API


#else

#define LIB_QF_C_API

#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library.
 */

#ifndef LIB_QF_C_API
#define LIB_QF_C_API /* No special import/export declaration */
#endif

extern LIB_QF_C_API
bool MW_CALL_CONV QFInitializeWithHandlers(
       mclOutputHandlerFcn error_handler,
       mclOutputHandlerFcn print_handler);

extern LIB_QF_C_API
bool MW_CALL_CONV QFInitialize(void);

extern LIB_QF_C_API
void MW_CALL_CONV QFTerminate(void);



extern LIB_QF_C_API
void MW_CALL_CONV QFPrintStackTrace(void);

extern LIB_QF_C_API
bool MW_CALL_CONV mlxQ_filt(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);


#ifdef __cplusplus
}
#endif

#ifdef __cplusplus

/* On Windows, use __declspec to control the exported API */
#if defined(_MSC_VER) || defined(__BORLANDC__)

#ifdef EXPORTING_QF
#define PUBLIC_QF_CPP_API __declspec(dllexport)
#else
#define PUBLIC_QF_CPP_API __declspec(dllimport)
#endif

#define LIB_QF_CPP_API PUBLIC_QF_CPP_API

#else

#if !defined(LIB_QF_CPP_API)
#if defined(LIB_QF_C_API)
#define LIB_QF_CPP_API LIB_QF_C_API
#else
#define LIB_QF_CPP_API /* empty! */
#endif
#endif

#endif

extern LIB_QF_CPP_API void MW_CALL_CONV Q_filt(int nargout, mwArray& Out, const mwArray& u, const mwArray& n, const mwArray& m, const mwArray& q);

#endif
#endif

Вот код QF.cpp
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
//
// MATLAB Compiler: 4.18.1 (R2013a)
// Date: Sat Apr 15 23:48:48 2017
// Arguments: "-B" "macro_default" "-W" "cpplib:QF" "-T" "link:lib" "-d"
// "C:\Users\User\Documents\MATLAB\QF\src" "-w"
// "enable:specified_file_mismatch" "-w" "enable:repeated_file" "-w"
// "enable:switch_ignored" "-w" "enable:missing_lib_sentinel" "-w"
// "enable:demo_license" "-v"
// "C:\Users\User\Documents\MATLAB\Cardi\стат_тесты\Q_filt.m"
//

#include <stdio.h>
#define EXPORTING_QF 1
#include "QF.h"

static HMCRINSTANCE _mcr_inst = NULL;


#if defined( _MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__LCC__)
#ifdef __LCC__
#undef EXTERN_C
#endif
#include <windows.h>

static char path_to_dll[_MAX_PATH];

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void *pv)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        if (GetModuleFileName(hInstance, path_to_dll, _MAX_PATH) == 0)
            return FALSE;
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
    }
    return TRUE;
}
#endif
#ifdef __cplusplus
extern "C" {
#endif

static int mclDefaultPrintHandler(const char *s)
{
  return mclWrite(1 /* stdout */, s, sizeof(char)*strlen(s));
}

#ifdef __cplusplus
} /* End extern "C" block */
#endif

#ifdef __cplusplus
extern "C" {
#endif

static int mclDefaultErrorHandler(const char *s)
{
  int written = 0;
  size_t len = 0;
  len = strlen(s);
  written = mclWrite(2 /* stderr */, s, sizeof(char)*len);
  if (len > 0 && s[ len-1 ] != '\n')
    written += mclWrite(2 /* stderr */, "\n", sizeof(char));
  return written;
}

#ifdef __cplusplus
} /* End extern "C" block */
#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library.
 */

#ifndef LIB_QF_C_API
#define LIB_QF_C_API /* No special import/export declaration */
#endif

LIB_QF_C_API
bool MW_CALL_CONV QFInitializeWithHandlers(
    mclOutputHandlerFcn error_handler,
    mclOutputHandlerFcn print_handler)
{
    int bResult = 0;
  if (_mcr_inst != NULL)
    return true;
  if (!mclmcrInitialize())
    return false;
  if (!GetModuleFileName(GetModuleHandle("QF"), path_to_dll, _MAX_PATH))
    return false;
    {
        mclCtfStream ctfStream =
            mclGetEmbeddedCtfStream(path_to_dll);
        if (ctfStream) {
            bResult = mclInitializeComponentInstanceEmbedded(   &_mcr_inst,
                                                                error_handler,
                                                                print_handler,
                                                                ctfStream);
            mclDestroyStream(ctfStream);
        } else {
            bResult = 0;
        }
    }  
    if (!bResult)
    return false;
  return true;
}

LIB_QF_C_API
bool MW_CALL_CONV QFInitialize(void)
{
  return QFInitializeWithHandlers(mclDefaultErrorHandler, mclDefaultPrintHandler);
}

LIB_QF_C_API
void MW_CALL_CONV QFTerminate(void)
{
  if (_mcr_inst != NULL)
    mclTerminateInstance(&_mcr_inst);
}

LIB_QF_C_API
void MW_CALL_CONV QFPrintStackTrace(void)
{
  char** stackTrace;
  int stackDepth = mclGetStackTrace(&stackTrace);
  int i;
  for(i=0; i<stackDepth; i++)
  {
    mclWrite(2 /* stderr */, stackTrace[i], sizeof(char)*strlen(stackTrace[i]));
    mclWrite(2 /* stderr */, "\n", sizeof(char)*strlen("\n"));
  }
  mclFreeStackTrace(&stackTrace, stackDepth);
}


LIB_QF_C_API
bool MW_CALL_CONV mlxQ_filt(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
  return mclFeval(_mcr_inst, "Q_filt", nlhs, plhs, nrhs, prhs);
}

LIB_QF_CPP_API
void MW_CALL_CONV Q_filt(int nargout, mwArray& Out, const mwArray& u, const mwArray& n,
                         const mwArray& m, const mwArray& q)
{
  mclcppMlfFeval(_mcr_inst, "Q_filt", nargout, 1, 4, &Out, &u, &n, &m, &q);
}
 


-- 16.04.2017, 15:06 --

самого алгоритма там почему то нет, наверно он в библиотеках .lib, но они то же есть в рабочем каталоге

Код:
>> mcc -win64 -W cpplib:QF -T link:lib -d C:\Users\User\Documents\MATLAB\Out  C:\Users\User\Documents\MATLAB\Cardi\стат_тесты\Q_filt.m
Warning: Adding path "C:\Users\User\Documents\MATLAB\Cardi\стат_тесты" to
Compiler path instance. 

Код:
>> mex bolz2000_qc.cpp
LINK : error LNK2001: неразрешенный внешний символ "mexFunction"
C:\Users\User\AppData\Local\Temp\mex_BLjGLN\templib.x : fatal error LNK1120: 1 неразрешенных внешних элементов

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение16.04.2017, 15:37 
Экс-модератор


12/07/07
2920
Донецк, Украина
mcc
Имя бинарного mex-файла должно совпадать с именем функции, см., справку или указанную выше книгу. (Грубо говоря, matlab по имени встретившейся функции ищет m-файл или mex-файл. Если имена не совпадают, то код функции не будет найден.) Проще всего ничего не переименовывать. m-файл уже должен иметь имя совпадающее с именем (основной) функции.

mex
Компилируется не тот файл или с неправильным именем (bolz2000_qc.cpp).

[1. Я для каждого проекта создаю отдельную директорию и в среде делаю её рабочей. Конечно, файлы идущие с matlab в эту директорию не копирую; «настраиваю пути».
2. mcc - lib не надо создавать.
3. Очень рекомендую почитать документацию. Так и легче общаться (если встретятся реальные проблемы), и проще гуглить, и быстрее результат получается.]

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение16.04.2017, 17:31 
Аватара пользователя


07/10/15
239
В общем сделал всё так как Вы и написали:
1. создал папку Out.
2. скомпилировал туда исходниси С++, lib создавать не стал (правда, думаю это ни на что не влияет)
Код:
>> mcc -win64 -W cpplib:Q_filt -d C:\Users\User\Documents\MATLAB\Out  C:\Users\User\Documents\MATLAB\Cardi\стат_тесты\Q_filt.m
Warning: Adding path "C:\Users\User\Documents\MATLAB\Cardi\стат_тесты" to
Compiler path instance.

Все исходники появились в папке. Копировать в неё ничего не стал. Сделал её текущей и запустил
Код:
>> mex Q_filt.cpp
выдаёт ошибку:
Код:
LINK : error LNK2001: неразрешенный внешний символ "mexFunction"
C:\Users\User\AppData\Local\Temp\mex_U98333\templib.x : fatal error LNK1120: 1 неразрешенных внешних элементов
Cудя по всему это из за отсутствия необходимых библиотек. Вы пишите что ничего копировать не надо, а нужно просто прописать пути. Подскажите, пожалуйста, как это сделать и какие папки надо прописывать? (предполагаю что addpath нужно использовать, но какие папки нужно прописывать не знаю точно)

PS: документацию я тоже читаю, но толку от этого пока мало.
Попробовал приведённый там пример
Код:
>> mex timestwo.c
В нём используется только один исходник на С без каких-либо заголовочных файлов, и при этом, полученный .mexw64 прекрасно работает.
То ли у меня с самой функцией что-то не так, то ли ещё что, то ли в С надо, а не в С++ компилировать, пока не знаю в чём дело. Такое впечатление, что сама судьба обратилась против меня .... проблемы на пустом месте

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение16.04.2017, 22:25 
Экс-модератор


12/07/07
2920
Донецк, Украина
1. Конечно, создание lib ни на что не влияет. Но если будет меньше файлов, то легче разобраться.

2. Сообщение об ошибке (при запуске mex) означает, что нет определения функции mexFunction. (Это «интерфейсная» функция, которая получает данные от matlab, вызывает основную функцию и после её завершения возвращает результаты в Matlab.)
В приводимых в документации примерах (и примерах в соответствующем подкаталоге matlab на локальном диске) исходники содержат mexFunction.
У меня нет под рукой R2013, поэтому посмотрите на свои файлы. Если среди них нет файла содержащего mexFunction (Q_filt_mex.c) и текст Q_filt не содержит определение этой функции (так скорее всего и будет), то эту функцию нужно будет создать вручную и дописать в Q_filt.
После этого mex.

3. Из Q_filt.m можно создать нужный Q_filt.mexw64 в Matlab Coder.
Для этого.
    1. Перейти на вкладку Appl. Запустить Coder. Выбрать m-файл.
    2. Указать тип аргументов.
    3. Подправить имя выходного файла и нажать Built.
Эти шаги подробно описаны в документации “Matlab Coder”. В простейших случаях всё легко получается.

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение17.04.2017, 02:17 
Аватара пользователя


07/10/15
239
Спасибо!
с Matlab Coder получается намного лучше,
кое как прописал входные переменные (их можно объявлять прямо в коде m - функции)
теперь ругается на сам код. Вот, например, такие конструкции он не воспринимает

  1.  relate=[r;relate];  


т.е. операция конкатенации не компилируется. Есть там и другие операции, которые компилироваться с помощью Matlab Coder видимо не будут. Теперь мне представляется единственный путь - это переделывать код.

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение17.04.2017, 07:10 
Аватара пользователя


07/10/15
239
GAA в сообщении #1209990 писал(а):
В приводимых в документации примерах (и примерах в соответствующем подкаталоге matlab на локальном диске) исходники содержат mexFunction.


Да, действительно,
посмотрел С код примера - в нём есть mex функция
Код:
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )


сейчас попробую себе в исходник дописать что ни будь похожее, может получится лучше чем с Matlab Coder

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение17.04.2017, 14:41 
Аватара пользователя


07/10/15
239
К сожалению ничего не вышло, в исходнике .cpp нет самого алгоритма, только прототипы разных функций. Наверное это из-за выше указанных несоответствий.

Попробовал скомпилировать другую функцию. После небольшой модификации кода всё таки получилось.
Только вот результаты меня мягко говоря удивили:

Код:
>> codegen -config config_obj jade
Code generation successful: View report
>> tic; [A,S]=jade(V(:,1:50)',50); toc;
Elapsed time is 77.804615 seconds.
>> tic; [A,S]=jade_mex(V(:,1:50)',50); toc;
Elapsed time is 775.629398 seconds.

получается скомпилированный вариант работает в 10 раз медленнее чем исходная m-функция

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение13.05.2017, 08:00 
Аватара пользователя


07/10/15
239
Долгие старания всё же дали свой результат. Пишу на всякий случай - может кому пригодится.
1. Компилировать напрямую m-функции дело на мой взгляд малоперспективное. Может быть полезно если только в целях создания автономных приложений. Быстродействие при этом может даже понижаться (в моём случае в 10 раз).
2. Лучше всего делать как советовал GAA - писать код функции непосредственно на С или С++, а потом компилировать в .mex файл. Код можно писать прямо в matlab-Editor и сохранять рабочей папке. Единственный нюанс - в конце нужно дописать интерфейсную функцию, с прототипом
Код:
void mexFunction(int nOut, mxArray* pOut[], int nIn, const mxArray* pIn[])

в ней прописываются соответствия matlab - переменных и интерфейсных переменных главной C++ функции.

Тут есть свои особенности: 1. Все переменные mexFunction имеют тип double. Если в С++ функции используются другие типы, то нужно использовать reinterpret_cast. 2. Входные аргументы полученной mex - функции имеют тип cost Array и изменить их в функции видимо никак не получится (по крайней мере у меня не получилось) и это конечно недостаток.

В моём проекте использовался только один заголовочный файл
Код:
#include "mex.h"
все функции проекта - на одном листе, mexFunction - самая последняя.
Всё работает отлично
Код:
>> tic;quantilfit(x,y,4,0.5);toc;
Минимум F достигнут на 2040 итерации, прошло 1 мин. -45 сек.
MAD=1.56e+10 ,R2=1 ,ajR2=1
Elapsed time is 14.114526 seconds.
>> mex simplex.cpp
>> tic;simplex(x,y,4,0.5);toc;
Elapsed time is 0.171764 seconds.
>>

ускорение работы почти в 100 раз - для меня это очень хорошо.

Как запускать уже скомпилированные .dll через loadlibrary, пока не разобрался.

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение13.05.2017, 15:27 
Аватара пользователя


07/10/15
239
Приношу свои извинения, в действительности совет компилировать критичные к скорости фрагменты из С++ - кода в DLL давал Geen а не GAA. Написал по ошибке.

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение13.05.2017, 22:33 
Заслуженный участник
Аватара пользователя


01/09/13
1258
Andrey_Kireew в сообщении #1216104 писал(а):
Все переменные mexFunction имеют тип double.

Это что-то странное...

Andrey_Kireew в сообщении #1216104 писал(а):
Входные аргументы полученной mex - функции имеют тип cost Array

В MatLab'е вообще всё аргументы традиционно по значению передаются...

 Профиль  
                  
 
 Re: использование DLL в Matlab
Сообщение13.05.2017, 23:10 
Аватара пользователя


07/10/15
239
Под mexFunction я имел ввиду C++ интерфейс, т.е. фрагмент C++ кода, добавляемый в основной код для обеспечения связи с matlab. В откомпилированном .mexw64 - файле, разумеется, использование указателей не предусмотрено.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 27 ]  На страницу Пред.  1, 2

Модераторы: Toucan, maxal, Karan, PAV, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group