본문으로 바로가기

Tcl/Tk의 버전과 Stubs

category 카테고리 없음 2024. 5. 13. 09:59

공유 라이브러리(dll, so)로 Tcl/TK의 커맨드를 추가하는 것은, Tcl/Tk 인터프리터에 손상을 주지 않고 기존의 확장 tclsh나 확장 wish를 빌드하여 배포하는 방법보다도 편하기 때문에, 대부분의 유명한 확장 라이브러리는 공유 라이브러리 형태로 배포되고 있습니다. 사실 이것만으로도 충분하지만, Tcl/TK 8.1부터 지원되고 있는 Stub라고 하는 기능을 사용한다면, Tcl/TK의 각 버전에 있는 헤더파일과 라이브러리로 빌드하여 만들어진 공유 라이브러리를 다른 버전의 Tcl/Tk 에 로드하여 사용할 수 있게 됩니다.

#include <stdlib.h>
#include <string.h>
#include <tcl.h>
 
static int maxObjCmd(
   ClientData clientData, Tcl_Interp* interp,
   int objc, Tcl_Obj* CONST objv[]){
   int  i;
   double maxvalue = 0;
 
   if(objc == 1){
      Tcl_WrongNumArgs(interp, 1, objv, "num num...");
      return TCL_ERROR;
   }
   for(i=1; i<objc; i++){
      double v;
      if(Tcl_GetDoubleFromObj(interp, objv[i], & v) == TCL_ERROR){
      return TCL_ERROR;
      }
      if(i == 1 || v > maxvalue) maxvalue = v;
   }
   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(maxvalue));
   return TCL_OK;
}
 
DLLEXPORT int Max_Init(Tcl_Interp* interp){
#ifdef USE_TCL_STUBS
   Tcl_InitStubs(interp, "8.1", 0);
#endif
   Tcl_CreateObjCommand(interp, "max", maxObjCmd, NULL, NULL);
   return Tcl_PkgProvide(interp, "max", "1.00");
}

전 강좌의 소스와 비교했을때 다른 곳은 어디일까요? 바로 초기화 부분에 3행이 추가됐습니다.

#ifdef USE_TCL_STUBS
   Tcl_InitStubs(interp, "8.1", 0);
#endif

Stub 기능을 사용하는데 필요한 처리는 이것 뿐 입니다. Tcl_InitStubs는 반드시 초기화 함수의 선두 부분에 써야 합니다.

두 번째 인자에는

Tcl_InitStubs(interp, "8.1", 0);

지원 가능한 Tcl의 최저 버전을 문자열로 지정합니다. 3번째 인자는, 2번째 인자에 적은 버전보다 높은 버전이라면 어느 버전도 로드할 수 있다의 의미인 0을 적고, 아니면 2번째 인자에 기록한 버전만 로드할 수 있는 1을 적습니다. 보통은 0으로 적는 게 좋습니다. 또한, Tcl뿐만 아니라 TK의 API를 사용할 경우에도 Tk_InitStubs를 사용할 수 있습니다.

#ifdef USE_TCL_STUBS
   Tcl_InitStubs(interp, "8.1", 0);
#endif
#ifdef USE_TK_STUBS
   Tk_InitStubs(interp, "8.1", 0);
#endif

VC++의 nmake 파일은 다음과 같습니다.

CC = cl
SHLD = cl /LD
TCLROOT = C:\TCL
CFLAGS =/nologo /O2 /I"$(TCLROOT)\include" /DWIN32 /DUSE_TCL_STUBS
LDFLAGS =/nologo
LIBS ="$(TCLROOT)\lib\tclstub84.lib" \ 
      "$(TCLROOT)\lib\tkstub84.lib" \ 
      "$(TCLROOT)\lib\tcl84.lib" \ 
      "$(TCLROOT)\lib\tk84.lib"
.c.obj:
   $(CC)$(CFLAGS) -c $*.c
OBJS = max.obj
max.dll:$(OBJS)
   $(SHLD) /o $@ $(LDFLAGS) $(OBJS) $(LIBS)

앞서 나왔던 Makefile 하고는 다릅니다. 컴파일 옵션에 /DUSE_TCL_STUBS 가 추가 된 것과, 링크한 라이브러리가 tcl84.lib와 tk84.lib 뿐만 아니라, tclstub84.lib와 tkstub84.lib가 추가 되었습니다. Tk의 API를 사용할 경우 /DUSE_TK_STUBS도 함께 붙일 필요가 있습니다. 이제 max.dll을 wish83에 로드하여 보고, wish84에 로드하여 보면 이상 없이 불러와지는 걸 보실 수 있을 겁니다. 이것으로 사용자들은 여러분이 만든 공유 라이브러리를 어느 버전에서도 사용할 수 있게 됩니다.