사용자 도구

사이트 도구


kb:luabinaryextension

Lua Binary Extension

윈도우즈 환경 하에서 DLL 파일을 이용해, 루아 확장 모듈을 만드는 방법이다.

익스포트할 함수 만들기

일단 익스포트할 함수들을 만들어야 한다. 여기에서는 DirectoryTraversing을 위한 _findfirst, _findnext, _findclose 함수를 익스포트하기로 한다. (클로져를 사용하면 좀 더 깔끔하게 빠질 것 같지만, 일단은 패스.)

static int windows_find_first(lua_State* L)
{
    intptr_t ptr = -1;
    struct _finddata_t fileinfo = {0, };
 
    if ((ptr = _findfirst(luaL_checkstring(L, 1), &fileinfo)) == -1)
    {
        lua_pushnil(L);
        return 1;
    }
 
    lua_pushnumber(L, ptr);
    lua_pushstring(L, fileinfo.name);
    lua_pushboolean(L, (fileinfo.attrib & _A_SUBDIR) ? 1 : 0);
 
    return 3;
}
 
static int windows_find_next(lua_State* L)
{
    intptr_t ptr = -1;
    struct _finddata_t fileinfo;
 
    ptr = (intptr_t)luaL_checknumber(L, -1);
    if (_findnext(ptr, &fileinfo) != 0)
    {
        lua_pushnil(L);
        return 1;
    }
 
    lua_pushstring(L, fileinfo.name);
    lua_pushboolean(L, (fileinfo.attrib & _A_SUBDIR) ? 1 : 0);
 
    return 2;
}
 
static int windows_find_close(lua_State* L)
{
    _findclose((intptr_t)luaL_checknumber(L, -1));
    return 0;
}

패키지 등록 함수 만들기

DLL을 이용하는 경우에도, 다른 패키지와 마찬가지로 패키지 등록 함수가 있어야 한다. 다만 루아 쪽에서 이 함수를 호출할 수 있어야 하므로, __declspec(dllexport)를 붙여줘야 한다.

int __declspec(dllexport) luaopen_LuaExtension(lua_State* L)
{
    static const luaL_Reg windowslib[] = 
    {
        { "find_first", windows_find_first },
        { "find_next",  windows_find_next },
        { "find_close", windows_find_close },
        { NULL,         NULL }
    };
 
    luaL_register(L, "win", windowslib);
    return 0;
}

이 함수 이름은 약간 주의해야 하는데, luaopen_DLLNAME 형식으로 해줘야한다. 왜 그런지는 아래에서 설명한다. 위의 함수 4개를 빌드해서, LuaExtension.dll 파일을 만들었다고 하자. 이 파일을 패스로 등록된 어딘가에 복사한다.

루아에서 DLL 불러오기

2가지 방법이 있다.

첫번째는 package.loadlib 함수를 명시적으로 사용하는 방법이다.

libinit = package.loadlib("LuaExtension", "luaopen_LuaExtension")
libinit()

loadlib 함수의 첫번째 인자는 DLL 이름이고, 두번째 인자는 패키지 등록 함수의 이름이다. DLL을 무사히 로드한 경우, 패키지 등록 함수를 리턴한다. 리턴값으로 받은 함수를 호출해주면 패키지를 등록할 수 있다.

두번째는 그냥 require 구문을 이용하는 것이다.

require("LuaExtension")

사실 require 구문 안에서 첫번째 방법과 똑같은 과정이 이루어진다. 다만 패키지 등록 함수는 모듈 이름을 이용해 추정하게 되는데, 그 형식이 위에서도 잠깐 나온 것처럼 luaopen_DLLNAME 형식이다.

무사히 로드했다면, 이제 딱히 다른 패키지와 틀릴 것이 없다. 그냥 사용하면 된다. 아래의 예에서는 DLL 안의 DirectoryTraversing 함수를 이용해, 현재 디렉토리 안에 있는 모든 루아 파일들을 호출(require)하고 있다.

local ptr, name, is_dir = win.find_first(".\\*.lua")
if ptr then
    repeat
        if not is_dir then
            require(string.sub(name, 1, -5))
        end
        name, is_dir = win.find_next(ptr)
    until name == nil
    win.find_close(ptr)
end

kb/luabinaryextension.txt · 마지막으로 수정됨: 2014/11/06 16:43 (바깥 편집)