1. 개요

 

    이 문서는 ARM 보드에서 동작하는 C 프로그램이 루아 스크립트에 정의된 함수를
    호출하는 방법을 기술 합니다.
   
    lua_pcall 에서 에러 처리 함수를 지정하는 방법을 설명합니다.

    이 문서 구성은 동작 소스를 먼저 보여 주고 해당 소스에 대한 설명은 문서 뒤쪽에
    설명합니다.
   
    이 문서에는 다음과 같은 소스를 포함합니다.

    * 루아 스크립트 라이브러리를 포함하는 C 컴파일 용 Makefile
    * 루아 스크립트를 호출하고 값을 얻어 오는  C 샘플  main.c
    * 호출 되는 루아 스크립트 run.lua
   
2. 실습 구성

 

     다음과 같은 디렉토리 구성을 하였습니다.
    
     /project/lua/sample_lua_arm/lua_include    : LUA 헤더 파일 모음
     /project/lua/sample_lua_arm/lua_lib        : LUA 라이브러리 소스 모음
     /project/lua/sample_lua_arm/lua_samples    : 앞으로 진행할 강좌의 소스 들
    
3. 기본 샘플 구성

 

    소스는 다음 디렉토리에 위치 합니다.
    
     /project/lua/sample_lua_arm/lua_samples/070_lua_pcall_error
    
     이 디렉토리에는 다음과 같은 파일이 있습니다.
    
     Makefile
     main.c    
     run.lua
    
4. 소스들

 

Makefile

 

 CROSS_PREFIX = arm-linux
TARGET     = app_run_lua
TARGET_NFS = /nfs/lua
C_SRCS =
C_SRCS += main.c
LUA_SRCS = run.lua
# LUA Support  -- CORE 
C_SRCS += ../../lua_lib/lapi.c
C_SRCS += ../../lua_lib/lcode.c
C_SRCS += ../../lua_lib/ldebug.c
C_SRCS += ../../lua_lib/ldo.c
C_SRCS += ../../lua_lib/ldump.c
C_SRCS += ../../lua_lib/lfunc.c
C_SRCS += ../../lua_lib/lgc.c
C_SRCS += ../../lua_lib/llex.c
C_SRCS += ../../lua_lib/lmem.c
C_SRCS += ../../lua_lib/lobject.c
C_SRCS += ../../lua_lib/lopcodes.c
C_SRCS += ../../lua_lib/lparser.c
C_SRCS += ../../lua_lib/lstate.c
C_SRCS += ../../lua_lib/lstring.c
C_SRCS += ../../lua_lib/ltable.c
C_SRCS += ../../lua_lib/ltm.c
C_SRCS += ../../lua_lib/lundump.c
C_SRCS += ../../lua_lib/lvm.c
C_SRCS += ../../lua_lib/lzio.c
# LUA Support  -- LIB
C_SRCS += ../../lua_lib/lauxlib.c
C_SRCS += ../../lua_lib/lbaselib.c
C_SRCS += ../../lua_lib/ldblib.c
C_SRCS += ../../lua_lib/liolib.c
C_SRCS += ../../lua_lib/lmathlib.c
C_SRCS += ../../lua_lib/loslib.c
C_SRCS += ../../lua_lib/ltablib.c
C_SRCS += ../../lua_lib/lstrlib.c
C_SRCS += ../../lua_lib/loadlib.c
C_SRCS += ../../lua_lib/linit.c
INCLUDES += -I. 
INCLUDES += -I/usr/local/include
INCLUDES += -I/usr/$(CROSS_PREFIX)/include
INCLUDES += -I../../include
INCLUDES += -I../../lua_include
LDFLAGS += -L../../lua_lib/
LDFLAGS += -L/usr/$(CROSS_PREFIX)/lib
LIBS        = -lm
CFLAGS   += $(INCLUDES)
CFLAGS   += -Wall -O2 -g
ARFLAGS = rs
#---------------------------------------------------------------------
CC           = $(CROSS_PREFIX)-gcc
AR           = $(CROSS_PREFIX)-ar rc
AR2          = $(CROSS_PREFIX)-ranlib
RANLIB       = $(CROSS_PREFIX)-ranlib
LD           = $(CROSS_PREFIX)-ld
NM           = $(CROSS_PREFIX)-nm
STRIP        = $(CROSS_PREFIX)-strip
OBJCOPY      = $(CROSS_PREFIX)-objcopy
CP = cp
MV = mv
#--------------------------------------------------------------------
C_OBJS    = $(C_SRCS:%.c=%.o)
%.o:%.c
    @echo "Compiling $< ..."
    $(CC) -c $(CFLAGS) -o $@ $<
all :  $(TARGET) $(LUA_SRCS)
    cp $(TARGET) $(TARGET_NFS)
    cp $(LUA_SRCS) $(TARGET_NFS)
$(TARGET) : $(C_OBJS)
    $(CC) $(LDFLAGS) $(C_OBJS) -o $@ $(LIBS)
dep :
    $(CC) -M $(INCLUDES) $(C_SRCS) > .depend
clean:
    rm -f *.bak
    rm -f *.map
    rm -f *.o
    rm -f $(C_OBJS)
    rm -f $(TARGET) core
distclean: clean
    rm -rf .depend
ifeq (.depend,$(wildcard .depend))
include .depend
endif


run.lua --------------------------------------------------------------------------------

 

 print( "ENTER RUN.LUA" )
function sample_function( arg1, arg2 )
    print( "ENTER RUN.LUA - sample_function() " )
    print( ">>> Hello! I am lua function" )
    print( ">>> -- arg1 = ", arg1 );
    print( ">>> -- arg2 = ", arg2 );
    call_error();
    return arg1 + arg2
end
print( "END........." )

main.c --------------------------------------------------------------------------------

 

 #include <stdio.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#define LUA_FILENAME   "run.lua"
int main( int argc, char **argv ) 
{
    lua_State   *L = NULL;  
    int         error;
    int         int_value;
    char        *str_value;
    int         save_index;
    printf( "sample : C function call Lua Script \n" );
    L = luaL_newstate();                            
    luaL_openlibs(L);                               
    error =  luaL_loadfile( L, LUA_FILENAME )       
          || lua_pcall    ( L, 0,0,0    );          
    printf( "Enter C routine\n" );                  
    if( error )                                     
    {
        printf( "%s\n", lua_tostring(L,-1));    
        lua_pop(L,1);
        exit(0);
    }
    lua_getglobal( L,"sample_function" );   // <<-- (1)
    save_index = lua_gettop(L);             // <<-- (2)
    lua_getglobal(L, "_TRACEBACK");         // <<-- (3)
    lua_insert(L, save_index);              // <<-- (4)
    lua_pushnumber(L, 3);                   // <<-- (5) 
    lua_pushnumber(L, 4);                   // <<-- (6) 
    error = lua_pcall( L, 2,1,save_index ); // <<-- (7)
    printf( "Enter C routine\n" );                  
    if( error )                             // <<-- (8)
    {
        printf( "error running fuinction sample_function : %s", lua_tostring(L,-1));
        lua_pop(L,2);                       // <<-- (9)
    }
    else
    {
        str_value = lua_tostring(L,-1);     // <<-- (10)
        int_value = lua_tointeger(L,-1);    // <<-- (11)    
        printf( "return value 1 : [%s/%d]\n", str_value, int_value );
        
        lua_pop(L,2);                       // <<-- (12)    
    }   
    lua_close(L);                                   
    printf( "sample end\n" );                   
    return 0;
}

 

5 소스 설명

 

 (1) 루아 스크립트 함수 sample_function를 스택으로 복사해 옵니다.
 (2) 에러 함수를 루아 스크립트 함수 이전에 넣기 위해 현재 스택 인덱스를 얻어옵니다.
 (3) 내장된 루아 에러 처리 함수중 _TRACEBACK  이라는 함수를 스택 상위로 불러 옵니다.
 (4) 스택 가장 상위에 있는 함수를 sample_function 아래로 이동합니다.
 (5) lua_pushnumber() 함수를 이용하여 첫번째 매개변수를 스택에 넣습니다.
 (6) lua_pushnumber() 함수를 이용하여 두번째 매개변수를 스택에 넣습니다.
 (7) 스택에 옮겨진 함수를 호출합니다.
 (8) 에러가 발생하면 0 이 아닌값이 반환됩니다.
     이때  lua_pcall() 함수의 4번째 매계변수에 지정된 _TRACEBACK  이 호출된다.
     이 함수는 콜스택을 에러 메세지 문자열로 스택에 쌓는다.
 (9) 이때는 에러 함수처리 함수와 에러 메세지 스택에 있고
     이전에 전달된 함수와 매개변수는 모두 제거되므로
     스택 두개를 비우면 됩니다.
 (10) 반환된 첫번째 매개변수를 문자열로 구합니다.
 (11) 반환된 첫번째 매개변수를 숫자로 구합니다.
 (12) 반환된 결과 값과 에러 함수를 제거 합니다.

 

5.1 스택의 변화 설명

 

    각 단계별 스택의 상황을 표시하면 다음과 같습니다.
   
 (6) 단계를 거치면 다음과 같은 스택 상태가 됩니다.
 
        |                  |
        +------------------+
    4   |  4               | -1
        +------------------+
    3   |  3               | -2
        +------------------+
    2   |  sample_function | -3
        +------------------+
    1   |  _TRACEBACK      | -4
        +------------------+

 (8) 단계 상태(에러발생)이면 다음과 같은 스택 상태가 됩니다.

        |                  |
        +------------------+
    2   |  에러 메세지     | -1
        +------------------+
    1   |  _TRACEBACK      | -2
        +------------------+
       
 (10) 단계 상태이면 다음과 같은 스택 상태가 됩니다.


        |                  |
        +------------------+
    2   |  7               | -1
        +------------------+
    1   |  _TRACEBACK      | -2
        +------------------+

 

6. 결론

 

    루아 스크립트의 함수 호출 처리중 에러에 대한 처리를 정의 하려면
   
    1)  lua_getglobal() 함수를 이용하여 스택 꼭대기로 함수를 복사합니다.
    2)  스택 꼭대기에 있는 함수를 호출할 함수 아래로 이동 시킵니다.
    3)  호출 후에 에러 함수는 스택에서 제거가 되지 않으므로
        이를 고려해서 스택을 제거해야 합니다.

 

7 수행 예

 

 다음은 보드에서 수행한 예 입니다.
 
[root@falinux nfs]$ ./app_run_lua
sample : C function call Lua Script
ENTER RUN.LUA
END.........
Enter C routine
ENTER RUN.LUA - sample_function()
>>> Hello! I am lua function
>>> -- arg1 =   3
>>> -- arg2 =   4
Enter C routine
error running fuinction sample_function : run.lua:9: attempt to call global 'call_error' (a nil value)sample end
[root@falinux nfs]$