كيف يمكنني دفع مثيل لفئة c++ ملفوفة بـ swig إلى مكدس lua؟

StackOverflow https://stackoverflow.com/questions/613282

  •  03-07-2019
  •  | 
  •  

سؤال

لدي فصل ملفوف بـ swig ومسجل في lua.يمكنني إنشاء مثيل لهذه الفئة في البرنامج النصي لوا، وكل شيء يعمل بشكل جيد.

لكن لنفترض أن لدي مثيلًا لفئة تم إنشاؤها في كود c++ الخاص بي مع استدعاء X الجديد، ولدي la lua_state L مع وظيفة أريد الاتصال بها، والتي تقبل وسيطة واحدة، مثيل X...كيف يمكنني استدعاء هذه الوظيفة.إليك (بعضًا) من التعليمات البرمجية المعنية (لقد حذفت الأخطاء في معالجة الأشياء):

main.cpp

class GuiInst;
extern "C"
{
    int luaopen_engine (lua_State *L);
}

int main()
{
    GuiInst gui=new GuiInst;
    lua_State *L=luaL_newstate();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);
    lua_getglobal(L,"Init");
    //Somehow push gui onto lua stack...
    lua_pcall(L, 1, 0, 0));
    lua_close(L);
}

mainmenu.lua

function Init(gui)
    vregion=gui:CreateComponent("GuiRegionVertical");
end

في الوقت الحالي، كل ما وجدته يمكن أن ينجح هو الكشف عن بعض الوظائف من ملف cpp الذي تم إنشاؤه بواسطة swig، واستدعاء ذلك.وهذا أمر سيء لعدة أسباب..لن ينجح الأمر إذا كان لدي وحدات متعددة واضطررت إلى تغيير مواصفات الارتباط الافتراضية في ملف swig (باستخدام -DSWIGRUNTIME=).

أقوم بإضافة ما يلي إلى main.cpp

extern "C"
{
    struct swig_module_info;
    struct swig_type_info;
    int luaopen_engine (lua_State *L);
    swig_module_info *SWIG_Lua_GetModule(lua_State* L);
    void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own);
    swig_type_info *SWIG_TypeQueryModule(swig_module_info *start,swig_module_info *end,const char *name);
}
//and then to push the value...
SWIG_Lua_NewPointerObj(L,gui,SWIG_TypeQueryModule(SWIG_Lua_GetModule(L),SWIG_Lua_GetModule(L),"GuiInst *"),0);

يؤدي ذلك إلى الحصول على مؤشر إلى الوحدة، ثم مؤشر إلى النوع، ثم يستدعي وظيفة swigs لتسجيله.لقد كان أمرًا غير معقول أن تضطر إلى البحث في ملف ليس من المفترض أن يكون قابلاً للقراءة من قبل الإنسان (كما هو مذكور في الجزء العلوي من الملف) وهو مجرد فوضوي!(لكنه يعمل!)

بالتأكيد هناك طريقة أفضل لإنجاز ما أحاول القيام به.

ملاحظة: من وجهة نظر عالية المستوى، ما أريده هو عدم قيام Lua بإعادة حساب مكونات واجهة المستخدم الرسومية التي تم إنشاؤها بواسطة Object Factory في GuiInst، في حالة قيامي بهذا الخطأ.هذه هي المرة الأولى التي أعرض فيها وظائف لغة برمجة نصية بصرف النظر عن بعض وحدات بايثون البسيطة جدًا (وغير المعقدة)، لذا فأنا على استعداد لأخذ النصيحة.

شكرا على أي نصيحة!


الرد على تعليق RBerteig

يتم تعريف مُنشئ GuiInst على أنه خاص عند تشغيل swig لمنع lua من إنشاء مثيلات له، لذلك لن ينجح ذلك بالنسبة لي.ما كنت أحاول منعه هو ما يلي (في لوا):

r=engine.GuiRegionVertical()
r:Add(engine.GuiButton())

والذي قد يستدعي "g=new GuiButton" ثم يسجله في GuiRegionVertical (الذي يحتاج إلى تخزين مؤشر لأسباب مختلفة)، ثم يستدعي "delete g"، ويترك GuiRegionVertical بمؤشر متدلي إلى g.

أظن أن ما يجب أن يحدث حقًا هو أن GuiRegionVertical::Add(GuiButton*) يجب أن يزيد عدد المرجع الخاص بـ GuiButton*، ومن ثم يجب أن يؤدي مدمر GuiRegionVertical إلى تقليل إعادة حساب جميع محتوياته، على الرغم من أنني لست متأكدًا من كيفية القيام بذلك يجب القيام به مع غنيمة.

وهذا من شأنه أن يلغي الحاجة إلى شركات البناء الخاصة، وGui Object Factory، والأشخاص الخارجيين السيئين.

هل انا ذاهب حول هذا الخطأ؟

شكرًا.

هل كانت مفيدة؟

المحلول

هناك إجابة بسيطة ومباشرة، والتي قد لا تكون الإجابة الأكثر فعالية.تنتج SWIG أغلفة لمعالجة الكائنات من جانب لغة البرمجة النصية.بالنسبة للكائنات، فإنه يقوم أيضًا بتجميع مُنشئ ملفوف.لذا، فإن الحل المباشر هو السماح لمترجم Lua باستدعاء مُنشئ SWIG لإنشاء الكائن الجديد.

للمغلفة engine.GuiInst فئة، يكاد يكون من المؤكد أنه يمكنك القيام بشيء مثل:

int main()
{
    lua_State *L=lua_open();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);

    luaL_dostring(L, "Init(engine.new_GuiInst())");

    lua_close(L);
}

بالنسبة لحالة لمرة واحدة مثل بدء تشغيل البرنامج النصي، فإن عقوبة تشغيل ثابت سلسلة من خلال luaL_dostring() ليست سيئة على الإطلاق.ومع ذلك، سأبدو أكثر صعوبة لتجنب ذلك في رد اتصال حدث أو حلقة داخلية.

يبدو أنه يجب أن تكون هناك طريقة لتحويل المؤشر مباشرة إلى كائن ملفوف، وأنا لا أكتشفه في حفنة من أغلفة SWIG التي تم إنشاؤها.

يحرر: بالطبع، يمكن تقسيم جزء Lua إلى استدعاءات API التي تجعل جدول المحرك عالميًا على المكدس، واستخراج منه new_GuiInst عضو، اتصل به، ثم اتصل بالعالمي Init, ، ولكن القليل من الكفاءة يأتي على حساب بعض الوضوح.

أما بالنسبة للتعامل مع الكائنات التي لا ينبغي إنشاؤها عن طريق الصدفة في كود المستخدم، فكما يشير السؤال الموضح، سيكون دافعي الأول هو السماح لـ SWIG بإنشاء وظيفة المنشئ، والاحتفاظ بمرجع خاص إذا لزم الأمر لاحقًا، وإزالته من الجدول .حتى وحدة C هي (عادةً) مجرد جدول يحتوي أعضاؤه على قيم دالة.إن تنفيذها في لغة C لا يجعلها للقراءة فقط ما لم يتم بذل جهد إضافي.

لذلك، يمكنك دائمًا استرداد قيمة engine.new_GuiInst ووضعه في التسجيل (انظر luaL_ref() والمناقشة في القسم 3.5 من دليل لوا المرجعي من الفهرس الزائف LUA_REGISTRYINDEX لمزيد من التفاصيل) لاستخدامها لاحقا.وبعد ذلك، قبل السماح بتشغيل أي رمز مستخدم، قم ببساطة بما يعادل engine.new_GuiInst = nil.يجب أن أشير إلى أنه بالنسبة لأنواع بيانات لغة C التي كنت ألعب بها مؤخرًا، أنشأت SWIG منشئين لكل نوع، باسم new_TYPE و TYPE.كان كلاهما مرئيًا في جدول الوحدة، وقد ترغب في تعيين كلا الاسمين لهما nil.إذا كانت لديك خبرة أقل بكثير في تغليف فئات C++ SWIG، فقد تختلف النتيجة...

قد ترغب في التحقق من محتوى الملف بالكامل ومراجعته engine تم إرجاع الجدول بواسطة SWIG، وقم بإنشاء كائن وكيل يحتوي فقط على الأساليب التي تريد توفيرها للمستخدمين.يمكنك أيضًا تغيير بيئة يراها البرنامج النصي للمستخدم بحيث يتوفر لديه الوكيل فقط، ويسمي الوكيل engine أيضًا.لقد كان هناك قدر لا بأس به من النقاش حول وضع الحماية البرامج النصية للمستخدم على قائمة لوا وفي مستخدمي لوا ويكي.

نصائح أخرى

أن تأتي متأخرًا خير من ألا تأتي أبدًا، وهذا الحل سيساعد الآخرين.

void handle_web_request(WebRequest *request, WebResponse *response)
{
  lua_getfield(rackam->lua_state, LUA_GLOBALSINDEX, "handle_web_request");
  SWIG_Lua_NewPointerObj(rackam->lua_state, request, SWIGTYPE_p_WebRequest, 0);
  SWIG_Lua_NewPointerObj(rackam->lua_state, response, SWIGTYPE_p_WebResponse, 0);
  lua_call(rackam->lua_state, 2, 0);
}

يجب أن يكون هذا الرمز داخل كتل %{}% في ملف .i الخاص بك، لأن SWIGTYPE_p_WebRequest هو

#define SWIGTYPE_p_WebResponse swig_types[6]

وswig_types[6] هو

static swig_type_info *swig_types[12];

مما يعني أنه لا يمكن الوصول إلى swig_types إلا من ملف C++ الذي تم تعريفه منه.

يرسل هذا المقتطف الخاص اثنين من المؤشرات المجمعة، لذا فإن استدعاء Handle_web_request(request, Response) من جانب C++ للأشياء سيؤدي إلى تشغيل وظيفة lua العامة "handle_web_request" وتمرير المؤشرين الخاص بي، مع تطبيق SWIG السحري.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top