понедельник, 29 октября 2007 г.

Опыты со SWIG'ом: C++ код и Ruby

Недавно у меня возник вопрос, как скрестить C++ и Ruby, а именно - есть С++ либа, хотелось бы использовать ее из Ruby. Покопавшись немного в инете, нашел статью "Использование C и Ruby", откуда стало ясно, что основные способы создания расширений для Руби - использование Ruby API (ruby.h, rubyio.h, intern.h) и утилита SWIG. Для начала решил попробовать SWIG.

SWIG на основе С и С++ интерфейса генерит код для расширений к другим высокоуровневым языкам (причем не только к скриптовым). На входе получает файл интерфейса .i, на выходе - С или С++ код.

В качестве примера берем такой код:

Создаем интерфейсный файл test.i:

Тепер на основанни этого файла можно сгенерить код расширения для Руби:

swig -c++ -ruby test.i

Очевидно, что -ruby указывает целевой язык.

Ключ -с++ указывает на то, что исходный код написан на с++. Если этого не указать, то может вылезти ворнинг типа: "test.i:7 Warning(301): class keyword used, but not in C++ mode.", файл получится с расширением .c и в дальнейшем возникнут проблемы с его сборкой.

Для указания имя модуля можно использовать либо ключ -module либо в интерфейсном файле добавить строку %module name.

Результат выполнения команды файл test_wrap.cxx. Получить необходимую библиотеку из него можно двумя способами - создать скрипт, генерящий make-файл или собрать в ручную. В ручную это будет выглядеть подобным образом:

Скрипт, создающий Makefile, будет выглядеть так:

В итоге получилась библиотека test.so. Осталось посмотреть, как это будет работать в Руби:

В принципе ничего сложного.

Интересно что получится, если type_t определить как std::string... Все описанные выше манипуляции прошли нормально, но вот тест не пошол, в месте require 'test' выводит ошибку 'LoadError'. Просто так не получается, но SWIG предоставляет механизм typemaps - трансляция С/С++ типа в тип целевого языка, т.е. теоретически можно использовать контейнеры STL в коде, который будет использоваться Руби, но это оставлю до следующего раза.

2 комментария:

sash_ko комментирует...

Вообще в test.i вместо куска кода (class MyTest...), можно просто добавить
%include "test.h"
Тогда и файл будет выглядеть меньше и менять его не придется при изменении test.h.

Unknown комментирует...

Спасибо за флаг "-с++"!