Clojure로 뭔가를 할 때
Emacs,
SLIME,
swank-clojure,
clojure-mode 조합을 사용하려면
Clojure Box가 가장 이상적인 환경이라고 할 수 있을 것입니다. 그러나, 이미 자신만의 Emacs 환경을 가지고 있다면(
아마 처음 Emacs를 접한 분이 아니라면 대부분 자신만의 환경을 가지고 있을 겁니다. Emacs란 그런 물건이니까요.) Clojure Box를 별도로 설치해서 사용하기보다는 자신의 Emacs 환경에 통합하기를 더 좋아할 겁니다.
저는 SLIME과 swank-clojure, clojure-mode 각각을 고유 저장소에서 직접 내려 받아 사용하고 있습니다. 그런데, SLIME이 변경되는 속도는 swank-clojure가 그것을 따라잡는 속도보다 조금 더 빠르고, Clojure의 여러 가지 파격적(?) 문법이 함수형 언어에 '
달아' Common Lisp과 '
서르 사맛디 아니'하다는 점 때문에 약간의 문제가 생기곤 합니다. 그래서, 지금까지 저장소 버전을 사용하면서 겪었던 문제에 대해 그 해결 방법을 정리해보았습니다.
1. SLIME REPL 버퍼가 멈추는 문제
제일 처음 겪은 심각한 문제는 SLIME의 REPL 버퍼가 멈추는 것이었습니다. 도무지 원인을 알 수가 없었지요. 이리저리 마구잡이로 설정을 변경해가며 테스트 해보다가 결국 알아낸 것이,
slime-autodoc-mode가 활성화되어 있을 때 문제가 발생한다는 것이었습니다.
이 문제를 해결하기 위한 방법은 간단합니다. SLIME을 시작하기 전에 slime-autodoc-mode를 비활성화해주면 됩니다.
(setq slime-use-autodoc-mode nil)
Common Lisp에선 slime-autodoc-mode가 문제 없이 잘 동작하므로, Clojure와 Common Lisp을 같이 사용하는 경우라면 별도의 함수를 만들어서 상황에 따라 slime-use-autodoc-mode 변수값을 적절히 바꿔주면 됩니다.
그리고, SLIME이 clojure-mode와 연동되기 때문에 clojure-mode에서 slime-autodoc-mode가 활성화될 경우 마찬가지로 SLIME REPL 버퍼가 멈추게 됩니다. 이 문제를 해결하기 위해서는 clojure-mode에 대해 slime-autodoc-mode를 비활성화하는
hook을 추가해줍니다.
(eval-after-load "clojure-mode"
'(progn
(add-hook 'clojure-mode-hook
(lambda ()
(slime-autodoc-mode 0)))))
또 한 가지,
desktop-save-mode를 설정해서 사용하고 있고, Emacs 실행 시 자동으로 다시 열리는 파일 중 clojure 소스 파일이 있다면 여전히 SLIME REPL 버퍼와 clojure 소스 버퍼가 멈추는 문제가 발생합니다. 그러므로, slime-mode에 대해 다음과 같이 hook을 추가해줄 필요가 있습니다. (clojure-mode일 경우에 slime-autodoc-mode를 비활성화하고 그 외의 경우에는 활성화합니다.)
(eval-after-load "slime"
'(progn
(add-hook
'slime-mode-hook
(lambda ()
(if (eq major-mode 'clojure-mode)
(slime-autodoc-mode 0)
(slime-autodoc-mode 1))))
(add-hook
'slime-connected-hook
(lambda ()
(if (string=
(slime-lisp-implementation-type)
"Clojure")
(setq slime-use-autodoc-mode nil)
(setq slime-use-autodoc-mode t))))))
(eval-after-load "slime-repl"
'(progn
(add-hook
'slime-repl-mode-hook
(lambda ()
(if (string=
(slime-lisp-implementation-type)
"Clojure")
(progn (setq slime-use-autodoc-mode nil)
(slime-autodoc-mode 0))
(progn (setq slime-use-autodoc-mode t)
(slime-autodoc-mode 1)))))))
2. Evaluation abort 상황에서 오류 발생하는 문제
SLIME REPL 상에서 일반적인 에러가 발생하면
sldb 버퍼가 뜨는데, 여기서 '
Quit to the SLIME top level'을 선택하면 아래와 같은 에러 메시지를 보게 됩니다.
error in process filter: Wrong number of arguments: nil, 0
위 상황 외에도 다른 몇몇 상황에서 역시 동일한 에러 메시지를 보게 되는데, 이 문제는 저장소 상의 최신 SLIME 소스에서 swank
abort 메시지 인터페이스가 변경되었기 때문에 발생하게 된 것입니다. 변경된 swank abort 메시지 인터페이스는
condition 인자를 하나 필요로 하지만, swank-clojure에선 아무런 인자 없이 abort 메시지만 전달하기 때문에 에러가 발생하는 것이죠. 이 문제를 해결하기 위해선 swank-clojure 쪽 소스를 살짝 손봐야 합니다.
[swank-clojure 폴더]/src/swank/core.clj 파일에서 아래 부분을 모두 찾아,
(:abort)
다음과 같이 수정해줍니다. (
물론 이것은 공식적인 해결 방법은 아닙니다. 에러 없이 동작할 수 있도록 임시로 수정해주는 것이죠.)
(:abort ~(thread-name (current-thread)))
이 글을 작성하고 있는 시점에서 수정해야 할 부분은 총 5 곳인데, 모두
eval-for-emacs 함수 내부에 있습니다.
수정 후 다시 swank-clojure를 구동한 다음 sldb에서 확인해보면 'Quit to the SLIME top level'을 선택했을 때 REPL 상에서 정상적으로 아래와 같은 메시지를 볼 수 있습니다.
; Evaluation aborted on Swank REPL Thread.