E D R S I H C RSS
ID
Password
Join
책속에서 편안하다. --김우재



Contents

1 C와 Lua의 공존
1.1 질문
1.1.1 답변
1.2 질문
1.2.1 답변
2 예제
2.1 질문
2.1.1 답변
2.2 질문
2.2.1 답변
2.3 질문
2.3.1 답변
2.4 질문
2.4.1 답변
3 변수 참조
3.1 질문
3.1.1 답변
4 Lua 포팅
4.1 답변
4.2 답변 2
4.3 답변에 대한 답변
4.3.1 답변에 대한 답변에 대한 답변
4.3.1.1 그리고 또 거기에 대한 답변
5 잡담
5.1 질문
5.1.1 답변
5.2 질문
5.2.1 답변

1 C와 Lua의 공존 #

1.1 질문 #

일단 제일 헷갈리는 부분이, "C와 Lua쏘스가 어떻게 공존하는가"입니다. 그러니깐 ctest.c 에서 luatest.lua 의 함수 luafunction() 을 호출한다고 할 때, luatest.lua 는 luac 를 사용해서 오브젝트로 만든 후, ctest.c 를 컴파일해서 만든 오브젝트와 link를 시켜서 하나의 실행파일로 만들 수 있는 것인가요? 아니면 그냥 luac를 사용해서 일종의 메타파일을 만든 후에 ctest.c 에 인터프리터를 포함시켜서 메타파일을 읽어서 실행시키는 건가요? 그것도 아니라면 luatest.lua 그 자체로서 배포가 되어서 ctest.c 에 포함된 인터프리터가 실행시키는 건가요?

1.1.1 답변 #

간단히 말하면 위 방법 중 링크빼고 모두 됩니다. :) 거기다 덧붙이자면, 굳이 text화일의 형태로 별도로 보관하지 않아도 됩니다. (메모리상의 char * 변수에 담긴 lua소스도 실행할 수 있으니까요. :) 제가 손보고 있는 게임 엔진에서는 luac를 사용하지 않고 별도의 dat화일을 만들어 거기에 모두 모아놓는 형태입니다. 즉, text로만 존재하면 어떠한 형태로도 공존이 가능하죠. 루아는 별도의 랭귀지 이므로 원칙적으로는 호스트 프로그램과는 독립되어있습니다.

1.2 질문 #

그렇다면, 컴파일을 거친 외부의 파일 (예를 들어 luatest.out)을 C쏘스에게 알려주려면 어떻게 해야 하나요? 파일을 메모리에 올려두는 함수가 있는건가요? 아니면 따로 만들어야하나요?

1.2.1 답변 #

화일을 읽어오는 함수가 있습니다. luaL_dofile()/luaL_dobuffer()가 그런 역할을 하죠. 아래 소스를 참조하시길...

2 예제 #

2.1 질문 #

아주 간단히, c에서 lua를 호출하는 예제를 보여주셨으면 합니다. 예를 들어 test.lua 가
-- luatest.lua
function luafunction(num1, num2)
   return num1 + num2
end
와 같다고 한다면, luafunction을 c에서 어떻게 호출해야 하는지요?

2.1.1 답변 #

위 함수를 호출하는 예제는 다음과 같습니다. C 소스입니다.
lua_State *L;
lua_pushstring(L, "luafunction");
lua_rawget(L, LUA_GLOBALSINDEX); // "luafunction"을 얻어와 스택의 맨위에 놓습니다.
lua_pushnumber(L, 100);    // 첫번째 인자
lua_pushnumber(L, 200);    // 두번째 인자
lua_call(L, 2, 1);         // "luafunction"에 2개의 인자를 가지고 실행한 후 그 결과를 스택의 최상단에 놓는다.
printf("결과값 : %d\n", lua_tonumber(L, -1));  // 스택의 맨윗값을 얻어 화면에 출력

2.2 질문 #

LUA_GLOBALSINDEX 는 어디서 어떻게 정의되는 매크로인가요?

2.2.1 답변 #

lua.h에 보시면 선언되어있습니다. 전역 변수들을 담아놓는 테이블을 의미합니다.

2.3 질문 #

그냥
#include <stdio.h>
#include "lua.h"

void main(void)
{
	lua_State *L; 
	
	lua_pushstring(L, "luafunction"); 
//	lua_rawget(L, LUA_GLOBALSINDEX); // "luafunction"을 얻어와 스택의 맨위에 놓습니다. 
	lua_pushnumber(L, 100);    // 첫번째 인자 
	lua_pushnumber(L, 200);    // 두번째 인자 
	lua_call(L, 2, 1);         // "luafunction"에 2개의 인자를 가지고 실행한 후 그 결과를 스택의 최상단에 놓는다. 
	printf("결과값 : %d\n", lua_tonumber(L, -1));  // 스택의 맨윗값을 얻어 화면에 출력 
}
와 같이 했는데, (당연히) 안 됩니다 --; luafunction의 내용을 c에 알려줘야할 것 같은데..;

2.3.1 답변 #

풀소스를 요구하시는 군요. 다음을 실행시켜보시길...
#include <stdio.h> 
#include "lua.h" 
#include "lualib.h" 
#include "lauxlib.h" 
 
// 현재 스택의 상태를 출력해줍니다.  
void printstackstatus(lua_State *L) 
{ 
        printf("(top:%d)", lua_gettop(L)); 
        for (int i = 1; i <= lua_gettop(L); i++)  
        { 
                switch(lua_type(L, i)) 
                { 
                case LUA_TTABLE : 
                case LUA_TNIL :  
                case LUA_TFUNCTION : 
                case LUA_TUSERDATA : 
                case LUA_TTHREAD : 
                case LUA_TBOOLEAN : 
                        printf("(%d:%s)%d ", i, lua_typename(L, lua_type(L, i)), lua_toboolean(L, i)); break; 
                case LUA_TLIGHTUSERDATA : 
                        printf("(%d:%s) ", i, lua_typename(L, lua_type(L, i))); break; 
                case LUA_TNUMBER : 
                        printf("(%d:%s)%d ", i, lua_typename(L, lua_type(L, i)), (int)lua_tonumber(L, i)); break; 
                case LUA_TSTRING : 
                        printf("(%d:%s)%s ", i, lua_typename(L, lua_type(L, i)), lua_tostring(L, i)); break; 
                } 
        } 
        printf("\n"); 
} 
 
int main(int argc, char *argv[]) 
{ 
        lua_State *L = lua_open(); // 루아 state를 생성한다. 
 
        lua_baselibopen(L); // print 루아 함수때문에 실행합니다. 나머지는 실행하면 스택만 길어지므로 빼주시길... 
        /*lua_tablibopen (L); 
        lua_iolibopen (L); 
        lua_strlibopen (L); 
        lua_mathlibopen (L); 
        lua_dblibopen (L);*/ 
 
        // luatest.lua 를 로드해서 실행한다. (5.0 beta에서만 됩니다. alpha에서는 에러! 버그였는데 해결된거더군요.) 
        lua_dofile (L, "luatest.lua"); 
 
        // "print(func1(100, 20))" 문장을 실행한다. 
        char tmpluacode[] = "print(func1(100, 20))"; 
        lua_dobuffer(L, tmpluacode, strlen(tmpluacode), "_temp"); 
 
        // 함수를 C레벨에서 호출한다. 
        lua_getglobal(L, "func2"); // "func1"을 얻어와 스택의 맨위에 놓습니다. 
        printstackstatus(L); 
        lua_pushnumber(L, 100);    // 첫번째 인자 
        lua_pushnumber(L, 200);    // 두번째 인자 
        printstackstatus(L); 
        lua_call(L, 2, 1);         // "func1"에 2개의 인자를 가지고 실행한 후 그 결과를 스택의 최상단에 놓는다. 
        printstackstatus(L); 
 
        lua_close(L); // 루아 state를 해제한다. 
        return 0; 
} 
lua_tonumber() 앞에 int로 캐스팅을 해주어야 하는군요. 알고 있던건데 항상 잊어먹습니다. :(

2.4 질문 #

lua 4.0.1에선 lua_pcall이 없어서 lua_call(L, 2, 1)을 해 줬는데요, 실행은 되는 것 같은데 리턴값을 못 얻어옵니다.

C에선
        lua_State *L = lua_open(0); // 루아 state를 생성한다. 4.0.1 에는 lua_open() 하면 안 되더군요.
        lua_baselibopen(L);
        lua_dofile (L, "luatest.lua"); 
        //lua_rawget(L, LUA_GLOBALSINDEX); // 4.0.1 에는 LUA_GLOBALSINDEX이 정의가 안 되어있더군요..

        // 함수를 C레벨에서 호출한다. 
        lua_getglobal(L, "luafunction"); // "luafunction"을 얻어와 스택의 맨위에 놓습니다. 
        lua_pushnumber(L, 100);    // 첫번째 인자 
        lua_pushnumber(L, 200);    // 두번째 인자 
        lua_call(L, 2, 1); 
        printf("결과값 : %d\n", lua_tonumber(L, -1));

        lua_close(L); 
와 같이 했고, lua에선
-- luatest.lua 
function luafunction(num1, num2) 
   print ("num1=".. num1)
   print ("num2=".. num2)
   return (num1 + num2) 
end 
로 했습니다. 결과는
num1=100
num2=200
결과값 : 0
이렇게 나옵니다 -_-

리턴값을 얻어오려면 어떻게 해야 할까요?

2.4.1 답변 #

printf("결과값 : %d\n", lua_tonumber(L, -1));
printf("결과값 : %d\n", (int)lua_tonumber(L, -1));
로 고치시면 됩니다.

3 변수 참조 #

3.1 질문 #

lua의 변수를 c에서 어떻게 참조하는지, 거꾸로 c의 변수를 lua에선 어떻게 참조하는지 궁금합니다.

3.1.1 답변 #

lua->C 는 테이블내의 변수인지, 전역변수인지에 따라 다릅니다. 전역변수도 "전역테이블"에서 꺼내온다고 생각하시면 됩니다.
lua_pushstring(L, "변수명");
lua_rawget(L, LUA_GLOBALSINDEX);   // "변수명"에 해당되는 전역변수의 값을 얻어온다.
위처럼 하신 후에 lua_to...() 함수들을 써서 스택의 맨위에서 뽑아내면 됩니다.

C->lua 는 특정 함수를 작성해서 루아내에서 실행반환값으로 얻어내는 것이 최고입니다. (경험적인 생각) 예를 들어, 다음의 함수는 lua상에서 C 프로그램상의 문자열을 구하는 함수입니다.
char sampletext[] = "redpixel바보!";
int gettext(lua_State *L)
{
   lua_pushstring(L, sampletext);
   return 1;   // 반환값이 1개라는 의미입니다.
}
그다음 위 gettext() 함수를 등록해야합니다. 다음과 같이 합니다.
lua_pushcfunction(L, gettext);
lua_setglobal(L, "gettext");
이제 루아상에서는 다음과 같이 실행합니다.
a = gettext()
print(a)
아마도 "redpixel바보!"라고 찍힐거라 생각됩니다. :)

4 Lua 포팅 #

Lua를, gp32로 포팅하려고 하고 있는데요, 일단 라이브를 ads로 컴파일하는데 성공했고, c에서 lua_dobuffer로 실행을 시도해봤는데, 제대로 안 되는군요. Lua 변수참조를 해 보는 것과 Lua에서 C함수를 호출하는 걸 테스트해 봤는데, 윈도즈 환경에서 테스트해보면 잘 되는 것이 gp32 기계에 올리면 제대로 안 나옵니다. 문제는.. Lua 호출에 필요한 여러 함수들 중 어디에서 문제가 생기는지 알 길이 없다는 것입니다-_-

뭔가 아이디어가 없을까요? --파연

4.1 답변 #

저도 나중에 시도해보고 싶었던 것인데.. :) 수고하시네요. 어쨌든 저도 루아의 전체 소스를 훑어본 적이 없는지라 정확히 말씀드리기 어렵지만, 표준 C 함수들과 화일 입출력, 메모리 할당 함수들을 모두 gp32용으로 변환해야한다고 생각됩니다. (정말 노가다가 되지 않을까 생각되네요... :| ) gp32 SDK를 보니 C 언어를 사용하는 것 뿐이지, 표준 C 함수들을 지원하는 것 같아보이진 않더군요. 특히 메모리 할당함수부분이 아마도 gp32 API로 바뀌어야 할 듯 하네요.

gcc로 하시나요? 저도 호기심에 아샬님 홈피에서 가져다가 해봤습니다만 꽤 흥미로운 기계라 생각됩니다. 저와 같이 일하는 그래픽 디자이너(동생)이 관심을 많이 보이더군요. :)

몇가지 저도 해보고 연락드리겠습니다. 아참, 홈피가 바뀌신 것 같던데...-_-;

4.2 답변 2 #

일단 메모리부분만 찾아보았습니다. 루아 소스중 lmem.c라는 화일에서 다음부분을 찾아보세요.
/*
** definition for realloc function. It must assure that l_realloc(NULL,
** 0, x) allocates a new block (ANSI C assures that). (`os' is the old
** block size; some allocators may use that.)
*/
#ifndef l_realloc
#define l_realloc(b,os,s)	realloc(b,s)
#endif

/*
** definition for free function. (`os' is the old block size; some
** allocators may use that.)
*/
#ifndef l_free
#define l_free(b,os)	free(b)
#endif
처음부분이니깐 쉽게 찾을 수 있으실 겁니다. 이 부분을 구조화하는 방법은 두가지가 있을 듯 한데요.
  1. gp32 API 중 gp_mem_func 전역 구조체안의 메모리 할당/해제용 함수포인터들로 대체하면 될 듯 합니다. (realloc()이 없다는 것이 조금 걸립니다만, free->malloc하면 되지 않을까합니다)
  2. gp32 API 중 malloc_ex()/free_ex()/make_mem_partition() 함수를 사용하여 루아 state가 시작하기 전 미리 메모리를 확보해두고, 따로 realloc()에 대한 함수를 직접 작성해서 메모리관리를 하는 방법도 있겠네요.

물론 실험해보지 않아 무책임(?)한 답변입니다. :) 파연님이 실험해 주실거라 믿습니다. :)

4.3 답변에 대한 답변 #

realloc 은.. 사실 free - malloc 뿐만 아니라 원래 메모리의 내용까지 옮겨야하는 문제가 있습니다. 저 주위를 조금 더 뒤져보면 malloc_debug 씨리즈들이 있는데, 그걸 그냥 그대로 사용했습니다.

표준함수에 대한 포팅은.. 반 정도 하고 반 정도 남은 상태에서 중지상태입니다-_- 위에 말씀하신 문제 외에도, lua는 내부에서 double 형으로 연산이 일어나고, gp32에는 double 형 연산이 없다는 문제도 있습니다. (ads를 사용하면 소프트웨어로 에뮬레이션해주는 듯 한데, 제대로 되지 않거나 되어도 느려터진..) long 형으로 다 바꿔봤지만 제대로 되지 않는 상태구요 -_-

테스트용 루아루틴이 제대로 동작하지 않는데, 무엇보다도 어디서부터 문제가 있는지를 확인할 수 있는 길이 없다는 것이 가장 문제입니다. 어디가 문제인지 알아야 고치든지 말든지 할텐데...;;

이래저래 현재는 Lua 포팅을 중단한 상태입니다. --; 뚜렷한 아이디어가 떠오르기 전까지는 말이죠 (그러나 영원히 안 떠오를 것 같은 불길한 예감이...;;; )

그런 것입니다. 쿨럭. --파연

4.3.1 답변에 대한 답변에 대한 답변 #

그렇게 된 것이군요. 수고하셨습니다. 하지만 한가지 더 미련을 가지게 해드리자면, 루아는 꼭 double을 기본으로 사용하지는 않습니다 :) lua.h화일에서,
/* type of numbers in Lua */
#ifndef LUA_NUMBER
typedef double lua_Number;
#else
typedef LUA_NUMBER lua_Number;
#endif
이 부분을 int로 고치고 해보면 되지 않을까요? :) 물론 루아상의 math 라이브러리는 사용하지 못하게 되겠지만, 어짜피 별도의 패키지로 작성해야하는 부분이니까요.

-- redpixel

4.3.1.1 그리고 또 거기에 대한 답변 #

그 부분을 건드렸던 것인데, 사실 typedef 한 줄만 고치는걸로는 해결 안 됩니다. 여기저기 손 볼 것이 있죠; 뭐 그건 그다지 어려운 것은 아니고.. 어째튼 그런 것입니다 - -;

Lua는 윈도우즈 겜 만들때 활용해볼 요량을 하고 있습니다. --파연

5 잡담 #

5.1 질문 #

제대로 공부를 안 해보고 질문드리는 거라, 좀 한심한 질문인지 모르겠습니다-_- 하지만 lua 메뉴얼은 너무 설명이 빈약한 것 같아요 ㅠㅠ

5.1.1 답변 #

별말씀을... 메뉴얼 설명 괜찮습니다. 예제가 빈약하다는 표현이 맞겠네요. 저처럼 몇번 삽질해보시면 의외로 구조가 간단하다라는 것을 아실 수 있을겁니다. 전 개인적으로 python 붙이는 거보다는 쉽다고 생각되는데요. :) 그리고 처음 연습하시는 거라면 lua 인터프리터 소스를 분석해보세요. test 디렉토리에 보시면 각종 예제가 있는데 그것을 분석해보셔도 됩니다.

5.2 질문 #

감사합니다.. --파연

5.2.1 답변 #

별말씀을... 즐거운 년말 되시길... --redpixel

a.lua라는 파일에 있는 function을 b.lua라는 파일에서 사용할려면 어떤 방식으로 하면 될가요? -- 아리스 2005-09-26

자답 > 너무 간단해서 답변 dofile(파일명) 형태로 하면 되었었군요..
안에 있는 function명을 적어주기만 하면 끝..

이걸 끝내니 또다시 떠오른 생각이 a:b:c() 이런식의 호출이 가능할까? 라는 =ㅁ=; -- 아리스 2005-09-28

불가능합니다. -_-; a.b:c()라는 형태는 가능합니다. :이라는 기호는 .메소드명(self,..)의 줄임이기 때문이죠. -- redpixel 2005-09-29

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2010-10-28 12:42:52
Processing time 0.5155 sec