ARM 보드에서 루아 이용 - 루아 스크립트에서 정의된 함수 호출 2

 C000_lua.gif

1. 개요

 

    이 문서는 ARM 보드에서 동작하는 C 프로그램이 루아 스크립트에 정의된 함수를
    호출하는 방법을 기술 합니다.
   
    이번은 루아 스크립트 함수에 매개변수를 전달하고
    결과 값을 가져 오는 스크립트를 설명합니다.
   
    이 문서 구성은 소스를 보여주고 해당 소스에 대한 설명은 문서 뒤쪽에
    설명합니다.
   
    이 문서에서는 다음과 같은 소스를 포함합니다.

    * 루아 스크립트 라이브러리를 포함하는 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/060_call_function_from_script_2
    
     이 디렉토리에는 다음과 같은 파일이 있습니다.
    
     Makefile
     main.c    
     run.lua
    
4. 소스들

Makefile

 

 
# CROSS_PREFIX = arm-linux
CROSS_PREFIX = mingw32
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 );
    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;
    
    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)
    lua_pushnumber(L, 3);                   // <<-- (2)
    lua_pushnumber(L, 4);                   // <<-- (3) 
    error = lua_pcall( L, 2,2,0 );          // <<-- (4)
    printf( "Enter C routine\n" );                  
    if( error )                             // <<-- (5)
    {
        printf( "error running fuinction sample_function : %s", lua_tostring(L,-1));
        lua_pop(L,1);                       // <<-- (6)
    }
    else
    {
        str_value = lua_tostring(L,-2);     // <<-- (7)
        int_value = lua_tointeger(L,-2);    // <<-- (8) 
        printf( "return value 1 : [%s/%d]\n", str_value, int_value );
        str_value = lua_tostring(L,-1);     // <<-- (9) 
        printf( "return value 2 : %s\n", str_value );
        
        lua_pop(L,2);                       // <<-- (10)    
    }   
    
    lua_close(L);                                   
    
    printf( "sample end\n" );                   
    return 0;
}
 


 

5 소스 설명

 

 (1) 루아 스크립트 함수 sample_function를 스택으로 복사해 옵니다.
 (2) lua_pushnumber() 함수를 이용하여 첫번째 매개변수를 스택에 넣습니다.
 (3) lua_pushnumber() 함수를 이용하여 두번째 매개변수를 스택에 넣습니다.
 (4) 스택에 옮겨진 함수를 호출합니다.
 
   이 예제는 반환값은 두개를 요구 했고 실제로 반환은 한개만
      발생했을때의 예 입니다.
      
 (5) 에러가 발생하면 0 이 아닌값이 반환됩니다.
 (6) 에러는 에러 메세지 한개가 스택에 쌓이고
     이전에 전달된 함수와 매개변수는 모두 제거되므로
     스택 한나만 비우면 됩니다.
 (7) 반환된 첫번째 매개변수를 문자열로 구합니다.
 (8) 반환된 첫번째 매개변수를 숫자로 구합니다.
 (9) 반환된 두번째 매개변수를 표출 합니다.
      문자열로 구한것은 반환값 갯수는 2개로 했는데
      반환은 1개만 했을경우 돌려지는 값이 어떤것인가를 보여 주기 위한 것입니다.
 (8) 반환된 결과값을 스택에서 제거 합니다.

 

5.1 스택의 변화 설명

 

    각 단계별 스택의 상황을 표시하면 다음과 같습니다.
   
 (3) 단계를 거치면 다음과 같은 스택 상태가 됩니다. 

 
        |                  |
        +------------------+
    3   |  4               | -1
        +------------------+
    2   |  3               | -2
        +------------------+
    1   |  sample_function | -3
        +------------------+


 

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

 

         |                  |
        +------------------+
    1   |  에러 메세지     | -1 
        +------------------+ 


        
 (7) 단계 상태이면 다음과 같은 스택 상태가 됩니다.

 

         |                  |
        +------------------+
    1   |  null            | -1 
        +------------------+
    0   |  7               | -2 
        +------------------+


 

6. 결론

 

    루아 스크립트에 선언된 함수에 메개변수를 전달하고 반환값을 받을 때는
   
    1)  lua_getglobal() 함수를 이용하여 스택으로 값을 복사합니다.
    2)  lua_pushXXX() 함수 계열을 이용하여 파라메터를 스택으로 복사 합니다. 
    3)  lua_pcall() 함수를 이용하여 호출합니다.
    4)  반환된 값은 스택에 있고 전달된 함수와 데이터는 스택에서 제거 됩니다.


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
return value 1 : [7/7]
return value 2 : (null)
sample end
[root@falinux nfs]$