Сначала DllNotFoundException, затем EntryPointNotFoundException при вызове чистой функции C из C#
Я пытаюсь использовать код на C в Unity3D pro.
Мой основной подход заключается в том, чтобы (1) встроить исходный код C в статическую библиотеку (2) создать пустой пакет и связать его с библиотекой (3) импортировать пакет в Unity 3D pro (в качестве плагина).
Я в основном следовал этому уроку.
Это работало для меня некоторое время до недавнего времени, когда я обновлял свой код C и перекомпилировал и перестраивал библиотеку и пакет, все идет не так, как надо...
Когда я впервые импортировал пакет, я получил исключение DllNotFoundException.
На этом этапе мой пакетный проект представлял собой просто кучу библиотек - библиотека, построенная из моего исходного кода (который представляет собой файл.a) и несколько других библиотек, от которых, как мне кажется, зависит библиотека.a (другие библиотеки имеют расширение.dylib).).
Я добавил один файл test.c в комплект. Тестовый файл.c содержит только две строки:
#include <stdio.h>
#include "ccn.h"
char* say()
{
return "hi";
}
в котором ccn.h является заголовочным файлом из моего исходного кода на языке C.
После того, как я перестроил пакет, DllNotFoundExeption исчез, но я получил EntryPointNotFoundException.
Вот что я думаю:
- Поскольку Xcode настолько интеллектуален, я предполагаю, что, добавляя простой файл test.c, Xcode изменил некоторые настройки моего пакета для меня. И я полагаю, что это причина, почему DllNotFoundException ушла в первую очередь. Я правильно думаю?
- Я думаю, что для решения проблемы EntryPointNotFound мне также придется изменить некоторые настройки проекта пакета - но я не знаю, как... Пожалуйста, помогите мне...
Большое и большое спасибо!
редактировать
- Я видел этот поток, предлагающий, что, поскольку XCode использует g++ для компиляции, мне понадобится extern "C", даже если мой неуправляемый код находится на чистом C. Я изменил настройку цели в XCode4 для " Compiler for C / C++ / Objective-C " от Apple LLVM 3.0 до LLVM GCC 4.2, но я все еще получаю то же исключение.
- Я также видел эту моно документацию, в которой говорится, что mono использует GLib для загрузки библиотек, и у Glib есть ошибка в Mac OS X, которая заключается в том, что он не распознает библиотеки.dylib. Я удалил библиотеки.dylib и попробовал еще раз, но получал то же исключение.
- Также в документации Apple говорится, что каждый загружаемый пакет должен иметь основной класс, и если пользователь не указывает, какой класс является основным, NSBundle будет использовать первый класс, показанный в проекте XCode, в качестве основного класса. Ну, я предполагаю, что созданный мной пакет является загружаемым пакетом, но поскольку он представляет собой просто статическую библиотеку, созданную из C, он буквально не имеет никакого класса. Когда я посмотрел на info.plist моего проекта, запись основного класса просто пуста. Может ли это быть проблемой? Если да, то как мне это решить?
Также в документации Apple я увидел кое-что, чего я не совсем понял:
Если загружаемый пакет представляет собой плагин, разработчик хост-приложения обычно предоставляет интерфейс для архитектуры плагина в платформе. Эта структура обычно содержит класс, от которого наследуются все основные классы подключаемого модуля, или протокол (формальный или неформальный) для принятия основным классом подключаемого модуля.
Я уверен, что загружаемый пакет, который я создаю, является плагином. Я импортирую пакет в Unity3D. Означает ли это, что я должен определить основной класс из Unity? Как?
1 ответ
Проблема имеет простое решение:
сначала попробуйте любую функцию, которая дает вам исключение EntryPointNotFoundException в файле test.c.
Под "попыткой" я подразумеваю, чтобы функция вызывалась в вашем main() и сначала проверялась в C.
В моем случае функция, которая выбрасывает исключение EntryPointNotFoundException, называется ccn_run(). Итак, я сделал следующие вещи:
- добавить функцию main() в test.c
- введите ccn_run () в функцию main()
- добавить цель командной строки в проект Xcode и протестировать ее
Я попробовал это, и функция работает нормально в C, теперь волшебная вещь состоит в том, что когда я перестраиваю пакет (без удаления функции main() и вызова ccn_run () внутри него), Unity может вызвать функцию ccn_run () без проблем!
Я не мог объяснить, почему это решает мою проблему, но это работает для меня уже почти месяц. Недавно Xcode обновился до 4.3.2, и я попробовал тот же подход снова, все еще работает. Я думаю, возможно, добавление функции main() помогает определить точку входа?
Наконец, я задокументировал весь процесс импорта кода C в Unity, и я рад поделиться с ним здесь: https://docs.google.com/document/d/1vAeupNQlBTY3y3Bma5Jo_Hs4JRYm6FoEc4vQN0WBGNg/edit
Мой пример кода:
- Проект Xcode: https://github.com/CherryQu921/CCNxPlugin
- Проект Unity: https://github.com/CherryQu921/cqs
Надеюсь, что этот ответ особенно помогает мой урок!