Как я дружил MatLab и C++ в Linux

в 14:25, , рубрики: c++, linux, Matlab, qt, метки: , , ,

Как я дружил MatLab и C++ в Linux
Прошла пора дипломов и я хочу поделиться своим рецептом его выполнения. Итак: тема сложная, времени мало, писать все «с нуля» или искать готовые библиотеки — нет большого желания, тем более что мне важна скорость работы системы, а от левых самописных библиотек можно ждать любого подвоха.
Надо сказать что размышлял я недолго и пришел к следующим выводам:

  1. Операционная система — тут думать особо не пришлось: т.к. я являюсь поклонником Debian (к слову: мое решение можно перенести и на Windows).
  2. Интерфейс будущей программы — C++, Qt.
  3. Логика программы — MatLab.

Подготовка

Для работы системы нам необходимы следующие компоненты:

  1. Так называемый MATLAB Compiler Runtime. Это свободно распространяемый набор динамических библиотек MatLab. Скачать его можно с официального сайта и пользовать на свое усмотрение.
  2. Собственно сам Qt. Скачивается из репозиториев Linux, либо с официального сайта.

Установка

MATLAB Compiler Runtime распространяется в zip архиве. Внутри вы найдете файл install.sh. После его запуска откроется графический инсталятор, который в 3 клика сделает свое дело.
Qt ставится из репозиториев. Если вы скачали свеженькую версию с сайта, то необходимо выполнить следующие действия:
Под рутом:

mkdir /opt/QtSDK
chown %username% /opt/QtSDK

Дальнейшую установку производим обязательно от имени пользователя и в каталог /opt/QtSDK
С установкой закончили, переходим к настройкам:
Необходимо прописать библиотеки в системе, для этого:

echo /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/runtime/glnxa64 >> /etc/ld.so.conf.d/matlabLibs.conf
echo /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/os/glnxa64 >> /etc/ld.so.conf.d/matlabLibs.conf
echo /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnxa64/jre/lib/amd64/native_threads >> /etc/ld.so.conf.d/matlabLibs.conf
echo /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnxa64/jre/lib/amd64/server >> /etc/ld.so.conf.d/matlabLibs.conf
echo /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnxa64/jre/lib/amd64 >> /etc/ld.so.conf.d/matlabLibs.conf
ldconfig

И прописать переменную окружения XAPPLRESDIR (необходимы права рута):

export XAPPLRESDIR="/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/X11/app-defaults"

Далее необходимо скопировать файл: /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/X11/app-defaults/Matlab в домашнюю директорию пользователя. Вообще, в теории, этого делать не надо, но без этого ничего не работает. Это известный баг, но его пока еще не исправили.
Пройдусь немного по путям к библиотекам:

  • Часть /usr/local/MATLAB/MATLAB_Compiler_Runtime/ может меняться в зависимости от того, куда вы устанавливали MCR.
  • Часть v716/ это версия самого MatLab и она тоже может меняться.
  • Часть glnxa64/ для 64 битной ОС и glnxa32 для 32 битной ОС.

Да и вообще. Все эти пути будут написаны на финайльной стадии установки MCR, но копировать их я не советую и предлагаю перепроверить и переписать все вручную (не знаю в чем тут дело, но у меня на двух разных машинах тупое копирование этих путей не дало результатов). Также после установки будет еще один путь: /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/os/glnxa64, его прописывать я не советую: т.к. после этого у меня отказались запускаться все программы, а без него все прекрасно работает.

Расчехляем MatLab

Теперь можно писать логику будущего приложения. Создаем новый m-файл и пишем новую функцию. Функция у нас будет простая: будем суммировать два переданных массива чисел:

function [out] = SUM(in1, in2)
    out = in1 + in2;
end

Все готово для компиляции этой функции в динамическую библиотеку:

  1. Пишем в консоли MatLab: deploytool.
  2. В открывшемся окне пишем имя проекта, его расположение а из выпадающего списка выбираем C Shared library и нажимаем OK. Учтите, что в Linux названия библиотек начинается со слова lib, поэтому и проект стоит называть libsum.prj
  3. В окне Exported Functions нажимаем на Add files и добавляем только что созданную функцию.
  4. Нажимаем на кнопку Build и дожидаемся окончания компиляции.

После компиляции в папке с проектом окажется папка distrib, в которой и будет находиться наша библиотека и заголовочный файл.
На этом работа с MatLab закончена.

Расчехляем Qt

Запускаем Qt и создаем новый проект.
В pro файле прописываем пути к библиотекам и заголовочным файлам:

INCLUDEPATH += /usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/extern/include
LIBS += -L/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/bin/glnxa64/ -leng -lm
#При условии, что скомпилированная библиотека лежит в каталоге lib создаваемого проекта
LIBS += -L$$PWD/lib/ -lsum
#При условии, что заголовочный файл лежит в каталоге include создаваемого проекта
INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include

В самом проекте пишем следующией код:

#include <QtCore/QCoreApplication>
#include <libsum.h>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    cout<<"Loading..."<<endl;
    if (!libsumInitializeWithHandlers(NULL, 0)){
        cout<<"Could not initialize the application."<<endl;
        return -1;
    }
    if (!libsumInitialize()){
        cout<<"Could not initialize the library."<<endl;
        return -2;
    }
    mxArray *in1        = mxCreateDoubleMatrix(2, 1, mxREAL);
    mxArray *in2        = mxCreateDoubleMatrix(2, 1, mxREAL);
    mxArray *out        = mxCreateDoubleMatrix(2, 1, mxREAL);
    double *i1 = mxGetPr(in1);
    double *i2 = mxGetPr(in2);
    i1[0] = 1;
    i1[1] = 2;
    i2[0] = 3;
    i2[1] = 4;

    if(!mlfSUM(1, &out, in1, in2)){
        cout<<"Could not execute function."<<endl;
    }
    double *res = mxGetPr(out);
    cout<<res[0]<<"; "<<res[1]<<endl;

    mxDestroyArray(in1);
    mxDestroyArray(in2);
    mxDestroyArray(out);
    cout<<"Terminating..."<<endl;
    libsumTerminate();
    return 0;
}

Вот и все. Можно запускать.

Выводы

Диплом выполнен, программа работает, я — счастливый инженер по информационным технологиям. Вроде бы все хорошо и радужно, но есть парочка нюансов:

  1. Размер архива MCR составляет 874 Мб.
  2. После запуска программы — начинают загружаться библиотеки MatLab и это откладывает запуск на пару секунд.

Правда есть и плюсы:

  1. Вы можете сосредоточить свое внимание на основной работе, не заботясь об оптимизации побочных функций и отлове ошибок в них.
  2. Скорость выполнения функций MatLab намного выше той, что вы смогли бы добиться за 3 месяца работы над проектом.
  3. Вы получаете всю силу MatLab в своем приложении.
  4. Время работы над проектом сокращается.

Если будет интересно напишу как я таким образом распознавал голосовые команды при помощи нейронных сетей.

Автор: Impuls

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js