вызов C++ DLL из LuaJIT

Я знаю, что не могу использовать FFI для загрузки DLL C++ (подойдет только C), так как мне это сделать? Если мне нужно использовать обертку, как именно мне начать с этим?

РЕДАКТИРОВАТЬ: я никак не могу изменить DLL.


person theman    schedule 29.05.2014    source источник


Ответы (2)


Вы можете попробовать изменить имена вручную в cdefs FFI, но разные компиляторы используют разные схемы изменения имен, не говоря уже о том, что обращение к функциям было бы неудобным.

Вместо того, чтобы вручную изменять имена в cdef, я рекомендую написать какую-нибудь оболочку на C. Хотя это утомительно, это не так уж сложно. Суть в том, что на стороне C классы рассматриваются как непрозрачные структуры, которые можно передать функциям-оболочкам. посетите этот сайт, где можно найти более подробную информацию и некоторые ошибки. .

Вот пример фрагмента оболочки, которую я использую для Box2D:

#include <Box2D/Box2D.h>

#ifdef __linux__
    #define CEXPORT extern "C"
#else
    #define CEXPORT extern "C" __declspec(dllexport)
#endif


// ///////////////////////////////////////////////////////
// World

CEXPORT b2World* b2World_new(b2Vec2* gravity) {
    return new b2World(*gravity);
}
CEXPORT void b2World_destroy(b2World* world) {
    delete world;
}
CEXPORT b2Body* b2World_createBody(b2World* world, const b2BodyDef* def) {
    return world->CreateBody(def);
}
CEXPORT void b2World_destroyBody(b2World* world, b2Body* body) {
    world->DestroyBody(body);
}
CEXPORT void b2World_step(b2World* world, float32 timeStep, int32 velIters, int32 posIters) {
    world->Step(timeStep, velIters, posIters);
}
CEXPORT b2Body* b2World_getBodyList(b2World* world) {
    return world->GetBodyList();
}

И соответствующий cdecl:

typedef struct b2World b2World;

b2World* b2World_new(b2Vec2*);
void     b2World_destroy(b2World*);
b2Body*  b2World_createBody(b2World*, const b2BodyDef*);
void     b2World_destroyBody(b2World*, b2Body* body);
void     b2World_step(b2World*, float, int32_t, int32_t);
b2Body*  b2World_getBodyList(b2World*);
person Colonel Thirty Two    schedule 30.05.2014

Вы можете использовать C++ DLL. Вам нужно экспортировать такие функции (в MSVC):

extern "C" __declspec(dllexport)

Из-за искажения имени C++ (используемого для перегрузки) сигнатура вашей функции не будет такой же, как именование C. Например, эта функция:

int foo(char* a, int b, double c)

Может быть экспортирован как что-то вроде foo@12abunchoflettershere с использованием именования C++ вместо foo, как это было бы при именовании C.

Обратите внимание, что extern "C" не означает, что ваш код написан на чистом C. Вы можете использовать C++ в обычном режиме. Это все еще в силе:

extern "C" __declspec(dllexport) void foo(char *a, int b, std::shared_ptr<Foo> ptr)
person Bruno Ferreira    schedule 29.05.2014
comment
Хорошо, это имеет смысл. Есть ли способ, которым я все еще могу вызывать функции С++, вообще не изменяя DLL? Возможно, обращение к другой DLL, написанной на C, которая может справиться с искажением имени? - person theman; 29.05.2014
comment
-1: Весь смысл extern "C" в том, что Компилятор C++ не искажает имя. Если вы используете extern "C", вам не нужно беспокоиться об искажении имени. - person Colonel Thirty Two; 30.05.2014
comment
@ColonelThirtyTwo Именно это я и сказал. - person Bruno Ferreira; 30.05.2014
comment
@user2030964 user2030964 Вы можете использовать C++ в обычном режиме. Просто помните, что функции внутри классов не могут быть виртуальными или перегруженными. Возможно, были еще какие-то ограничения, но я сейчас не могу вспомнить. - person Bruno Ferreira; 30.05.2014
comment
@BrunoFerreira Нет, ты этого не сделал. Вы сказали использовать extern "C", а затем сразу же сказать, что сигнатура функции не будет такой же, как именование C, что неверно для функций C. - person Colonel Thirty Two; 30.05.2014
comment
@ColonelThirtyTwo Извините, но я не могу понять вашу точку зрения, не могли бы вы объяснить? При экспорте общих объектов наиболее важной частью extern "C" является изменение имени. - person Bruno Ferreira; 30.05.2014