1. 개요

 

    이 문서는 루아 인터프린터에서 사용할 수 있는 모듈을
    리눅스 C 공유 라이브러로 제작하여 사용하는 방법을 기록한 문서이다.

 

2. 시리얼 모듈을 만들기 위한 기술 검토

 

    이전 설계 방침에 따르면 다음과 같은 형식으로 시리얼 모듈의 함수들이 실행될 수 있어야 한다.
   
        m = require "serial";
        m.port_list();
        m.create();
        m = nil;

 

    이 루아 스크립트는 serial.so 공유 라이브러리를 읽어 들이고
    m 을 모듈변수로 할당한다.
   
    이 m 모듈 변수를 이용하여 port_list()  함수와 create() 함수가 포함되어 있다.
   
    이 모듈에 포함된 함수를 사용하려면
   
      m.port_list();
     
    와 같은 형태로 호출 하면 된다.
   
    모듈 사용이 모두 끝나 더 이상의 사용을 하지 않는다면
    m 모듈 변수에 nil 을 대입하면 된다.
   
   
3. 루아 스크립트를 자동으로 수행하기 위한 방법

 

    위 스크립트 이름이 run.lua 라고 한다면
   
    명령 라인에 다음과 같이 입력해야 한다.
   
        ./lua run.lua
   
    매번 이렇게 입력하는 것은 매우 불편하다.
   
    그래서 루아 스크립트의 첫줄을 다음과 같이 고치면
    편하다.
   
        #!/mnt/nfs/lua/lua
   
    여기서 /mnt/nfs/lua/lua 은 실제로 lua 인터프린터가
    있는 위치를 나타낸다.
    자신의 환겨에 맞게 적절히 수정하면 된다.
   
    또 한가지 주의 할점은 윈도우에서 루아 스크립트를 만들면
    마지막에 ^M 문자가 추가되어 리눅스에서는 실행되지 않는다.
   
    리눅스에서 초기 파일을 만들던가
    또는 윈도우에서 만든후 ^M 문자를 제거해 주어야 한다.
   
3.1 테스트용 루아 스크립트

 

    이 강좌를 진행하기 위해서 시험해야 하는 루아 스크립트는 다음과 같다.
   
    #!/mnt/nfs/lua/lua
    print "START TEST LUA"
   
    m = require "serial";
    m.port_list();
    m.create();
    m = nil;
   
4. C 모듈을 만들기 위한 Makefile

 

    C 루아 모듈은 실제로 공유 라이브러리를 만드는 과정이다.
   
    serial.so 라는 공유 라이브러리는 루아에서 C 모듈이 된다.
   
    원 소스가 serial.c 라면 다음과 같은 컴파일 과정을 거치게 된다.
   
    arm-linux-gcc -c \
            -I.  \
            -I/usr/local/include \
            -I/usr/arm-linux/include \
            -I../include \
            -I../../lua_include \
            -Wall -O2 -g \
            -DLUA_USE_LINUX \
            -o serial.o serial.c   
           
    이 과정은  serial.c 를 컴파일 하여 오브젝트를 생성하는 과정인데

    리눅스에서 수행되기 위해서
           
       -DLUA_USE_LINUX
    
     를 포함해야 하는 점과 컴파일 하기 위해서 필요한 헤더파일 디렉토리를
     지정하는 부분만 주의 한다면 특별한 것이 없다.       
    
    arm-linux-gcc \
            -L./ \
            -L../../lua_lib/ \
            -L/usr/arm-linux/lib \
            -shared -Wl,-soname,serial.so \
            serial.o -o serial.so \
            -lm -ldl -llua

    실제로 공유 라이브러리인 srial.o 를 만드는 과정인데
   
    이 과정에서 다른 라이브러리들이 이미 컴파일 된
    디렉토리를 지정하는 것과
   
    공유 라이브러리 생성을 위한 옵션
   
       -shared -Wl,-soname,serial.so
      
   을 지정해야 한다.
  
   또한 생성될 공유 라이브러리가 참조할 다른 공유 라이브러리를    
   지정하는 옵션인
  
    -lm -ldl -llua

   를 포함하여야 한다.
   
5. C 모듈의 구성

 

    C 모듈이 루아 스크립트에서 사용되려면 몇 가지 규칙을
    가지고 작성되어야 한다.
   
    우선 "serial"  이라는 시리얼을 다루는 모듈이 있다고
    가정하자.
   
    이 루틴은 루아 스크립트에서 다음과 같은 형식으로
    모듈로써 등록된다.
   
        m = require "serial";
   
    이 require() 함수는 결론적으로  serial.so 를 찾게 된다.
   
    즉 C 모듈 함수이름은  serial.so  라는 이름을 가져야 한다는
    것이다.
   
    이 공유 라이브러리는 LUA 인터프린터에 의해서 읽혀진다.
    LUA 인터프린터는 serial 라이브러리에서 초기 호출 함수를
    찾는다. 이때 호출되는 함수 이름은 다음과 같은 형식이어야 한다.
   
        LUALIB_API int luaopen_xxx( lua_State *L );
       
    여기서 xxx 는 모듈 이름인 "serial " 대치되어
       
        luaopen_serial()
       
    라는 함수를 호출한다.
   
    즉  serial.c 에는 다음과 같은 형태의
    함수가 반드시 존재 해야 한다.
   
    LUALIB_API int luaopen_serial( lua_State *L )
    {
        return 1;
    }

   
    이 함수에서 해야 하는 일은
    모듈에 포함되는 함수를 모듈 구조체를 통하여 등록해야 한다.
   
    모듈에 포함되는 함수는
   
        struct luaL_Reg
       
    구조체 변수를 통하여 정의하고
   
        luaL_register()
       
    함수를 통하여 등록된다.
   
5.1 테스트용 C 모듈

 

    이 강좌를 진행하기 위해서 작성되는 C 모듈 소스는 다음과 같다.
   
    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
   
    #define LUA_LIB
   
    #include <lua.h>
    #include <lauxlib.h>
   
    static int port_list( lua_State *L )
    {
        printf( "OK CALL MODULE port_list()\n" );
        return 0;
    }
   
    static int create( lua_State *L )
    {
        printf( "OK CALL MODULE create()\n" );
        return 0;
    }
   
    static const struct luaL_Reg sm[] =
    {
        { "port_list"   , port_list },
        { "create"      , create },
       
        { NULL, NULL }
    };
   
    LUALIB_API int luaopen_serial( lua_State *L )
    {
        luaL_register(L, "serial", sm );
       
        return 1;
    }
   
5.2 Makefile

 

    위 소스를 모듈로 만들기 위한  Makefile 은 다음과 같다.
   
    각 모듈에 맞게 수정하는 부분은
   
    LUA_MODULE : 루아 모듈명
    C_SRCS     : 모듈을 구성하는 소스 목록
   
    -----------------------------------------------------------------------
   
    CROSS_PREFIX = arm-linux
   
    LUA_MODULE = serial.so
   
    TARGET     = $(LUA_MODULE)
    TARGET_NFS = /nfs/lua
   
    LIB_LUA_A  = liblua.a
   
    C_SRCS =
    LUA_SRCS =
    LUA_LIBS_SRCS =
   
    C_SRCS      += serial.c
    LUA_SRCS    += run.lua
   
    # LUA Support  -- CORE
    LUA_LIBS_SRCS =
    LUA_LIBS_SRCS += ../../lua_lib/lapi.c
    LUA_LIBS_SRCS += ../../lua_lib/lcode.c
    LUA_LIBS_SRCS += ../../lua_lib/ldebug.c
    LUA_LIBS_SRCS += ../../lua_lib/ldo.c
    LUA_LIBS_SRCS += ../../lua_lib/ldump.c
    LUA_LIBS_SRCS += ../../lua_lib/lfunc.c
    LUA_LIBS_SRCS += ../../lua_lib/lgc.c
    LUA_LIBS_SRCS += ../../lua_lib/llex.c
    LUA_LIBS_SRCS += ../../lua_lib/lmem.c
    LUA_LIBS_SRCS += ../../lua_lib/lobject.c
    LUA_LIBS_SRCS += ../../lua_lib/lopcodes.c
    LUA_LIBS_SRCS += ../../lua_lib/lparser.c
    LUA_LIBS_SRCS += ../../lua_lib/lstate.c
    LUA_LIBS_SRCS += ../../lua_lib/lstring.c
    LUA_LIBS_SRCS += ../../lua_lib/ltable.c
    LUA_LIBS_SRCS += ../../lua_lib/ltm.c
    LUA_LIBS_SRCS += ../../lua_lib/lundump.c
    LUA_LIBS_SRCS += ../../lua_lib/lvm.c
    LUA_LIBS_SRCS += ../../lua_lib/lzio.c
   
    # LUA Support  -- LIB
   
    LUA_LIBS_SRCS += ../../lua_lib/lauxlib.c
    LUA_LIBS_SRCS += ../../lua_lib/lbaselib.c
    LUA_LIBS_SRCS += ../../lua_lib/ldblib.c
    LUA_LIBS_SRCS += ../../lua_lib/liolib.c
    LUA_LIBS_SRCS += ../../lua_lib/lmathlib.c
    LUA_LIBS_SRCS += ../../lua_lib/loslib.c
    LUA_LIBS_SRCS += ../../lua_lib/ltablib.c
    LUA_LIBS_SRCS += ../../lua_lib/lstrlib.c
    LUA_LIBS_SRCS += ../../lua_lib/loadlib.c
    LUA_LIBS_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./
    LDFLAGS += -L../../lua_lib/
    LDFLAGS += -L/usr/$(CROSS_PREFIX)/lib
   
    LIBS  = -lm -ldl -llua
   
    CFLAGS   += $(INCLUDES)
    CFLAGS   += -Wall -O2 -g -DLUA_USE_LINUX
    CPPFLAGS += $(DEFINES)
   
    ARFLAGS = rs
   
    #---------------------------------------------------------------------
    CC           = $(CROSS_PREFIX)-gcc
    CXX          = $(CROSS_PREFIX)-g++
    AR           = $(CROSS_PREFIX)-ar rcu
    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)
    LUA_LIBS_OBJS   = $(LUA_LIBS_SRCS:%.c=%.o)
   
    #
    # Compilation target for C files
    #
    %.o:%.c
        @echo "Compiling $< ..."
        $(CC) -c $(CFLAGS) -o $@ $<
   
    %.o:%.cc
        @echo "Compiling $< ..."
        $(CXX) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
   
    #
    # Compilation target for C++ files
    #
    %.o:%.cc
        @echo "C++ compiling $< ..."
        $(CXX) -c $(CFLAGS) $(CXXFLAGS) -o $@ $<
   
    all : $(LIB_LUA_A) $(LIB_GXLIB_A) $(TARGET)
        cp -a $(LUA_MODULE) $(TARGET_NFS)
        cp $(LUA_SRCS) $(TARGET_NFS)
   
    $(LIB_LUA_A) : $(LUA_LIBS_OBJS)
        $(AR) $@ $?
        $(RANLIB) $@
   
    $(TARGET) : $(C_OBJS)
        $(CC) $(LDFLAGS)  -shared -Wl,-soname,$(TARGET) $(C_OBJS) -o $@ $(LIBS)
   
    dep :
        $(CC) -M $(INCLUDES) $(C_SRCS) > .depend
   
    clean:
        rm -f *.bak
        rm -f *.map
        rm -f *.o
        rm -f *.so
        rm -f $(C_OBJS)
        rm -f $(LUA_LIBS_OBJS)
        rm -f $(LIB_LUA_A)
        rm -f $(TARGET) core
   
    distclean: clean
        rm -rf .depend
   
    ifeq (.depend,$(wildcard .depend))
    include .depend
    endif

 

6. 수행

 

    수행은 nfs 를 마운트 해서 보드에서 하는데 다음과 같은 파일이 준비도 있어야 한다.
   
    [root@falinux lua]$ ls        
    lua        run.lua    serial.so
    [root@falinux lua]$           
   
     수행은 다음과 같이 하면 된다.
   
    [root@falinux lua]$ ./run.lua
    START TEST LUA
    OK CALL MODULE port_list()
    OK CALL MODULE create()
    [root@falinux lua]$

    모듈이 호출되는 것을 출력문으로 확인 할 수 있다.

 

C000_lua.gif