공유 라이브러리(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에 로드하여 보면 이상 없이 불러와지는 걸 보실 수 있을 겁니다. 이것으로 사용자들은 여러분이 만든 공유 라이브러리를 어느 버전에서도 사용할 수 있게 됩니다.