Matlab engine - cz. 1.

Silnik Matlaba (Matlab engine) jest zbiorem współdzielonych bibliotek, które umożliwiają komunikację między silnikiem obliczeniowym Matlaba a zewnętrznymi programami napisanymi w C/C++ i Fortranie. W przeciwieństwie do mrowia sposobów oferowanych przez najnowsze wersje Matlaba (na tę chwilę 2011a z 8 kwietnia tego roku), które wykorzystują nowe toolboksy (jak MATLAB Builder JA), użycie silnika Matlaba oferuje całkowitą kompatybilność wsteczną. Nie jestem pewien czy wersje starsze niż 5.1 też udostępniały te biblioteki, jednak Matlab 5.3 jest nadal masowo eksploatowany w różnych przedsiębiorstwach, w szkołach i na uczelniach.

Niniejszy artykuł jest wstępem do krótkiego poradnika obsługi silnika Matlaba. Nie jest to dokumentacja – wszystkie funkcje udostępnianego API są dość dobrze udokumentowane. Jest to raczej ściągawka najczęstszych problemów, które pojawiają się przy pisaniu programów używających silnika do komunikacji z sesjami Matlaba.

Użycie bibliotek silnika Matlaba ma jedną bardzo poważną wadę. Wymaga posiadania zainstalowanego Matlaba. Jeśli nie chcesz instalować Matlaba, być może powinieneś zainteresować się, drogi Czytelniku, Matlabowskim środowiskiem MCR (Matlab Compiler Runtime), które instaluje minimalną ilość bibliotek wymaganą do wykonywania plików *.m. Tak czy siak, na potrzeby niniejszej prezentacji potrzebować będziemy co zainstalowanego Matlaba w wersji 5.3. Dla celów niniejszego artykułu wprowadzę również oznaczenie bezwzględnej ścieżki głównego katalogu Matlaba: $MATLABROOT.

Położenie

Wszystkie niezbędne do szczęścia biblioteki znajdują się w katalogu $MATLABROOT/bin/$ARCH gdzie $ARCH oznacza architekturę komputera (np. glnx86 dla 32-bitowego Linuksa, mac dla Macintosha z procesorem PowerPC, win32 dla 32-bitowego Windowsa itp.). Należy pamiętać, że starsze wersje Matlaba (np. wspomniana już 5.3) nie obsługują różnych architektur komputerów, więc wszystkie niezbędne biblioteki znajdują się bezpośrednio w katalogu bin. Nowe wersje teoretycznie zapewniają zgodność ze starszymi poprzez dołączenie w katalogu bin odpowiedniego skryptu, lecz praktycznie błędy pojawiają się na poziomie linkowania w czasie kompilacji, a później ustawiania odpowiednich ścieżek do zmiennych środowiskowych.

Poza powyższymi kompilator będzie potrzebował jeszcze plików nagłówkowych do silnika. Znajdują się one w katalogu: $MATLABROOT/extern/include

Dołączanie wszystkiego do projektu

W celu zbudowania projektu należy oczywiście ustawić odpowiednie flagi w naszym ulubionym kompilatorze, czyli gcc. Dlaczego nie kompilujemy na sposób Matlaba, czyli przy pomocy programu mex? Dlatego, że przysparza to jedynie problemów. Przede wszystkim Matlab nie dostarcza kompilatora języka C++, więc musimy zmusić ichnie rozwiązanie do współpracy z zewnętrznym kompilatorem tegoż języka. Stosowanie takich wrapperów wydaje mi się bezcelowe, skoro mogę stworzyć starego, dobrego Makefile’a. Poza tym polecenie mex -setup lubi nie wykryć kompilatora C++.

Oczywiście na początek:

g++ (...) -I$MATLABROOT/extern/include (...)`

Pominąłem w powyższym wszystkie inne flagi i pliki, bo zależą one od posiadanej architektury, pisanego programu i własnych preferencji.

Następnym krokiem jest to co przysparza, jak wynika z mych pobieżnych oględzin for internetowych, najwięcej problemów. Linkowanie wszystkiego.

Przede wszystkim należy przekazać linkerowi katalog, w którym zamieszczone są biblioteki silnika. Robi się to przy pomocy przełącznika -L$MATLABROOT/bin/$ARCH. Następnie należy wskazać bezpośrednio dwie biblioteki: libeng oraz libmx. Robi się to przy pomocy przełączników -leng -lmx. To nie wszystko. Obie te biblioteki korzystają z innych bibliotek, które rezydują razem z nimi w katalogu (ldd -d libeng.so). Najprościej uwzględniamy je w linkerze przy pomocy przełącznika -rpathlub -rpath-link. Odpowiednia opcja w linkerze wygląda następująco: -Wl,-rpath-link,$MATLABROOT/bin/$ARCH. Dokumentacja podaje wprawdzie, że używane biblioteki muszą rezydować w tym samym katalogu co libeng i libmx, ale empirycznie sprawdziłem, że jest to kłamstwo wierutne. Z drugiej strony, skoro i tak Matlab musi być zainstalowany (licencja), to co za różnica, gdzie będą?

Alternatywą dla rpath, jeśli ktoś bardzo się gryzie z tą dyrektywą, jest zaktualizowanie ścieżek wyszukiwania bibliotek w katalogu /etc/ld.so.conf:

touch /etc/ld.so.conf/matlab.conf
echo $MATLABROOT/bin/$ARCH >> /etc/ld.so.conf/matlab.conf

Koniec końców, w przypadku użycia rpath-link, nasze polecenie będzie wyglądać następująco:

g++ -L$MATLABROOT/bin/$ARCH -leng -lmx -Wl,-rpath-link,$MATLABROOT/bin/$ARCH
(...)

To by było na tyle w tej części. W następnej może napiszę już jakiś prosty program. :)