본문으로 바로가기

pcm0279 님이 올려주신 팁입니다.


C 프로그램에서 정의한 API들을 동적 라이브러리(.dll)로 만들어 Tcl script에서 C API 명령을 호출하여 사용하는 방법이다. 다음은 C프로그램의 예제소스이다.

// calc.h
extern int sum(int a, int b);          // extern을 사용하여 외부에서 호출 가능하도록 함.
extern int minus (int c, int d);      // extern을 사용하여 외부에서 호출 가능하도록 함.
// calc.c
#include <stdio.h>
#include "calc.h"
int sum(int a, int b) {
        return a+b;
}

int minus (int c, int d) {
        return c-d;
}

 

위 API들(sum,minus)을 호출하기 위한 과정은 다음과 같다.

  1. 헤더 정보에서 각 API들을 extern을 사용하여 외부에서 호출할 수 있도록 한다.
  2. 각각의 API들을 패키지로 만든다.
// tclsum.c
#include <tcl.h>
#include "calc.h"
static int sum_HandleProc( ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{        
        int a, b, c;

        Tcl_GetInt(interp, Tcl_GetString(objv[1]), &a);
        Tcl_GetInt(interp, Tcl_GetString(objv[2]), &b);

        c = sum(a, b);  // <-- sum API 호출 부분
        Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
        return TCL_OK;
}

DLLEXPORT int Sum_Init(Tcl_Interp* interp){
   Tcl_CreateObjCommand(interp, "sum", sum_HandleProc, NULL, NULL);
   return Tcl_PkgProvide(interp, "sum", "1.00");
}
// tclminus.c
#include <tcl.h>
#include "calc.h"
static int minus_HandleProc( ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{        
        int a, b, c;

        Tcl_GetInt(interp, Tcl_GetString(objv[1]), &a);
        Tcl_GetInt(interp, Tcl_GetString(objv[2]), &b);

        c = minus(a, b);  // <-- minus API 호출 부분
        Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
        return TCL_OK;
}

DLLEXPORT int Minus_Init(Tcl_Interp* interp){
        Tcl_CreateObjCommand(interp, "minus", minus_HandleProc, NULL, NULL);
        return Tcl_PkgProvide(interp, "minus", "1.00");
}

 

makefile 작성

# makefile_sum
TCL   = c:\tcl                                                        # tcl 위치
SHLD   = cl /LD

CFLAGS   = /nologo /O2 /I"$(TCL)\include"
LDFLAGS   = /nologo
LIBS   = "$(TCL)\lib\tcl85.lib" "$(TCL)\lib\tk85.lib"    #  $(TCL)\lib\tcl<tcl version No.>.lib

TARGET = sum.dll                                                 # 동적 라이브러리 지정

SRC = calc.c tclsum.c                                            # 소스파일 지정
OBJS = $(SRC:.c=.obj)

.SUFFIXES:
.SUFFIXES: .c .obj
.c.obj:
        $(CC) /c $(CFLAGS) /Fo$*.obj $<

$(TARGET): $(OBJS)
        $(SHLD) /o $@ $(LDFLAGS) $(OBJS) $(LIBS)

all: $(TARGET)

clean:
        del /q $(OBJS)
        del /q $(TARGET)
# makefile_minus
TCL   = c:\tcl                                                          # tcl 위치
SHLD   = cl /LD

CFLAGS   = /nologo /O2 /I"$(TCL)\include"
LDFLAGS   = /nologo
LIBS   = "$(TCL)\lib\tcl85.lib" "$(TCL)\lib\tk85.lib"      # $(TCL)\lib\tcl<tcl version No.>.lib

TARGET = minus.dll                                                 # 동적라이브러리 지정

SRC = calc.c tclminus.c                                           # 소스파일 지정
OBJS = $(SRC:.c=.obj)

.SUFFIXES:
.SUFFIXES: .c .obj
.c.obj:
        $(CC) /c $(CFLAGS) /Fo$*.obj $<

$(TARGET): $(OBJS)
        $(SHLD) /o $@ $(LDFLAGS) $(OBJS) $(LIBS)

all: $(TARGET)

clean:
        del /q $(OBJS)
        del /q $(TARGET)

 

cmd 창에서 해당 소스와 makefile위치로 이동 후

> nmake -f makefile_sum
.....................
.....................
Creating library sum.lib and object sum.exp
> nmake -f makefile_minus
.....................
.....................
Creating library minus.lib and object minus.exp

 

위와 같은 메시지가 나타났다면 검증을 해보겠다. 폴더안에 .dll, .exp, .lib, .obj파일이 생성되었는지 확인한다.  cmd.exe 를 실행한다.

>tclsh85
%load sum.dll
%sum 3 6
9
%load minus.dll
%minus 5 3
2

위 과정이 모두 정상적으로 진행이 되었다면 C API호출법은 끝난 것이다. 마지막으로 .tcl파일을 작성하여 정상적으로 호출되는지 테스트를 해보겠다.

# test.tcl
load sum.dll
load minus.dll

puts [sum 10 1]
puts [minus 10 1]

gets stdin

cms를 실행 후

>tclsh85 test.tcl
11
9


수고하셨습니다. ^^ 위 방법을 전수해 주신 운영자님 진심으로 감사합니다. ^^