#d #gobject #clutter
#d #gobject #беспорядок
Вопрос:
Я изучаю возможность создания привязки Clutter для языка D (http://d-programming-language.org /) и начали с того, что попробовали несколько простых тестов с использованием динамической загрузки libclutter. Я столкнулся с проблемой, которая может быть связана с системой наследования GObject, и я был бы признателен за любую помощь в ее решении. Вот краткое изложение: использование clutter_stage_get_default возвращает ClutterActor *, который я могу использовать с методами clutter_actor_ *. Но я всегда получаю ошибки или сбои в сегментах, когда я использую методы clutter_stage_ * или clutter_container__ *. Вот мой тестовый код:http://pastebin.com/nVrQ69dU
При вызове clutter_container_add_actor в строке 56 я получаю следующую ошибку: (<unknown>:11976): Clutter-CRITICAL **: clutter_container_add_actor:
assertion 'CLUTTER_IS_CONTAINER (container)' failed
В примере кода я заметил макросы CLUTTER_STAGE и CLUTTER_CONTAINER для приведения (они, очевидно, мне недоступны), но, насколько я мог судить, они просто выполнили некоторые проверки, а затем выполнили простое приведение C. Если это неверно, и перед приведением к указателю stage необходимо выполнить какую-то магию типа Gobject, пожалуйста, дайте мне знать. Привязка и использование clutter_stage_set_title или clutter_stage_set_color с cast(ClutterStage*)stage
привели к ошибкам сегментации, предположительно, с той же проблемой.
РЕДАКТИРОВАТЬ: Вот урезанный пример без каких-либо внешних зависимостей (если вы не используете Linux, вам нужно будет заменить вызовы dl эквивалентами вашей ОС). Этот код завершается с ошибкой segfault, которая, согласно GDB и Valgrind, находится в clutter_stage_set_title (in /usr/lib/libclutter-glx-1.0.so.0.600.14)
Ответ №1:
Проблема в том, что вы не объявляете функции C как extern(C)
. Из-за этого dmd думает, что вы вызываете общую функцию, и использует неправильное соглашение о вызове. Один из способов сделать это правильно выглядит следующим образом:
alias extern(C) void function(void*, const char*) setTitleFunc;
auto clutter_stage_set_title = getSym!(setTitleFunc)("clutter_stage_set_title");
Хотя я не уверен, как заставить его работать без псевдонима. DMD отказывается анализировать что-либо с extern(C)
в параметре шаблона:
auto clutter_stage_set_title = getSym!(extern(C) void function(void*, const char*))("clutter_stage_set_title"); //Doesn't work
Кстати: Ваша cstring
функция опасна: она возвращает символ *, указывающий, что строка может быть изменена, но это не всегда верно: если вы передаете строковый литерал в toStringz
, он может не выделить новую память, а вместо этого вернуть указатель на исходную строку. Строковые литералы находятся в памяти, доступной только для чтения, поэтому это может привести к проблемам.
Вы могли бы просто настроить типы ваших функций в соответствии с типами C ( const gchar*
в C —> const char*
в D) и использовать toStringz напрямую.
Комментарии:
1. Ах, я не понимал, что мне нужно было указывать соглашение о вызовах C при динамическом связывании, хотя, оглядываясь назад, это имеет смысл.
Ответ №2:
структуры в D не могут наследовать друг от друга, и приведение указателей на структуры вернет null, если не будет промежуточного приведения к Я получил опровержение здесь void*
(в отличие от приведения C)
вам лучше добавить еще один уровень абстракции, используя структуры с переносом дескрипторов и эмулируя проверки из этих макросов при приведении
но что произойдет, если вы сделаете
clutter_container_add_actor(cast(ClutterContainer*)(cast(void*)stage), textbox);
(сначала преобразование в void *, а затем в ClutterContainer *)
Комментарии:
1. Использование вашего предложения приводит к тем же результатам. Кроме того, приведение указателей структуры к нулевому значению не приводит
writeln(stage); writeln(cast(ClutterContainer*)stage);
к двум идентичным адресам памяти. Я использую DMD 2.053, если это имеет какое-либо значение.2. @justin возможно, вам просто придется использовать указатели void для дескрипторов Clutter, это то, что я видел в других библиотеках, взаимодействующих со структурами в стиле C
3. @justin или попытайтесь получить точную структуру структур и воссоздать их в файлах общего интерфейса и попробуйте это с этими
4. Поскольку я просто передаю указатели от одной функции clutter к следующей, мне не нужно ничего знать о содержимом структур. Кроме того, отредактированный вопрос со ссылкой на упрощенный, ничего, кроме примера void *.
5. @justin кстати, импортируемые вами функции выполнены в соответствии с соглашением о вызовах C?