SWIG로 감싸는 C ++ 클래스의 인스턴스를 LUA 스택에 어떻게 밀어 넣으려면?

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

  •  03-07-2019
  •  | 
  •  

문제

나는 SWIG로 싸서 LUA에 등록 된 수업이 있습니다. LUA 스크립트 에서이 클래스의 인스턴스를 만들 수 있으며 모두 잘 작동합니다.

그러나 새로운 X에 대한 호출로 C ++ 코드에 작성된 클래스 인스턴스가 있다고 말하면서 전화하고 싶은 함수가있는 la lua_state l이 있습니다. 그 기능을 어떻게 호출합니까? 다음은 해당 코드의 (일부)입니다 (오류 처리 사항을 생략했습니다).

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

현재 내가 찾은 것은 SWIG 생성 된 CPP 파일에서 일부 기능을 노출시키고 호출하는 것입니다. 이것은 몇 가지 이유가 나쁘다 ... 여러 개의 모드가 있고 SWIG 파일에서 기본 링크 사양을 변경 해야하는 경우 작동하지 않습니다 (-dswightuntime =).

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);

모듈에 대한 포인터를 얻은 다음 유형에 대한 포인터를 얻은 다음 SWIG 기능을 호출하여 등록합니다. 인간을 읽을 수없는 파일을 파헤쳐 야하는 것은 불합리한 일이었습니다 (파일의 상단에 표시됩니다). (하지만 작동합니다!)

분명히 내가하려는 일을 성취하는 더 좋은 방법이 있습니다.

추신 높은 수준의 POV에서 내가 원하는 것은 LUA가 Guiinst의 Object Factory에서 만든 GUI 구성 요소를 refcount하지 않도록하는 것입니다. 이것은 매우 간단한 (그리고 비 스펙터) 파이썬 모듈과는 별도로 기능을 스크립팅 언어에 노출시키는 것은 이번이 처음이므로 조언을받을 준비가되어 있습니다.

조언에 감사드립니다!


Rberteig의 의견에 대한 응답

Guiinst의 회의자는 SWIG가 실행될 때 LUA가 인스턴스를 구성하는 것을 방지하기 위해 비공개로 정의되어 있으므로 저에게는 효과가 없습니다. 내가 예방하려고했던 것은 다음과 같습니다 (LUA).

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

"G = New Guibitton"이라고 부르면 GuiregionVertical (여러 가지 이유로 포인터를 저장해야 함)에 등록한 다음 "Delete G"를 호출하면 GuiregionVertical은 G에 매달려있는 포인터가 남아 있습니다.

실제로 일어나야 할 것은 Guiregionvertical :: Add (Guibitton*)가 Guibitton*의 심판 수를 늘려야한다는 것입니다. 그런 다음 Guiregionvertical의 파괴자는 모든 내용의 refcounts를 감소시켜야합니다. SWIG로 완료하십시오.

이는 개인 생성자, GUI 오브젝트 공장 및 불쾌한 외부의 필요성을 제거합니다.

내가 이것을 잘못하고 있습니까?

감사.

도움이 되었습니까?

해결책

단순하고 직접적인 답변이 있으며 가장 효율적인 답변이 아닐 수도 있습니다. 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 ()을 통해 문자열 상수를 실행 한 페널티는 전혀 나쁘지 않습니다. 그러나 이벤트 콜백 또는 내부 루프에서는 피하기가 더 어려워 보입니다.

포인터를 포장 된 물체로 직접 변환하는 방법이 있어야하는 것처럼 보입니다.

편집하다: 물론 LUA 조각은 스택에 엔진 테이블을 전 세계적으로 가져 오는 API 호출로 분해 될 수 있습니다. new_GuiInst 회원에게 전화 한 다음 글로벌에 전화하십시오 Init, 그러나 약간의 효율성은 명확성의 비용으로 발생합니다.

명확한 질문에서 알 수 있듯이 사용자 코드로 우연히 구축해서는 안되는 개체를 다루는 것은 SWIG가 생성자 함수를 생성하고 나중에 필요한 경우 개인 참조를 유지하고 테이블에서 제거하는 것입니다. . C 모듈조차도 (일반적으로) 멤버가 함수 값을 포함하는 테이블 일뿐입니다. 추가 노력을 기울이지 않는 한 C로 구현된다고해서 읽기 전용은 아닙니다.

따라서 항상 값을 검색 할 수 있습니다 engine.new_GuiInst 레지스트리에 주차하십시오 (참조 luaL_ref() 그리고 토론 LUA 참조 매뉴얼의 섹션 3.5 의사-인덱스의 LUA_REGISTRYINDEX 자세한 내용) 나중에 사용합니다. 그런 다음 사용자 코드를 실행하게하기 전에 engine.new_GuiInst = nil. 가장 최근에 플레이 한 C 데이터 유형의 경우 Swig는 각 유형에 대해 두 개의 생성자를 만들었습니다. new_TYPE 그리고 TYPE. 둘 다 모듈 테이블에서 볼 수 있었으며 두 이름을 모두 nil. SWIG 포장 C ++ 클래스에 대한 경험이 훨씬 적고 결과가 다를 수 있습니다 ...

전체 내용을 확인하고 검토하고 싶을 수도 있습니다. engine SWIG에 의해 반환 된 테이블은 사용자가 사용할 수있는 메소드 만 포함 된 프록시 객체를 만듭니다. 당신은 또한 변경할 수 있습니다 환경 프록시 만 사용할 수 있도록 사용자 스크립트에서 볼 수 있고 프록시의 이름을 지정합니다. engine 또한. 상당한 논의가있었습니다 샌드 박스 사용자 스크립트 LUA 목록 그리고 Lua-users Wiki.

다른 팁

늦지 않는 것이 좋지 않으며이 솔루션은 다른 사람들에게 도움이 될 것입니다.

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);
}

이 코드는 swigtype_p_webrequest이기 때문에 .i 파일의 % {} % 블록 내부에 있어야합니다.

#define SWIGTYPE_p_WebResponse swig_types[6]

그리고 swig_types [6]는

static swig_type_info *swig_types[12];

즉, SWIG_TYPES는 정의 된 C ++ 파일에서만 액세스 할 수 있습니다.

이 특정 스 니펫은 내 래퍼 된 포인터 중 두 개를 보내므로 C ++ 측면에서 hone_web_request (요청, 응답)를 호출하면 글로벌 LUA 기능 "handle_web_request"가 실행되고 Swig 마법이 적용된 두 포인터를 전달합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top