1990년대 후반에 프로그래밍 세계라는 컴퓨터 잡지에 기고했던 글입니다. 해당 잡지는 폐간되었습니다.
이번 회에는 Tcl/Tk를 확장하여 더 많은 기능을 제공하고 프로그래머들의 다양한 요구 사항을 만족시켜 줄 수 있는 Tcl/Tk의 확장된 형태의 언어(extension)와 Tcl/Tk의 응용 프로그램에 대해서 살펴보기로 한다. 대개의 Tcl/Tk Extension들은 Tcl을 기반 언어로 제공하고 있거나 다른 언어 쪽에서 Tcl의 기능을 추가시킨 것이 주를 이룬다.
다양한 Tcl/Tk 확장 언어들을 보면 Tcl/Tk가 얼마나 널리 사용되고 확장성이나 이식성이 뛰어난지를 알 수 있게 될 것이다. 그러나 모든 확장 언어들을 살펴 보기에는 지면이 허락하지 않으므로, 개발용으로 많은 기능이 s제공되고 발전 가능성이 있다고 생각되는 몇 가지의 extension을 골라서 그것들에 대해서 살펴 보기로 한다.
필자가 골라낸 확장 언어들은 Expect, TclX, SpecTcl, [incr Tcl]이 있고, Java와의 통합을 위한 Jacl과 TclBlend 등이 있다. 그 밖의 확장 언어들에 대해서 간단하게 살펴볼 것이다. 언어의 상세한 문법에 대해서는 다루지 않을 것이지만, 특징적인 기능에 대해 알아보고 사용 예에 대해서 들여다 보기로 한다.
Tcl/Tk의 응용 프로그램들은 각 분야별로 그 수가 엄청나기 때문에 하나씩 언급할 수조차 없다. 그러므로 특이할 만한 응용 프로그램을 필자가 임의로 몇 가지 골라서 그 특징적인 기능들에 대해서 살펴보기로 하겠다.
Expect는 User-interactive한 Tcl 스크립트를 작성할 수 있는 확장된 형태의 언어이다. 'expect & interact'라고 표현하는 것이 Expect의 핵심이라고 할 수 있는데, 이것은 interactive한 프로그램으로부터 나오는 메시지나 event를 기다렸다가(expect), 사용자의 입력을 받거나 받아두었다가 그 프로그램에 응답을 하는(interact) 특징적인 기능을 단적으로 보여주는 것이다.
Expect는 https://core.tcl-lang.org/expect 에서 구할 수 있다. Expect는 미국 NIST(National Institute of Standards and Technology)에서 지원하는 문자지향 응용프로그램을 자동화하는 사실상의(de facto) 표준 도구가 되었다. Tcl/Tk 프로그래머라면 한 번 쯤은 들어봤을 만한 유명한 Tcl Extension이라고 할 수 있다.
Expect는 telnet이나 ftp같은 네트웍 프로그램에 사용할 수도 있고, passwd나 fsck같은 unix 프로그램에도 사용할 수 있다. 환경변수를 비롯한 설정 등을 네트웍 프로그램이나 su 같은 명령이 수행될 때 프로그램을 뛰어넘어 가지고 갈 수 있다.
Expect의 주요 명령은 크게 5개가 있다. 그 밖에도 명령들이야 많이 존재하지만, 사용자와 expect 프로세스(process), 사용자가 수행하기를 원하는 프로세스의 3자간의 메시지 통신에 필요한 명령이 5가지인 것이다.
우선 Expect 메시지 통신에 사용되는 명령은 모두 expect를 기준으로 이름이 붙여져 있다. expect 프로세스가 사용자로부터 메시지를 기다리는 것은 expect_user이고 사용자 프로세스로부터 메시지를 기다리는 것은 expect이다. expect 프로세스가 사용자에게 메시지를 보내는 것은 send_user이고, 사용자 프로세스에 메시지를 보내는 명령은 send이다. 나머지 하나의 메시지 통신 명령은 interact로서, 이 명령은 사용자의 키 입력을 expect가 곧장 사용자 프로세스로 보내는 것이다. 그림 1은 이러한 메시지 통신의 메커니즘을 도식화한 것이다.
그림 1
telnet을 이용한 간단한 접속 프로그램을 작성해 보도록 한다.
#!/usr/local/bin/expect —
expect_user -re “(.*)\n”
set login_id $expect_out(1,string)
spawn telnet localhost
expect “login: ”
send “$login_id\n”
expect “Password: \n”
send “dlelql.\n”
interact
이 스크립트를 my_login이라는 이름으로 저장하고 실행 권한(permission)을 지정한 다음, 실행해보도록 하자.
vi my_login
chmod a+x my_login
rehash (Bourne shell계열의 shell에서는 hash -r)
./my_login
첫번째 줄의 expect_user명령은 위에서 설명한 대로, 사용자로부터 메시지를 기다리는 것이다. -re 옵션(option)은 정규 표현식(regular expression)을 의미하므로 newline을 제외한 모든 문자열을 expect_out이라는 변수에 저장하게 된다. 그 다음 줄에서 login_id라는 사용자 변수를 지정하면서 expect_out이라는 변수로부터 substring match된 첫번째 결과를 꺼내어 사용하게 된다.
세번째 줄에서는 telnet이라는 사용자 프로세스를 spawn하게 된다. spawn이란 Expect에서 사용하는 일종의 fork/exec 메커니즘이라고 볼 수 있다. 네번째 줄에서는 사용자 프로세스로부터 login: 이라는 메시지를 기다렸다가 다섯번째 줄에서 이미 지정된 사용자 변수의 값을 사용자 프로세스로 보내게 된다.
마지막 줄에서는 interact명령으로 사용자 프로세스에 대한 제어(control)을 사용자에게 넘겨주게 된다. 간단히 말해서, 사용자의 입력이 직접 사용자 프로세스로 넘어가게 될 것이다. 로그인(login) 과정이 성공적이었다면, 사용자의 telnet으로 localhost의 shell을 하나 더 띄워서 작업을 수행할 수 있게 되는 것이다.
기본적인 제어 구문이나 프러시져(procedure) 구문 등은 Tcl의 문법을 따르고 있기 때문에 자세한 설명은 넘어가기로 하겠다. Expect의 명령들은 다양한 옵션과 유연한 문법 구조를 가지고 있기 때문에 위에 제시된 예제와 같은 딱딱한 문법이 아니라 보다 자연스러운(영어식 표현으로 자연스러운) 방식으로 프로그램을 작성할 수 있을 것이다. 다음 예제를 살펴보도록 한다.
expect {
busy {
puts busy;
exp_continue
}
timeout my_proc1
connected my_proc2 "invalid password" my_proc3
}
expect 명령은 이와 같은 블럭(block)으로 구성할 수도 있는데, 이렇게 되면 각각의 상황에 따라 프러시져(또는 built-in 명령)를 수행하게 할 수 있다. busy한 경우에는 메시지를 출력하고 계속 expect 블럭을 재수행하게 되고, 다른 경우에는 각각 지정된 프러시져를 수행하게 된다. 일종의 분기 구문처럼 생각할 수 있다.
interact {
"/" {
forward_search
return
}
"?" {
backward_search
return
}
"Q" inter_return
}
interact 명령도 expect 명령처럼 블럭 구문으로 사용할 수 있는데, '/' 키를 입력하면 forward_search 프러시져를 수행하게 된다. “Q”를 누르면 interact 블럭을 빠져나오게 된다. inter_return은 interact 블럭을 빠져나오는데 반해, return은 블럭을 다시 수행한다는 차이점이 있다. 지정된 세 개의 키 이외의 입력이 들어오면 expect 프로세스가 가로채지 않고 사용자 프로세스로 직접 보내게 된다.
필자는 개인적으로 TclX를 사용하는데, 바로 TclX를 이용한 MP3 연주기의 X 윈도우 인터페이스(interface)를 사용하기 때문이다. MP3 연주기로 유명한 mpg123은 텍스트 기반의 프로그램이기 때문에 X 윈도우 인터페이스는 tk3play라는 패키지가 따로 지원되어야 한다. 바로 이 tk3play는 TclX로 작성된 스크립트이므로, TclX 패키지가 필요한 것이다. tk3play는 그림 2와 같은 인터페이스를 보여준다.
그림 2
TclX는 Extended Tcl을 뜻하는 확장 언어이다. 이 확장 언어는 Tcl에서 사용하기가 불편하거나 어려웠던 배열(array), 파일(file), 소켓(socket), 파일 이벤트(file event), 날짜와 시간 처리 등에 관한 다양한 기능이 추가된 형태이다.
TclX는 https://wiki.tcl-lang.org/page/TclX 에서 구할 수 있는데, 이 패키지를 컴파일(compile)하기 위해서는 Tcl/Tk 패키지도 함께 필요하다. 이것은 지난 1, 2회에 소개했던 대로 https://www.tcl.tk/에서 구할 수 있다. 컴파일이 끝나면 wishx라는 이름(Tcl/Tk를 컴파일하면 wish가 생긴다는 것은 지난 회에 이미 살펴보았다.)으로 실행 프로그램을 얻을 수 있다.
애초부터 TclX는 Tcl과는 개발 방향이 달랐다. TclX는 시스템 프로그래밍 작업과 거대한 응용 프로그램을 개발하는데 사용된다. 일반적인 시스템 프로그램에 사용되는 언어들, 예를 들면, C/C++, Java같은 언어들이 제공하는 것처럼, 기반 운영 체제를 다루는 방법과 도구를 제공하며, Tcl보다 훨씬 강력한 디버깅(debugging) 기능을 가지고 있다. 확장된 기능에 대한 자세한 내용은 다음과 같다.
TclX의 장점은 프로세스 제어 기능이 Tcl에 비해 상당히 정교하다는 것이다. fork와 execl 명령이 제공되며 system 명령도 이용할 수 있다. 파일 제어 기능에 있어서도 몇 가지 기능이 추가 되었는데, C 라이브러리 수준의 fcntl, flock/funlock, fstat, ftruncate, select등의 명령을 사용할 수 있다. 이진 탐색을 위한 bsearch 명령도 제공되고 있다.
정규 표현식을 다루는 명령인 scan은 scancontext, scanfile, scanmatch등의 명령들이 추가적으로 제공되어 더 강력한 정규 표현력을 가지게 된 것이다. 이것은 정규 표현식을 다루는 기능이 훨씬 뛰어났던 Perl과 같은 기존의 강력한 언어들을 굳이 사용하지 않아도 Tcl 차원에서 작업을 원활히 할 수 있다는 것을 보여주는 것이다.
수학함수나 리스트 관련 명령들도 추가되었는데, random이나 max, min같은 수학함수와 리스트를 집합처럼 사용할 수 있도록 union, intersect, intersect3같은 명령이 바로 그것이다. 이 밖에도 리스트를 다룰 수 있는 거의 모든 명령(lassign, lcontain, lempty, lmatch 등등)이 추가적으로 제공되고 있다.
eTclX에서는 'Keyed List'라는 자료형을 제공하는데, 이것은 C의 struct와 같은 자료형이라고 생각할 수 있다. key/value 쌍을 리스트의 하나의 필드(field)로 다룰 수 있는 것이다. 기존의 Tcl에서는 key/value는 해시(hash)형의 associative array에만 저장할 수 있었고, 필드에는 순서가 존재하지 않았는데 반해, TclX에서는 hash가 아닌 리스트에 저장할 수 있게 된 것이다. keylget, keylkeys, keyldel, keylset 등의 명령을 이용하면 리스트처럼 사용할 수 있는 것이다.
문자와 문자열을 다루는 기능에서도 많은 명령이 추가되었다. ccollate, cconcate, cequal, cindex, clength, crange, csubstr, ctoken, ctype 등의 명령이 그것이다. C 라이브러리에서 문자를 다루는 isalpha(), islower() 등의 함수들과, 문자열을 다루는 함수들인 strcmp(), strcat(), strlen() 등의 함수를 TclX에 구현해놓은 것이라고 할 수 있다. 이 밖에도 개발을 위해 디버깅 관련 명령들(cmdtrace, profile 등등)이 제공되고 있다.
[incr Tcl]은 “인크리먼트 티클”이나 “잉커 티클”이라고 읽는다. [incr Tcl]을 짧게 줄여서 itcl이라고도 한다. itcl은 C++이 C를 객체지향 언어로 확장시킨 것처럼, Tcl을 객체지향 언어로 확장시킨 것이다. itcl에는 객체지향 언어가 가져야 할 특성인 객체(object)와 클래스(class), 상속(inheritance), namespace 등의 개념이 도입되었다. 뿐만 아니라, 단순한 위짓을 모아서 강력한 기능을 가지는 위짓 셋(set)을 제공하는데, 이것을 megawidget이라 한다.
[incr Tcl]은 http://www.tcltk.com/itcl 에서 구할 수 있으며, 현재는 Scriptics사의 TclPro와 Tcl/Tk Consortium의 Tcl Blast!의 일부로 패키징되고 있다.
현재는 Tcl/Tk 패키지에 포함되어 있음
https://www.tcl.tk/man/tcl8.6/TclCmd/incr.htm
[incr Tcl]의 Object Oriented Programming 스타일은 C++이나 Java와 거의 비슷하다. 다만 거기서 사용하는 기호 대신에 예약어를 풀어쓰는 것이 다를 뿐이다. 다음의 예를 보자.
class Member {
variable name
variable address
constructor { myname myaddr } {
set name myname
set address myaddr
}
method show_addr { myname } {
puts $address
}
}
보다시피 C++이나 Java의 클래스 정의와 거의 비슷하다. 멤버 변수(member variable)를 선언할 때 명시적으로 variable이라는 예약어를 사용하고, 생성자와 소멸자를 지정할 때 constructor와 destructor를 선언한다. 멤버 함수(member function)를 위해 method라는 예약어가 사용된다. 멤버 변수나 멤버 함수를 사용하는 경우에는 다음과 같이 . 대신에 스페이스를 사용하는 것도 특징적이다.
Member member1 "Kim" "Seoul"
member1 show_addr
object를 제거하기 위해서는 delete object 명령을 사용할 수 있다.
delete object member1
class Tree {
…
method add { obj }
method clear { }
}
body Tree::add { obj } {
$obj parent $this
lappend children $obj
}
이와 같은 형식으로 클래스 내부에서는 method를 정의하지 않고 interface만 선언했다가 클래스 외부에서 body를 정의할 수도 있다.
멤버 변수나 멤버 함수 선언을 할 때, public, private, protected의 modifier를 써서 접근을 제어할 수 있다. public은 외부에 완전히 공개하는 것이고, private은 현재 정의가 되고 있는 clas 내부에서만 사용할 수 있으며, protected는 상속받은 sub클래스에서도 사용할 수 있다는 의미로 쓰인다. 공통으로 사용하는 변수는 common으로 지정할 수 있다. 이것은 C++과 Java의 static과 같은 것이라고 볼 수 있다.
class Memeber {
…
private common club_name
public proc list { }
}
이 예에서 club_name은 클래스에 하나만 존재하는 변수로 선언되고, list 함수는 method가 아니라는 사실에 주목해보자.
클래스를 선언할 때 inherit 명령을 사용하여 base class(super class)를 지정할 수 있는데, 여러 클래스를 함께 써서 다중 상속을 하는 것도 가능하다.
class FileTree {
inherit Tree FileMenu
…
}
FileTree라는 클래스는 Tree와 FileMenu라는 클래스를 상속받고 있다.
namespace는 재사용 가능한 라이브러리를 패키징하기 위해서 사용되는 명령, 변수, 클래스의 집합이다. 다음의 예를 보면서 설명을 하도록 하자.
namespace filebrowser {
variable roots
proc load_dir { cwin dir { selcmd "" } } {
global roots
set roots($cwin) [create_node $cwin $selcmd $dir]
}
return $roots($cwin)
}
namespace는 이와 같은 형식으로 만들 수 있다. namespace 안에서 선언된 변수와 함수들은 name collision이 발생하는 것을 피할 수 있게 된다.
::filebrowser::load_dir .textwin /usr/local/lib
이런 형식으로 함수를 사용하게 되면, 다른 namespace나 global 영역(scope)에서 사용되는 같은 이름의 함수와 충돌이 일어나지 않는 것이다. 다만 import 명령으로 namespace를 import하게 되면 굳이 ::로 시작하는 절대경로를 지정할 필요는 없다.
import filebrowser
load_dir .textwin /usr/local/lib
위짓을 다루는 데 있어서도 객체 지향적인 방법이 사용되었는데, 이러한 부분을 [incr Tk]가 담당하고 기본적인 Tk의 위짓을 확장시킨 위짓 집합을 [incr Widget]이라고 한다.
[incr Widget]의 모든 위짓은 itk::Archetype으로부터 상속을 받아서 기능을 확장시킨 클래스라고 생각할 수 있다. itk::Archetype은 다시 두 가지의 위짓 클래스로 분류되는데, 하나는 itk::Widget이고, 또 하나는 itk::Toplevel이다. 모든 위짓은 두 위짓을 상속받아서 새로 만들어낼 수 있다. 전자는 기존의 윈도우에 포함되어 생성이 되지만, 후자는 또 하나의 새로운 윈도우를 만들어 내며 생성이 된다. Combobox가 itk::Widget이라면 Messagedialog는 itk::Toplevel인 것이다.
그림 3
spinint .temp -labelpos w -labeltext “Water Temperature:” -fixed 5 -width 5 -range {32 212} -step 2 -wrap yes -orient horizontal
pack .temp -padx 10 -pady 10
다음은 Spinint라는 위짓을 만들어 가는 과정을 간단하게 살펴보기로 한다. 그러나 Spinint 위짓은 이미 만들어져서 제공되고 있기 때문에 다음의 과정을 답보할 필요는 없다. 위와 같이 하나의 위짓을 사용하듯이 선언하고 pack하기만 하면 된다.
class Spinint {
inherit itk::Widget
constructor { args } {
…
eval itk_initialize $args
}
public method clear { }
…
}
Spinint라는 새로운 위짓을 만들 때, 가장 먼저 하는 작업은 itk::Widget을 상속받는 것이다. 그리고 생성자에서 argument로 넘겨받은 옵션을 처리한다. 나머지는 위짓을 다루는 method를 정의하면 된다.
위짓의 인스턴스(instance)가 하나 만들어질 때, 생성자가 호출되면 우선은 itk::Archetype의 생성자가 component list와 master option list를 만들게 된다. 다음은 itk::Widget의 생성자가 일종의 container인 hull이라는 컴퍼넌트(component)를 만든다. 이 hull이라는 컴퍼넌트는 화면에 나타나지는 않지만, 이후에 추가될 컴퍼넌트들을 포함하게 되는 가장 기본적인 컴퍼넌트이다.
다음은 Spinint 위짓 클래스의 생성자 내부에서 label 위짓 클래스의 인스턴스인 lab과 entry 위짓 클래스의 인스턴스인 ent를 컴퍼넌트로 등록하는 예제이다.
itk_component add label {
label $itk_interior.lab
} {
rename -background -textbackground textBackground Background
keep -background
keep -foreground
keep -cursor
}
이 예제는 lab이라는 위짓에서 사용하는 배경색, 전경색 등의 옵션을 master option list에 등록하는 것이다. -background 옵션은 -textbackground 옵션으로 이름을 바꾸어 충돌이 발생하지 않도록 하고 있다. master option list에 옵션이 등록되면, Spinint 위짓을 configure할 때, 그 영향이 컴퍼넌트인 lab 위짓까지 미치게 되는 것이다.
itk_component add entry {
entry $itk_interior.ent
} {
usual
ignore -foreground
}
ent 위짓은 usual이라는 명령으로 entry 위짓 클래스의 일반적인 옵션을 모두 master option list에 등록하고 ignore 명령으로 전경색 옵션을 제거하고 있다.
[incr Widget]에서 이미 만들어서 제공하고 있는 위짓 집합에는
등이 있다.
지난 Tk 강좌에서 텍스트 창에 스크롤바(scrollbar)를 붙이는 작업을 해보았는데, 그다지 쉬운 일은 아니었다. 이제는 [incr Widget]에서 제공하는 scrolledtext 위짓을 사용하여 간단하게 원하는 작업을 할 수 있다.
scrolledtext .st -labelpos n -labeltext “/etc/passwd” -vscrollmode static -hscrollmode static
pack .st -padx 10 -pady 10 -fill both -expand yes
.st import /etc/passwd
그림 4
[incr Tcl]을 사용하게 되면 다양한 위짓 집합과 상속이라는 기능을 가지게 되므로 위짓을 새로 만들고 다루는 일은 훨씬 쉬운 일이 되었다. 이제 더 정교하고 강력한 위짓을 만들기 위해 프로그래머가 할 일은 기존의 위짓들을 잘 배치하는 것 뿐이다.
BLT는 Tk에 새로운 위짓과 geometry 관리자의 기능을 추가한 것이다. 새로 추가된 위짓으로는 테이블이나 그래프, 곡선, 벡터 등이 있다. BLT는 https://wiki.tcl-lang.org/page/BLT 에서 구할 수 있다. 몇 가지 위짓의 예를 살펴보기로 하자. BLT를 설치하여 bltwish를 실행시키면 바로 BLT의 위짓을 사용할 수 있는 것은 아니다.
package require BLT
if { $tcl_version >= 8.0 } {
namespace import blt::*
namespace import -force blt::tile::*
}
패키지로 BLT를 사용하겠다고 선언한 후, namespace를 import하여 blt 관련 위짓을 상대 경로로 이름을 사용하겠다는 것을 지정해야 한다.(namespace는 [incr Tcl]을 참고할 것) 이제부터는 테이블이면 table, 그래프면 graph라고 쓸 수 있다.
다음은 하나의 barchart 예제가 보여줄 수 있는 여러가지 결과의 screenshot이다.
그림 5
그림 6
그림 7
그림 8
이 밖에도 차트를 zoom in/out하거나 차트의 방향(orientation)을 바꾸고, 축(axis)을 조정하는 기능까지도 사용할 수 있다. barchart와 비슷한 기능을 하는 위짓에는 graph가 있다. graph는 barchart의 많은 기능 뿐만 아니라, 그래프 상에 찍는 점 대신에 이미지를 사용할 수도 있다. 다음은 그래프 위짓의 예이다.
그림 9
Java와 Tcl은 개발의 취지조차 아예 다른, 성격이 상이한 언어들이다. Java는 이식성이 뛰어난 강력한 3세대 언어로서 복잡한 응용 프로그램을 개발하는데 사용되고 있고, Tcl은 다른 응용 프로그램에 내장되거나(embedded), 스크립트(script) 언어로서 간단하고 쉽게 사용되고 있다. 그러나 각각의 장점을 취합하여 확장시키려는 시도가 있었고, 그 결과물이 바로 Jacl과 Tcl Blend이다.
우선 Java 쪽에서 Tcl을 이용하는 면을 생각해본다면, Java는 시스템 프로그래밍에 적합하고, 복잡한 자료 구조와 강력한 타입 체킹(type checking)를 하며, 거대한 시스템을 구축하는데 사용될 수 있다. 그러나 자료구조와 algorithm을 표현하고 다루는 것이 복잡하므로 이런 점에서는 스크립트 언어를 사용하는 것이 더 유리하다. 반대로, Tcl은 빠른 개발에 유리하고 컴퍼넌트간의 연결이 간단하다. 게다가 library형태로 제공되므로 다른 언어에 내장될(embedded) 수 있다.
여기에서 착안하여 Java에 Tcl의 scripting 능력을 추가하여 Java를 VBA(Visual Basic for Application)처럼 사용할 수 있는 것이다. 다시 말하면, VBA가 그러하듯이 응용 프로그램들 위에서 그것들을 연결시키는 기능을 Java가 수행할 수 있게 하는 것에 Tcl을 이용하는 것이다.
다음으로 Tcl쪽에서 Java를 이용하는 면을 고려한다면, 물론 Tcl도 이식성이 뛰어난 언어이긴 하지만, Java로 작성됨으로써 아주 다양한 시스템(Unix가 아닌)에까지 널리 이식될 수 있을 것이다. 이것이 바로 Jacl로서, Java 언어를 이용하여 Tcl을 구현한 것이라고 볼 수 있다.
Tcl Blend는 C로 작성된 Tcl 해석기가 JVM(Java Virtual Machine)을 load/interact할 수 있도록 만든 프로그램으로 C로 작성되어 있는 코드들을 조금씩(incrementally) Java 코드로 옮겨서 이식성을 높이는데 사용할 수 있다.
Jacl과 Tcl Blend이라는 Java Package는 Java의 reflection API를 이용하여 Java의 class를 Tcl에서 사용할 수 있을 뿐만 아니라, JavaBean를 스크립트에서 쉽게 다룰 수 있으므로 Java의 강력한 기능까지도 Tcl에서 아주 쉽게 사용할 수 있다는 장점을 가지게 된다. 새로운 컴퍼넌트를 작성하기 위해 Java Studio를 이용할 수도 있다. 이러한 특징들은 Tcl을 더욱 강력하게 만드는 무기가 될 것이 분명하다.
다음의 예제 코드를 참조하도록 하자. 낯익은 Java의 method들이 Tcl에서 사용되고 있지 않은가!
set f [java::new java.awt.Frame]
$f setTitle “Hello World”
set text [java::new java.awt.TextArea]
$text setText “Simple example”
$f {add java.awt.Component} $text
$f setLocation 100 100
$f pack
$f toFront
이 예제는 Java AWT의 Frame을 생성하고 그 위에 TextArea를 붙여서 그 컴퍼넌트들을 다루는 작업을 Tcl로 수행하고 있는 것이다. 다음의 예제는 Java Beans와 관련하여 callback 함수를 Beans에 등록하는 작업을 간단하게 수행하는 것이다.
set f [java::new java.awt.Frame]
set b [java:: new java.awt.Button “Exit”]
java::bind $b actionPerformed {set done yes}
$f {add java.awt.Component} $b
$f setLocation 100 100
$f pack
$f toFront
set done “no”
vwait done
$f dispose
Java에서 callback 함수를 등록하려면, 등록하기 전에 객체 인터페이스의 정확한 타입을 가져야 하므로 두 객체를 붙이기 위해 새로운 클래스(adaptor class)를 작성해야 하는 부담이 있으나, Tcl에서는 java:bind 명령만을 사용하여 아주 간단하게 callback 함수를 등록하고 있다.
Jacl은 https://wiki.tcl-lang.org/page/Jacl에서, Tcl Blend는 https://wiki.tcl-lang.org/page/TclBlend 에서 구할 수 있다.
Comanche는 Apache GUI 프로젝트의 일환으로 추진되는 프로젝트인데, Tcl/Tk를 기반으로 하여 Apache 웹 서버(web server) 설정을 할 수 있도록하는 X 윈도우 인터페이스를 제공하는 프로젝트의 이름이다. 텍스트로 작성된 설정 파일을 사용자가 직접 고치는 부담을 덜어주려는 의도에서 출발한 이 프로젝트는 최근에도(99년 4월) 계속 새로운 버전의 패키지를 발표하고 있다. 프로그램의 인터페이스는 그림 10~13과 같다.
그림 10
그림 11
그림 12
그림 13
Comanche는 Apache 웹 서버의 설정을 윈도우 상에서 할 수 있도록 여러 위짓(widget)을 이용하고 있는데, Tcl/Tk를 기반으로 했기 때문에, 단순히 Unix의 X 윈도우 시스템 뿐만 아니라 MS 윈도우 시스템에도 이식(porting)이 어렵지 않다. 이러한 이식성 때문에 사용자들이 쉽게 강력한 기능을 가진 Apache 웹 서버를 시스템에
구애받지 않고 사용할 수 있게 되는 것이다.
Comanche는 Configuration Manager for Apache의 줄임말로서, 미국 서부에 거주하는 토착민(인디언)의 한 부족의 이름이기도 하다. Apache도 마찬가지이다. Comanche 홈페이지에서 미국 내 인디언 부족들에 관련된 정보를 제공하는 사이트에 연결된 링크를 볼 수 있다.
https://wiki.tcl-lang.org/page/Comanche 에서 더욱 자세한 내용을 살펴볼 수 있을 것이다.
Tcl Debugger에는 여러 가지가 있다. TclPro 패키지에 들어가는 TclPro Debugger는 거의 DDD(Data Display Debugger)의 수준까지 제공을 하고 있으나, Freeware가 아닌 관계로 여기서 다루지는 않도록 하겠다.
텍스트 환경에서 디버깅을 하려면, Expect를 사용하는 것이 도움이 된다. Expect는 Debugger를 포함하고 있는 관계로 -D 옵션을 사용하여 에러 발생시 내장 디버거가 작동하도록 할 수 있다.
% expect -D 1
expect1.1> set 1 hello
1: history add {set 1 hello
}
dbg1.0> w
*0: expect {-D} {1}
1: unknown {history} {add} {set 1 hello
}
Expect debugger의 명령들은 다음 표와 같다.
명령 | 설명 |
---|---|
s | step into procedure : 프러시져 안으로 컨트롤을 옮긴다. |
n | step over procedure : 프러시져를 건너 뛴다. |
r | return from procedure : 프러시져에서 빠져나온다. |
b | set, clear, or show /td : 중지점 |
c | continue : 수행을 계속한다. |
w | show stack : 스택을 조사한다. |
u | move scope up : 스택의 scope에서 위쪽으로 컨트롤을 옮긴다. |
d | move scope down : 스택의 scope에서 아래쪽으로 컨트롤을 옮긴다. |
h | help : 자세한 옵션 설명을 볼 수 있다. |
Expect debugger를 사용하는 자세한 방법은 생략하도록 하겠다. GNU Debugger에 어느 정도 익숙한 개발자라면 충분히 이해할 수 있을 만큼 간단한 기능으로 국한되어 있기 때문이다.
윈도우 인터페이스를 가지고 있는 디버거도 있는데, TDB(Tcl Debugger)이다. https://wiki.tcl-lang.org/page/debugging 에서 구할 수 있다.
TDB는 TdChoose.tcl이라는 윈도우 인터페이스와 TdDebug.tcl이라는 디버거로 구성된 2개의 Tcl/Tk 스크립트인데, wish로 읽어들여서 수행가능하다.
wish TdChoose.tcl ~/bin/mpgplay.tcl
~/bin/mpgplay.tcl이라는 Tcl/Tk 스크립트를 Debugging할 때 위와 같은 방법으로 Tcl Debugger를 사용할 수 있다.
그림 14
그림 15
그림 14처럼 메인 화면에 뜨고, 프러시져 내부로 들어가면 그림 15와 같은 윈도우가 떠서 그 안에서 중지점(breakpoint)을 잡아서 디버깅을 수행할 수 있다.
SpecTcl은 Tcl/Tk 프로그램의 GUI(Graphical User Interface)를 제작하는 것을 돕는 개발 환경을 제공하는 프로그램이다. Grid Geometry Manager를 사용하여 Tcl/Tk 응용 프로그램의 개발 환경을 제공하는데, constraint-based이기 때문에 하나의 위짓을 Grid 안에 위치한 하나의 컬럼으로 다루게 되어 매우 간단하게 사용할 수 있다.
Tcl/Tk 응용 프로그램에서 GUI를 만들게 되면 대부분의 시간을 packing하고 layout을 잡는데 허비하게 되는데, SpecTcl을 이용하게 되면, Grid안에 위짓을 하나씩 위치시킬 수 있으므로, 위짓들의 geometry를 관리하는 아주 번거로운 작업들을 자동화하고 일관성있게 조작할 수 있다는 장점이 있다.
SpecTcl은 다음에서 구할 수 있다.
http://www.tcl.tk/software/spectcl/index.tml
http://spectcl.sourceforge.net/
SpecTcl은 Tcl/Tk 응용프로그램 뿐만 아니라, Java, Perl등의 X 윈도우 응용 프로그램을 개발할 수 있다. SpecTcl을 실행시키면 Target 언어를 선택하라는 메뉴가 뜨고, 그에 따라 각각의 언어로 된 응용 프로그램의 GUI 개발 환경이 실행된다.
SpecTcl을 실행하여 Java를 선택해본다.
그림 16
그림 17
그림 16과 같은 개발 환경이 화면에 나타난다. 여기서 왼쪽 툴바(toolbar)에 있는 버튼을 드래그(drag)하여 중앙 화면에 있는 Grid 안의 임의의 컬럼으로 옮긴다. 그러면 버튼이 생성될 것이다. 그림 17과 같이 배치될 것이다.
버튼 위짓 위에 커서를 위치시키고 더블 클릭하여 속성 창을 띄워보자. 그림 18과 같은 속성 창이 뜰 것이다. 속성 창에서 action을 test2();라고 지정한다. 버튼을 클릭하면 test2()라는 callback 함수를 호출하겠다는 의미이다. 그리고 Edit 메뉴에서 Edit Code를 선택하여 test2() 함수를 정의한다. 그림 19는 함수를 정의하는 편집기 역할을 하는 창이다.
public int test2() {
System.out.println(“Hello”);
return 0;
}
그림 18
그림 19
File 메뉴에서 Save를 하고, Commands 메뉴에서 Build를 하면 Java 프로그램이 저장된다. test1이라는 프로그램으로 저장했다고 하면, test1.java가 생성되었을 것이다. 이제 Java 소스 프로그램을 컴파일하고 실행시켜보자.
javac test1.java
java test1
그림 20
그림 20와 같이 아주 간단한 프로그램이 실행되었다. 버튼을 눌러 “Hello”라는 메시지가 나오는 것을 확인하도록 하자.
SpecTcl의 수많은 기능들은 스스로 코드를 작성하면서 직접 확인해 볼 수 있을 것이다. 현재는 SpecTcl과 SpecJava 뿐만 아니라, SpecPerl까지 지원되고 있다. SpecTcl은 free로 배포되지만 개발이 중단되었고, SpecJava또한 아직까지는 JDK 1.0의 코드만을 생성할 따름이다. SpecPerl을 조금 변형시켜서 SpecPython이 개발되기도 하였다.
COSH는 윈도우즈용 wish이다. http://home.t-online.de/home/dshepherd/cosh.htm 에서 구할 수 있다.
Active Tcl은 Tcl 8.0을 위한 ActiveX의 wrapper이다. 다음에서 구할 수 있다.
https://www.activestate.com/products/tcl/
http://qwerty.maxwell.syr.edu/nt-tcl 에는 NT 관리자에게 유용한 Tcl 스크립트를 제작할 수 있는 프로그램을 제공하고 있다.
이 밖에도 COM이나 OLE를 다루는 Tcl 확장 언어들이 있다. 관련 패키지들은 http://www.scriptics.com/resource/software/extensions/windows 에서 확인할 수 있을 것이다.