GNUEmacsManual:34

From 흡혈양파의 번역工房
Jump to navigation Jump to search
일반적 문제 처리하기(Dealing with Common Problems)

일반적 문제 처리하기(Dealing with Common Problems)

의도하지 않은 Emacs 명령어를 입력할 경우 곤란한 결과가 발생하곤 한다. 이번 장에서는 이해하기 이해하기 힘든 상황에서 복구하거나 실수를 취소하기 위해 어떤 일을 할 수 있는지 알려주고자 한다. Emacs 버그와 시스템 충돌 역시 고려하겠다.

끝내기와 취소하기(Quitting and Aborting)

C-g
C-Break

(MS-DOS만 해당) 끝내기: 실행 중이거나 부분적으로 입력한 명령어를 취소한다.


C-]

가장 안쪽의 재귀적 편집 수준을 중지하고 그것을 호출한 명령어를 취소한다(

abort-recursive-edit

).


ESC ESC ESC

끝내거나(quit) 취소(abort)한다(

keyboard-escape-quit

).


M-x top-level

현재 실행 중인 모든 재귀적 편집 수준을 취소한다.


C-/
C-x u
C-_

버퍼 내용에 대해 이전에 변경한 사항을 취소한다(

undo

).


명령어가 완료되기 전에 취소하는 방법에는 두 가지가 있는데, 하나는 C-g 를 이용해 끝내는(quitting) 방법이고 나머지 하나는 C-] 또는 M-x top-level 을 이용해 취소하는(aborting) 방법이다. 끝내기를 실행할 경우 부분적으로 입력되었거나 여전히 실행 중인 명령어를 취소한다. 취소를 실행할 경우 재귀적 편집 수준을 종료하여 재귀적 편집을 호출한 명령어를 취소시킨다(404 페이지의 31.10절 [재귀적 편집(Recursive Edit)] 참고).


C-g 를 이용해 끝내는 방법은 부분적으로 입력된 명령어나 사용자가 원하지 않는 수치적 인자를 제거하는 방법이다. 또한 실행 중인 명령어 중간에 위치할 때 C-g 를 사용하면 상대적으로 안전한 방법으로 명령어를 끝낸다. 가령 오랜 시간이 소요되는 제거 명령어를 끝낼 경우 모든 텍스트가 여전히 버퍼에 위치하거나 모든 텍스트가 킬 링에 위치하거나, 버퍼와 킬 링 두 위치에 존재할 수도 있다. Transient Mark 모드가 꺼져 있지 않은 한 영역이 활성화되었을 때 C-g 를 사용하면 마크를 비활성화시킨다(50 페이지의 8.7절 [비활성화된 Transient Mark(Disabled Transient Mark)] 참고). 증분 검색의 중간에 위치할 경우 C-g 는 특별하게 행동하는데, 검색에서 벗어나도록 두 개의 연속된 C-g 문자를 취할 수 있기 때문이다. 상세한 내용은 12.1절 [증분 검색(Incremental Search)]을 참고한다.


MS-DOS 에서 문자

C-Break

C-g 와 같은 끝내기(quit) 문자 역할을 한다. 그 이유는 MS-DOS에서는 명령어가 실행되는 동안 사용자와의 상호작용 사이에서 C-g 를 인식하는 데에 그것을 실행할 수 없기 때문이다. 반면

C-Break

는 언제든 인식할 수 있다. 관련 내용은 Specialized Emacs Features 의 "MS-DOS Keyboard" 절을 참고한다.


C-gC-g 를 입력하는 즉시

quit-flag

변수를

t

로 설정하여 작동하는데, Emacs Lisp 는 이 변수를 자주 확인하고 그 값이

nil

이 아닌 경우 끝낸다(quit). C-g 는 Emacs 가 입력 값을 기다리는 동안 사용자가 그것을 입력할 경우에 명령어로서 실행된다. 이런 경우 C-g

keyboard-quit

명령어를 실행시킨다.


텍스트 터미널 시스템에서 C-g 가 인식되기 전에 사용자가 C-g 를 두 번째로 입력하여 끝낼 경우 "비상 탈출(emergency escape)"이란 기능이 활성화되어 셸로 돌아간다. 관련 내용은 448 페이지의 34.2.8절 [비상 탈출(Emergency Escape)]을 참고한다.


끝낼 수 없는 상황도 있다. Emacs가 운영체제가 무언가를 실행하도록 기다리는 경우에는 Emacs 내에서 대기가 발생하는 특정 시스템 호출에 공을 들이지 않는 이상 끝내기가 불가능해진다. 우리는 사용자들이 종료시킬법한 시스템 호출에 공을 들였지만 아직 처리되지 않은 상황에 직면할 가능성은 여전히 존재한다. 매우 흔한 한 가지 사례로 NFS를 이용해 파일 입력 또는 출력을 기다리는 경우를 들 수 있는데, Emacs는 종료하는 방법을 스스로 알고 있지만 NFS 서버가 hung 상태일 때 사용자 프로그램들이 NFS를 기다리는 작업을 중단하도록 허용하는 NFS 구현은 소수에 불과하다.


C-] (

abort-recursive-edit

)를 이용해 중지하는 방법은 재귀적 편집 수준에서 벗어나 그것을 호출한 명령어를 취소하는 데에 사용된다. C-g 를 이용하여 끝내면 이러한 일을 실행하지도 않고 실행할 수도 없는 것이, 재귀적 편집 수준 내에서 부분적으로 입력된 명령어를 취소하는 데에 사용되기 때문이다. 두 가지 연산 모두 유용하다. 가령 재귀적 편집에서 C-u 8 을 입력하여 수치적 인자를 입력하고자 할 경우 C-g 를 이용해 인자를 취소하고 재귀적 편집에 남아 있을 수 있다.


ESC ESC ESC (

keyboard-escape-quit

) 시퀀스는 끝내기와 취소 모두 가능하다. (이런 방식으로 정의한 이유는 ESC 가 많은 PC 프로그램에서 "나가다(get out)"를 의미하기 때문이다.) 이는 접두 인자를 취소하거나, 선택된 영역을 삭제하거나, C-g 처럼 Query Replace 에서 벗어나게 해준다. 또한 C-] 처럼 미니버퍼 또는 재귀적 편집에서 벗어나도록 해준다. C-x 1 을 이용할 때처럼 프레임을 여러 창으로 나누는 작업을 벗어나게 해주기도 한다. 하지만 이 방법으로 실행할 수 없는 작업은 바로 실행 중인 명령어를 중단시키는 일이다. 그 이유는 이것이 일반 명령어로서 실행되고 Emacs 는 다음 명령어에 준비될 때까지 그것을 인식하지 못하기 때문이다.


M-x top-level 명령어는 사용자가 있는 모든 재귀적 편집 수준에서 벗어나도록 해주는 "충분한" C-] 명령어와 같으므로, 이것이 활성화되면 미니버퍼 역시 끝낸다. C-] 는 한 번에 하나의 수준을 벗어나도록 해주지만 M-x top-level 은 모든 수준을 한 번에 벗어난다. C-]M-x top-level 둘 다 여느 다른 명령어와 같지만 C-g 와 다르게 Emacs 가 명령어에 준비가 되어 있을 때에만 효력을 발휘한다. C-] 는 일반 키로서, 단지 키맵에서 그 바인딩 때문에 의미가 있다. 관련 내용은 404 페이지의 31.10절 [재귀적 편집(Recursive Edit)]을 참고한다.


C-/ (

undo

) 는 엄밀히 말해 명령어를 취소하는 방법은 아니지만 이미 실행이 완료된 명령어의 취소로 생각할 수 있겠다. 실행취소 기능에 관한 추가 정보는 109 페이지의 13.1절 [실행취소(Undo)]를 참고한다.


Emacs 문제 처리하기(Dealing with Emacs Trouble)

이번 절에서는 Emacs가 사용자의 예상대로 작동하지 않는 상황을 인식하고 처리하는 방법을 설명할 것인데 키보드 코드 믹스업, 이해할 수 없는 디스플레이, 메모리 부족, 충돌과 hang 을 예로 들 수 있겠다.


Emacs 에서 버그를 발견했다고 생각될 때 무엇을 해야 할지는 448 페이지의 34.3절 [버그(Bugs)]를 참고한다.


DEL 이 삭제를 실패할 경우(If DEL Failes to Delete)

모든 키보드에는 주로 ← Backspace 라고 붙여진 큰 키가 있는데, 이는 주로 사용자가 입력한 마지막 문자를 삭제하는 데에 사용된다. Emacs 에서 이 키는 DEL 과 동일하다.


그래픽 디스플레이 시스템에서 Emacs 를 시작하면 어떤 키가 DEL 의 역할을 하는지 자동으로 결정한다. 특이한 경우지만 Emacs가 시스템으로부터 틀린 정보를 얻어 ← Backspace 가 역방향이 아니라 순방향으로 삭제하는 경우도 발생한다.


어떤 키보드에는 보통 순방향으로 삭제하는 데에 사용되는 Delete 키도 있다. 이 키가 Emacs 에서 역방향으로 삭제할 경우 이 또한 Emacs 가 틀린 정보를 얻었음을 제시하지만 그 의미는 상반된다.


텍스트 터미널 시스템에서 ← Backspace 를 누를 때 문자를 삭제하는 대신

Control-h

과 같은 Help 명령어를 요청한다면 해당 키는 사실상 '

BS

' 문자를 전송함을 의미한다. Emacs 는 BSDEL 로 취급해야 하지만 그러지 않는 것이다.


어떤 경우든 즉각적 해결방법은 동일한데, 바로 M-x normal-erase-is-backspace-mode 명령어를 사용하는 것이다. 이는 Emacs 가 DEL 을 처리하기 위해 지원하는 2개의 모드를 토글하므로 Emacs가 틀린 모드에서 시작되었다면 올바른 모드로 전환시킬 것이다. 텍스트 터미널 시스템에서 BSDEL 로 취급될 때 도움을 요청하고 싶다면 F1 를 입력해야 하는데, 문자 코드 127을 전송한다면 C-? 역시 효과가 있을지도 모른다.


모든 Emacs 세션에서 문제를 해결하려면 다음 라인들 중 하나를 초기화 파일에 넣는다(437 페이지의 33.4절 [Init 파일(Init File)] 참고). 위에서 ← Backspace 가 역방향이 아닌 순방향으로 삭제하는 경우, 아래 라인을 이용해 ← BackspaceDEL 의 역할을 수행하도록 만든다:

(normal-erase-is-backspace-mode 0)


나머지 두 경우는 아래의 라인을 사용한다:

(normal-erase-is-backspace-mode 1)


모든 Emacs 세션에서 문제를 해결하는 또 다른 방법은

normal-erase-is-backspace

변수를 맞춤화하는 것으로,

t

값은 BS 또는 ← BackspaceDEL 인 모드를 명시하고,

nil

은 나머지 모드를 명시한다. 412 페이지의 33.1절 [쉬운 맞춤화(Easy Customization)]를 참고한다.


재귀적 편집 수준(Recursive Editing Levels)

재귀적 편집 수준은 중요하고 유용한 Emacs 의 기능이지만 그것을 이해하지 못한다면 작동하지 않는 것으로 보일 수도 있다.


모드 라인이 주 모드와 부 모드 이름을 포함하는 괄호 주변에 사각 괄호 '

[...]

'를 갖고 있다면 재귀적 편집 수준에 들어간 것이다. 의도적으로 들어가지 않았거나 그 의미를 이해하지 못할 경우 재귀적 편집 수준에서 벗어나야 한다. 그러기 위해서는 M-x top-level 을 입력한다. 404 페이지의 31.10절 [재귀적 편집(Recursive Edit)]을 참고한다.


화면 상의 쓰레기(Garbage on the Screen)

텍스트 터미널 상에 텍스트가 틀리게 보일 경우 가장 먼저 해야 할 일은 버퍼에서 틀린 것인지 확인하는 일이다. C-1 을 입력하면 전체 화면을 다시 표시한다. 이후 화면이 올바로 표시되면 전적으로 이전 화면 업데이트에 문제가 있는 것이다. (해결되지 않으면 다음 절을 참고한다.)


디스플레이 업데이트 문제는 사용자가 사용 중인 터미널에 대한 올바르지 않은 terminfo 엔트리에서 비롯되곤 한다. Emacs 배포판은 이러한 알려지지 않은 문제에 대한 해결책을

etc/TERMS

파일을 통해 제공한다.

INSTALL

은 그와 관련된 절에서 이러한 문제에 대한 일반적 조언을 포함한다. 올바른 terminfo 엔트리를 사용하는 것으로 보인다면 terminfo 엔트리에 버그가 있거나 Emacs 에서 특정 유형의 터미널에 대해 버그가 존재할 가능성이 있다.


텍스트 내 쓰레기(Garbage in the Text)

C-l 이 텍스트가 올바르지 않는다고 표시할 경우 C-h l 을 입력하여 사용자가 입력한 명령어들 중에서 관찰된 결과를 야기한 명령어를 확인한다. 이후 사용자가 올바르다고 간주하는 상태로 돌아갈 때까지 C-x u 를 이용하여 단계별로 변경 내용을 실행취소한다.


텍스트의 많은 부분이 버퍼의 시작이나 끝에서 누락된 것으로 보인다면 모드 라인에 '

Narrow

' 란 단어를 확인한다. 단어가 나타나면 사용자가 볼 수 없는 텍스트가 여전히 존재하지만 일시적으로 접근 불가 상태(off-limits)인 것이다. 다시 접근 가능하게 만들기 위해서는 C-x n w 를 입력한다. 73 페이지의 11.5절 [좁히기(Narrowing)]를 참고한다.


메모리 부족(Running out of Memory)

'Virtual memory exceeded'

라는 오류 메시지를 받으면 C-x s 를 이용해 수정된 버퍼를 저장하라. 이러한 저장 방법은 최소의 추가 메모리를 필요로 한다. Emacs 는 이러한 오류 메시지가 발생할 때 이용 가능한 메모리 reserve 를 유지하는데, 이것만으로 C-x s 가 작업을 완료하기엔 충분할 것이다. Reserve 가 사용될 때는 더 이상 reserve 가 없음을 의미하는

'!MEM FULL!'

이 모드 라인 시작에 표시될 것이다.


수정된 버퍼를 저장하고 나면 사용자는 해당 Emacs 세션을 종료하고 다른 세션을 시작하거나, M-x kill-some-buffers 를 사용해 현재 Emacs 작업에 공간을 제공할 수 있다. 이로 인해 충분한 공간이 확보되면 Emacs 는 그 메모리 reserve 를 다시 채울 것이고, 모드 라인에서

'!MEM FULL!'

이 사라질 것이다. 이는 사용자가 동일한 Emacs 세션에서 편집을 안전하게 계속할 수 있음을 의미한다.


메모리가 부족할 때 버퍼를 저장하거나 제거하기 위해 M-x buffer-menu 를 사용하는 것은 금하는데, Buffer Menu 는 자체에 꽤 많은 메모리를 필요로 하여 reserve 공급만으로 충분하지 않을 수 있기 때문이다.


Emacs가 충돌할 때(When Emacs Crashes)

Emacs 는 충돌하지 않도록 되어 있지만 만일 충돌할 경우 끝내기 전에 충돌 보고(crash report)를 생성한다. 충돌 보고는 표준 오류 스트림으로 출력된다. Emacs 가 GNU 또는 Unix 시스템에서 그래픽 데스크톱으로부터 시작되었다면 표준 오류 스트림은 보통

~/.xsession-errors

와 같은 파일로 전송되므로 그곳에서 충돌 보고를 찾을 수 있다. MS-Windows 에서 충돌 보고는 Emacs 프로세스의 현재 디렉터리에 표준 오류 스트림과 함께

emacs_backtrace.txt

란 이름의 파일로 작성된다.


충돌 보고의 포맷은 플랫폼에 따라 좌우된다. GNU C Library 를 이용하는 플랫폼을 비롯해 일부 플랫폼에서 충돌 보고는 충돌 이전의 실행 상태를 설명하는 backtrace 를 포함하는데, 이를 이용하면 충돌을 디버깅하는 데에 도움이 된다. GNU 시스템을 대상으로 예를 하나 들어보겠다:

Fatal error 11: Segmentation fault
Backtrace:
emacs[0x5094e4]
emacs[0x4ed3e6]
emacs[0x4ed504]
/lib64/libpthread.so.0[0x375220efe0]
/lib64/libpthread.so.0(read+0xe)[0x375220e08e]
emacs[0x509af6]
emacs[0x5acc26]
...


숫자 '

11

' 은 충돌에 해당하는 시스템 시그널 번호로, 이 사례에서는 세그멘테이션 오류에 해당한다. 16진수는 프로그램 주소로, 디버깅 툴을 이용해 소스 코드 라인과 상관될 수 있다. 가령 GDB 명령어 '

list *0x509af6

' 은 '

emacs[0x509af6]

' 엔트리에 해당하는 소스 코드 라인을 출력한다. 시스템에

addr2line

유틸리티가 있다면 아래의 셸 명령어는 소스 코드 라인 번호와 함께 backtrace을 출력한다.

sed -n 's/.*\[\(.*\)]$/\1/p' backtrace |
  addr2line -C -f -i -p -e bindir/emacs-binary


여기서 backtrace 는 backtrace 의 사본을 포함하는 텍스트 파일명이고, bindir 은 Emacs 실행 파일을 포함하는 디렉터리명이며, emacs-binary 는 Emacs 실행 파일의 이름인데 보통 GNU 와 Unix 시스템에서는

emacs

이고 MS-Windows 와 MS-DOS 에서는

emacs.exe

이다.

addr2line

의 버전이 너무 오래되어

-p

옵션을 가질 수 없다면 생략한다.


코어 파일을 지원하는 시스템에서 Emacs 가 충돌하면 코어 덤프(core dump)를 생성할 수 있다. 코어 덤프란 충돌 전에 프로그램의 상태에 관한 많은 데이터를 포함하는 파일로, GDB와 같은 디버거로 로딩함으로써 확인된다. 많은 플랫폼에서 코어 덤프는 기본적으로 비활성화되므로 사용자는 '

ulimit -c unlimited

' 라는 셸 명령어를 (셸 시작 스크립트에서) 실행함으로써 직접 활성화시켜야 한다.


충돌 후 복구(Recovery After a Crash)

Emacs 또는 컴퓨터가 충돌할 경우 사용자는 자동저장 파일로부터 충돌 시 편집 중이던 파일을 복구할 수가 있다. 이를 위해서는 Emacs 를 다시 시작하여 M-x recover-session 명령어를 입력한다.


이 명령어는 먼저 간섭된 세션 파일을 그 일자와 함께 열거하는 버퍼를 표시한다. 사용자는 복구시킬 세션을 선택해야만 한다. 보통 사용자는 가장 최근 세션을 원한다. 사용자가 선택하는 세션으로 포인트를 이동시킨 후 C-c C-c 를 입력한다.


그러면

recover-session

은 해당 세션 중에 편집하던 파일을 각각 고려하여 파이람다 복구할 것인지 묻는다. 파일에 y 로 답하면 해당 파일과 자동저장 파일의 일자를 표시한 후 그 파일을 복구할 것인지 다시 묻는다. 두 번째 질문에는 yes 로 확인해야 한다. 답을 하고 나면 Emacs 는 파일을 방문(visit)하지만 자동저장 파일로부터 텍스트를 얻는다.


recover-session

이 완료되면 사용자가 복구시킬 파일은 Emacs 버퍼에 위치한다. 이제 파일을 저장해야 한다. 파일을 저장해야만 업데이트를 할 수 있다.


어떠한 파일과도 상관되지 않은 내용의 버퍼를 갖고 있거나 자동 저장에서 중요한 변경 사항을 기록하기에 충분히 최근의 파일이 아닐 경우 GDB와

etc/emacs-buffer.gdb

스크립트를 이용해 (GNU Debugger) 코어 덤프로부터 복구할 수 있는데, 코어 덤프가 저장되어 있고 Emacs 실행 파일에 그 디버깅 심볼이 없을 경우에 한한다.


코어 덤프를 얻는 즉시

core.emacs

와 같은 다른 이름으로 재명명하여 다른 충돌이 발생 시 그것을 덮어쓰지 않도록 한다.


스크립트를 이용하기 위해서는 Emacs 실행 파일의 파일명과 코어 덤프의 파일명으로

gdb

를 실행하는데 '

gdb /usr/bin/emacs core.emacs

' 를 예로 들 수 있겠다.

(gdb)

프롬프트에서 복구 스크립트 '

source /usr/src/emacs/etc/emacs-buffer.gdb

' 를 로딩한다. 이후 어떠한 버퍼가 이용 가능한지 확인하려면

ybuffer-list

명령어를 입력한다. 이 명령어는 각 버퍼에 대한 버퍼 번호를 열거한다. 버퍼를 저장하려면

ysave-buffer

를 사용하는데, 버퍼 번호와 그 버퍼를 쓸 파일명을 명시한다. 기존이 없는 파일명을 사용해야 하며, 파일이 이미 존재하는 경우 스크립트는 오래된 내용의 백업을 만들지 않는다.


비상 탈출(Emergency Escape)

텍스트 터미널에서 비상 탈출 기능은 Emacs 가 사실상 Emacs 를 종료시켜 C-g 의 첫 번째 호출에 응답하기 전에 사용자가 C-g 를 두 번째로 입력할 경우 Emacs를 즉시 지연시킨다. 이러한 기능은 GNU Emacs가 얼마나 나쁜 hung 상태에 있든 빠져나올 수 있도록 만들기 위한 기능이다. 일이 순조롭게 진행되면 Emacs 가 첫 번째 C-g 를 빠르게 인식하고 처리하여 두 번째로 실행될 때 비상 탈출로 이어지지 않는다. 하지만 어떤 문제로 인해 Emacs 가 첫 번째 C-g 를 올바로 처리하지 못하면 두 번째 호출 시 셸로 돌아갈 것이다.


비상 탈출로 인한 지연 이후에 Emacs를 재개하면 이전에 하던 일로 되돌아가기 전에 두 가지 질문을 한다:

Auto-save? (y or n) 
Abort (and dump core)? (y or n)


각 질문에 y 또는 n 을 답한 후 RET 을 입력한다.


'

Auto-save?

' 에

y

라고 답하면 자동 저장이 활성화된 모든 수정 버퍼에서 즉각적인 자동 저장이 실행된다. n을 답하면 이를 건너뛴다.


'

Abort (and dump cord)?

' 에

y

라고 답하면 Emacs 의 충돌을 야기하여 코어를 덤프한다. 이는 Emacs 가 왜 애초에 중단하지 못했는지 알아내기 위해 마법사(wizard)를 활성화시키기 위함이다. 코어 덤프 이후에는 실행이 계속되지 않는다.


이 질문에

n

이라고 답할 경우 Emacs 실행이 재개된다. 운이 좋으면 Emacs는 요청한 중단(quit) 작업을 실행할 것이다. 아닐 경우 잇따라 C-g 를 실행할 때마다 비상 탈출을 다시 호출한다.


Emacs 가 hung 상태가 아니라 그저 속도가 느린 것이라면 그럴 의도가 아니더라도 C-g 기능을 두 번 호출한다. 그 다음 실행을 재개하여 두 질문에 n을 답하면 이전 상태로 돌아갈 것이다. 사용자가 요청한 중단(quit)이 곧 발생할 것이다.


비상 탈출은 텍스트 터미널 시스템에서만 활성화된다. 그래픽 디스플레이 시스템에서는 마우스를 이용해 Emacs를 죽이거나 다른 프로그램으로 전환할 수 있다.


MS-DOS 에서는

C-Break

를 (2회) 입력해야만 비상 탈출을 야기하지만 이조차도 작동하지 않을 때가 있는데, 바로 시스템 호출이 hung 상태이거나 Emacs 가 C 코드의 타이트 루프(tight loop)에 갇혔을 때이다.


버그 보고하기(Reporting Bugs)

Emacs에서 버그를 발견했다고 생각되면 보고하길 바란다. 버그를 수정하겠다고 장담하거나 그것이 버그라고 항상 동의하지는 못하더라도 이야기는 들어보길 원한다. 추가되었으면 하는 새 기능이 있어도 알려주길 바란다. 다음 절에서는 효과적인 버그 보고를 작성하도록 도와줄 것이다.

기존 버그 보고와 알려진 문제 읽기(Reading Existing Bug Reports and Known Problems)

버그를 보고하기 전에 가능하다면 이미 알려진 버그인지 확인하길 바란다. 사실 Emacs 향후 배포판인 개발 버전에서 수정된 버그일 수도 있기 때문이다. 알려진 문제를 확인하는 위치는 다음과 같다.

  • etc/PROBLEMS
    파일은 C-h C-p 를 입력하여 읽는다. 이 파일은 Emacs의 컴파일, 설치, 실행에서 직면하는 잘 알려진 문제를 열거한다. 해결책(workarounds)과 제 2 해결책(solutions)에 대한 제시사항이 실려 있다.
  • GNU Emacs FAQ 의 "Bugs and problems" 절에서는 사용자 수준의 문제를 추가로 찾을 수 있다.
  • http://debbugs.gnu.org 에서 찾을 수 있는 GNU Bug Tracker. Emacs 는 '
    emacs
    ' 패키지의 tracker 에 보관된다. Tracker 는 각 버그의 상태, 초기 버그 보고, 버그 보고자와 Emacs 개발자가 작성한 추적(follow-up) 메시지에 관한 정보를 기록한다. 버그는 제목, 심각성, 그 외 기준으로 검색할 수 있다.
    버그 트래커를 웹페이지로 보는 대신 Package Manu 에서 다운로드한
    debugs
    패키지를 이용해 Emacs 에서 확인할 수도 있다(408 페이지의 32장 [패키지(Packages)] 참고). 이 패키지는 버그를 열거하는 M-x debugs-gnu 명령어와 특정 버그를 검색하는 M-x debugs-gnu-search 명령어를 제공한다. Emacs 관리자가 적용한 사용자 태그는 M-x debugs-gnu-usertags 로 표시한다.
  • '
    bug-gnu-emacs
    ' 메일링 리스트('
    gnu.emacs.bug
    ' 뉴스그룹으로도 이용 가능). 리스트 아카이브는 http://lists.gnu.org/mailman/listinfo/bug-gnu-emacs 에서 확인할 수 있다. 이 리스트는 버그 트래커에게 전송되는 추적 메시지와 Emacs 버그 보고를 반영한다. 버스 트래커가 도입(2008년도 초)되기 전의 오래된 버그 보고 역시 포함한다.
    원한다면 리스트를 구독해도 좋다. 리스트는 버그와 기능 요청에 관한 정보를 Emacs 관리자에게 제공하는 데에 목적을 두기 때문에 보고는 꽤 많은 데이터를 포함할 수 있으므로 불평하지 않도록 한다.
  • '
    emacs-pretest-bug
    ' 메일링 리스트. 더 이상 사용되지 않으며 과거에 사용된 내용을 기록한 것이다(historical interest). 한 때는 Emacs 개발 버전에서 (아직 배포되지 않은 버전) 버그 보고에 사용되었다. http://lists.gnu.org/archive/html/emacs-pretest-bug/ 에서 2003년부터 2007년 중반까지 아카이브를 확인할 수 있다. 현재에는 '
    bug-gnu-emacs
    ' 라고도 불린다.
  • '
    emacs-devel
    ' 메일링 리스트. 이 메일링 리스트로 버그를 보고하는 사람들도 있다. 하지만 이것은 그러한 용도의 리스트가 아니므로 버그 리스트로 버그를 보고하는 편이 훨씬 낫다. 버그를 보고하기 전에는 꼭 읽을 필요가 없다.


버그가 발견될 때(When Is There a Bug)

Emacs 가 존재하지 않는 메모리 위치("세그먼테이션 오류(segmentation fault)")로 접근하거나 프로그램에 문제가 있음을 알리는 운영체제 오류 메시지와 함께 종료될 경우 ("디스크 꽉 참(disk full)"과 상반된 문제로 인하여), 이는 확실히 버그에 해당한다.


Emacs 가 버퍼의 내용과 적절하게 들어맞지 않으면 이는 버그다. 하지만 버퍼의 부분을 숨기고 그것이 표시되는 방법을 변경할 수 있는 버퍼 좁히기와 같은 (73 페이지의 11.5절 [좁히기(Narrowing)] 참고) 기능들이 버그의 원인이 아닌지 먼저 확인해야 한다.


명령어를 완료하는 데에 시간이 너무 많이 소요된다면 버그일 수 있지만 정말로 Emacs의 고장인지 확신해야 한다. 일부 명령어는 본래 실행에 시간이 많이 소요될 수도 있다. C-g (MS-DOS에서 C-Break)를 입력하고 C-h l 을 입력하여 Emacs가 수신한 입력 값이 사용자가 입력하려던 값인지 확인하고, 빠르게 처리되어야 하는 값임을 확신하는데도 느리다면 버그를 보고하라. 명령어에 그렇게 많은 시간이 소요되는지 알지 못한다면 매뉴얼을 살펴보거나 도움을 요청하여 알아내도록 한다.


익숙한 명령어가 있을 때 그 정의는 올바르지만 Emacs 오류 메시지를 야기하였다면 버그일 수 있다.


명령어가 잘못된 일을 수행하면 그것은 버그이다. 하지만 해당 명령어가 어떤 일을 수행해야 하는지는 확실히 이해하도록 하라. 익숙하지 않은 명령어의 경우 실제로 명령어는 올바로 일을 처리하고 있는지도 모른다. 의심이 간다면 명령어에 대한 문서를 읽는다(39 페이지의 7.2절 [이름 도움말(Name Help)] 참고).


명령어에 의도된 정의는 편집을 하기에 최적의 정의는 아니다. 매우 중요한 종류의 문제지만 개인의 판단에 좌우되기도 한다. 또한 기존의 기능 일부를 모르는 상태에서 결론을 내리기도 쉽다. 우선 문서를 확인하고 충분히 이해한다고 생각하여 확실히 원하는 바가 없다고 판단될 때까지는 그러한 문제에 대해 불평하지 않는 것이 상책이다. 다른 Emacs 사용자에게 물어도 좋다. 매뉴얼을 주의 깊게 읽은 후에도 명령어가 해야 하는 일을 확실히 이해할 수 없다면 색인과 용어집에서 모호한 용어를 확인한다.


매뉴얼을 주의 깊게 재독한 후에도 명령어가 해야 할 일을 이해하지 못한다면 매뉴얼에서 말하는 버그에 해당하므로 보고해야 한다. 매뉴얼은 당신을 포함해 Emacs 비전문가에게도 모든 것을 분명하게 설명하도록 되어 있다. 문서에 대한 버그에는 프로그램 버그만큼 보고가 중요하다.


함수 또는 변수에 대한 내장된 문서가 매뉴얼의 내용과 상이할 경우 둘 중 하나가 틀린 것이므로 버그에 해당한다.


버그 보고 이해하기(Understanding Bug Reporting)

버그가 있다고 판단되면 유용한 방식으로 보고하는 것이 중요하다. 유용한 방법이란 사용자가 Emacs를 실행하기 위해 사용하는 셸 명령어부터 시작해 문제가 발생할 때까지 어떤 명령어를 입력하는지 정확히 설명하는 것이다.


버그를 보고할 때 가장 중요한 원칙은 사실을 보고하는 것이다. 가정이나 말로 하는 설명이 상세한 raw 데이터를 대신할 수는 없다. 사실을 보고하는 일은 쉽지만 많은 사람들은 사실 대신 해설을 주장하고 보고하려는 압박을 받는다. Emacs가 어떻게 구현되었는지에 대한 짐작을 바탕으로 한 해설은 무용지물이며, 사실이 결여된 보고는 버그에 대한 정보가 전혀 없는 셈이다. 문제를 실제로 디버그(debug)하길 원한다면 짐작보다는 설명을 보고하되 실제 사실을 포함시키길 바란다.


예를 들어 규모가 큰 파일을 열 때 C-x C-f /glorp/baz.ugh RET 을 입력하면 Emacs 가 '

I feel pretty today

' 라고 표시한다고 가정해보자. 버그 보고는 이 정보를 모두 제공할 필요가 있다. 단, 파일의 크기 때문에 문제가 발생한다고 가정하여 "큰 파일을 열었는데 Emacs 가 '

I feel pretty today

' 라고 표시하였다"라고 말해선 안 된다. 이것을 "짐작 해설(guessing explanation)"이라고 부른다. 실제로는 파일명에 '

z

' 가 포함되었다는 사실 때문에 문제가 발생하였을지도 모르기 때문이다. 이런 경우 우리는 당신의 보고를 확인하고 나서 이름에 '

z

' 가 포함되지 않은 "큰 파일"로 문제를 확인하려 하지만 발견하지 못할 것이다. 이름에 '

z

' 가 포함된 파일을 열어봐야 한다는 사실을 짐작할 방도가 전혀 없기 때문이다.


C-x C-f 를 사용했다고 말하는 대신 "파일은 열었다"고 말해서도 안 된다. 마찬가지로 RET A B C RET C-p 라는 텍스트를 입력했다면, "라인에 세 개의 문자가 있을 때"이라고 말하기보다는 "RET A B C RET C-p 를 입력한 후에"라고 말하라.


가능하다면

emacs -Q

를 이용해 Emacs 를 호출하고 (Emacs를 초기 맞춤화 없이 시작하기 위해; 480 페이지의 C.2절 [초기 옵션(Initial Options)] 참고), 버그가 발생하게 된 단계를 그대로 반복함으로써 빠르게 버그를 다시 생성해보라. 이 방식으로 버그가 다시 생성된다면 개인 맞춤화에 버그를 제외시킬 수 있다. 그러면 사용자의 버그 보고는

emacs -Q

로 Emacs 를 시작하였음을 밝히고 버그를 다시 생성시킨 단계를 정확하게 기입하는 것으로 시작되어야 한다.


어떤 버그는

emacs -Q

로 재생성될 수 없으며, 또 어떤 버그는 절대 쉽게 재생성되지 않을 것이다. 그런 경우 자신이 무엇을 갖고 있는지 보고해야 하는데, 그 전에 사용자가 버그를 처음으로 유발시킨 것이 무엇인지에 대한 사실에 집중하길 바란다.


보고하고자 하는 문제가 여러 개인 경우 문제마다 별도의 버그 보고를 만들기 바란다.


버그 보고를 위한 체크리스트(Checklist for Bug Reports)

버그를 보고하기 전에 문제가 이미 보고된 적이 있는지 확인하라(448 페이지의 34.3.1절 [알려진 문제(Known Problems)] 참고).


가능하다면 문제가 이미 수정되었는지 Emacs의 최신 배포판을 시도해본다. 혹은 최신 개발 버전을 시도할 수 있다면 더할 나위가 없겠다. 어떤 사람에게는 이것이 힘든 일이라는 것을 알기에 버그를 보고하기 전에 무조건 이러한 버전을 시도해야 한다는 부담은 느끼지 않아도 된다.


Emacs 에 대한 버그 보고를 작성하는 최선의 방법은 M-x report-emacs-bug 명령어를 사용하는 방법이다. 이는 메일 버퍼를 준비시키고 (350 페이지의 29장 [메일 전송하기(Sending Mail] 참고) 필요한 정보의 일부를 자동으로 삽입한다. 하지만 필요한 정보를 모두 제공하지는 못하므로 사용자가 그 아래 지침서를 읽고 따라야 하며, 메시지를 전송하기 전에 직접 다른 필수 정보를 입력해야 한다. M-x report-emacs-bug 에 의해 삽입되는 정보 중에서 관련이 없는 정보가 있다고 생각할 수도 있겠지만 확실치 않다면 개발자들이 결정하도록 놔두는 편이 낫다.


보고의 작성이 끝나면 C-c C-c 를 입력하여

bug-gnu-emacs@gnu.org

의 Emacs 관리자들에게 전송한다. (개선사항이나 새 기능을 제안하는 경우도 동일한 주소를 사용한다.) Emacs 안에서 메일을 전송할 수 없는 경우 보고의 텍스트를 일반 메일 클라이언트로 복사하여 (시스템이 지원할 경우 C-c M-i 를 입력하면 Emacs가 대신 처리해준다) 해당 주소로 전송한다. 아니면 단순히 문제를 설명하는 이메일을 해당 주소로 전송할 수도 있다.


사용자의 보고는 '

bug-gnu-emacs

' 메일링 리스트로 전송되고, http://debbugs.gnu.org 의 GNU Bug Tracker에 보관된다. 보고에 대한 추가 정보를 요청할지도 모르니 유효한 이메일 답장 주소를 기입하길 바란다. 제출내용은 조정(moderate)되므로 보고가 표시되기까지 지연 시간이 있을 수도 있다.


Gnu Bug Tracker 가 버그를 보고하기 위해 어떻게 작업하는지는 이해할 필요가 없지만 그래도 알고 싶다면 사용할 수 있는 다양한 기능을 트래커의 온라인 문서에서 읽어올 수 있다.


'

bug-gnu-emacs

' 메일링 리스트로 전송되는 모든 메일은 '

gnu.emacs.bug

' 뉴스그룹으로 도달하기도 한다. 뉴스그룹으로 전송되는 메일이 메일링 리스트로 도달하기도 하지만 뉴스그룹을 통해 버그 보고를 발송(또는 답장)하지는 않길 요청한다. 추가 정보를 요청 시 당신에게 연락을 취하기가 훨씬 어려워지며 버그 트래커와 잘 통합되지도 않기 때문이다.


데이터가 500,000 바이트보다 클 경우 버그 보고에 직접 추가하는 대신, 요청 시 전송하겠다고 제시하거나 ftp 에서 이용 가능하게 만들어 위치를 알려주면 된다.


관리자들이 버그를 조사하기 위해서는 버그에 아래의 사항이 포함되어 있어야 한다.

  • Emacs의 버전 번호. 이것이 없이는 현재 GNU Emacs 버전에서 버그를 찾아야 할 이유도 없다.
    M-x report-emacs-bug 는 자동으로 이 정보를 포함하지만 사용자의 보고에 해당 명령어를 사용하지 않는 경우 M-x emacs-version RET 을 입력하여 버전 번호를 얻을 수 있다. 해당 명령어가 작동하지 않으면 GNU Emacs 외에도 사용할 명령어가 있을 것이니 다른 곳에서 버그를 보고해야 할 것이다.
  • 사용 중인 머신 유형과 운영체제 이름 및 버전 번호(역시 M-x report-emacs-bug 에 의해 자동으로 포함된다). M-x emacs-version RET 는 이 정보도 제공한다.
    *Message*
    버퍼의 출력을 복사하여 사용자가 모두 정확하게 수신하도록 한다.
  • Emacs 가 설치될 당시
    configure
    명령어로 주어진 피연산자(자동으로 M-x report-emacs-bug 에 의해 포함됨).
  • Emacs 소스에 대한 전체 수정 목록. (수정되지 않은 Emacs에서 버그가 발생하지 않는 한 버그를 조사할 시간적 여유가 없을지도 모른다. 하지만 사용자가 수정을 하였는데도 알리지 않을 경우 우리 시간까지 낭비할 것이다.)
    이러한 변경 사항은 상세히 알리도록 하라. 영어로 된 설명으로는 부족하니 컨텍스트 diff 를 전송하라.
    사용자의 파일을 추가하거나 다른 머신으로 전송하는 것 역시 소스의 수정으로 간주한다.
  • GNU Emacs 설치를 위한 표준 절차에서 벗어난 사항에 대한 세부적 설명.
  • 버그를 재생성하는 데에 필요한 모든 파일의 텍스트 전문.
    파일을 열지 않고 문제를 야기하는 방법을 알고 있다면 알려주길 바란다. 그렇다면 디버깅이 훨씬 수월해질 것이다. 파일이 필요하다면 정확한 내용을 확인하는 방법을 알려달라. 라인 끝에 공백이 있다거나 버퍼 내 마지막 라인 다음에 개행 문자가 있다는 문제를 예로 들 수 있겠다(마지막 라인이 종료되는지에 대한 여부는 신경 쓰지 않아도 되지만 그와 관련된 버그가 있다면 알려달라).
  • 버그를 다시 생성하기 위해 입력해야 하는 정확한 명령어. 가능하다면 '
    -Q
    ' 옵션으로 Emacs를 시작한 과정을 모두 제공하라(480 페이지의 C.2절 [초기 옵션(Initial Options)] 참고). 이는 개인의 맞춤화를 건너뛴다.
    Emacs에 대한 입력 값을 기록하는 한 가지 방법은 dribble 파일을 작성하는 것이다. 파일을 시작하려면 M-x open-dribble-file RET 명령어를 사용한다. 이후 Emacs는 프로세스가 죽을(kill) 때까지 명시된 dribble 파일로 입력 값을 모두 복사한다. 민감한 정보는 (예: 암호) 결국 dribble 파일에 기록될 것이다.
  • 발생할 가능성이 있는 디스플레이 버그의 경우, 터미널 타입(환경 변수
    TERM
    의 값),
    etc/termcap
    으로부터 터미널에 대한 전체 termcap 엔트리(파일은 모든 머신에서 동일하지 않으므로), 그리고 사실상 Emacs 가 터미널로 전송한 출력 값.
    터미널 출력 값을 수집하는 방법은 M-: 를 사용하거나 Emacs 를 시작한 직후
    *scratch*
    버퍼로부터 Lisp 표현식을 실행하는 것이다.
    (open-termscript "~/termscript")
    
    그때부터 Emacs는 Emacs 프로세스가 죽을 때까지 모든 터미널 출력을 명시된 termscript 파일에도 복사한다. Emacs가 시작할 때 문제가 발생하면 이 표현식을 Emacs 초기화 파일에 넣어 Emacs가 처음으로 화면을 표시하면 termscript 파일이 열리도록 한다.
    경고: 버그를 자극하는 유형의 터미널로 접근하지 않고 터미널에 의존적인 버그를 수정하기란 매우 까다로울 뿐 아니라 때로는 불가능하다.
  • Non-ASCII 텍스트 또는 국제화와 관련이 있다면 사용자가 Emacs를 시작하였을 때 현재 로케일이었던 로케일. GNU/Linux와 Unix 시스템, 혹은 Bash와 같은 Posix-style 셸을 사용 중일 경우 관련된 값을 확인하기 위해 아래의 셸 명령어를 사용할 수 있다:
    echo LC_ALL=$LC_ALL LC_COLLATE=$LC_COLLATE LC_CTYPE=$LC_CTYPE \
      LC_MESSAGES=$LC_MESSAGES LC_TIME=$LC_TIME LANG=$LANG
    
    또는 시스템에
    locale
    명령어가 있을 경우 이것을 이용하여 로케일 설정을 표시한다.
    M-! 를 이용해 Emacs 로부터 이러한 명령어를 실행한 후
    *Messages*
    버퍼로부터 출력을 버그 보고에 복사한다. 혹은 M-x getenv RET LC_ALL RET 을 이용하면 에코 영역에
    LC_ALL
    의 값이 표시될 것이며, 사용자는 그 출력을
    *Messages*
    버퍼로부터 복사할 수 있다.
  • 올바르지 않은 것으로 관찰되는 동작에 대한 설명. 가령 "Emacs 프로세스가 치명적 시그널을 얻는다" 거나 "결과 텍스트가 다음과 같은데 올바르지 않은 것 같다" 는 설명을 예로 들 수 있겠다.
    물론 Emacs가 치명적 시그널을 수신한다는 것이 버그라면 그것을 놓쳐선 안 된다. 하지만 버그가 올바르지 않은 텍스트라면 관리자는 무엇이 잘못되었는지 눈치채지 못할 것이다. 그런 여지를 남길 필요가 뭐 있는가?
    사용자가 경험하는 문제가 치명적 시그널이라 하더라도 여전히 사용자는 그것을 명시적으로 알려야 한다. 소스의 복사본이 동기화되지 않다거나 시스템의 C 라이브러리에서 버그가 보이는 경우처럼 뭔가 이상한 일이 일어나고 있다고 가정하자. (이런 일은 실제로 발생하였다!) 사용자의 복사본은 충돌하는데 우리 복사본은 충돌하지 않을 수 있다. 사용자는 충돌을 예상하라고 말했는데 우리 시스템에서 Emacs가 충돌하지 않게 되면 우리는 버그가 발생한 것이 아니란 결론을 도출할 수 있을 것이다. 그런데 충돌이 예상된다고 말하지 않으면 버그가 발생하고 있었는지 우리가 알 길이 없고 우리 관찰에서는 어떠한 결론도 도출할 수 없을 것이다.
  • Emacs Manual 또는 Emacs Lisp Reference Manual 이 Emacs 의 실제 행위를 설명하지 못한다거나 텍스트가 혼란스럽다는 버그의 경우, 잘못되었다고 생각하는 매뉴얼에서 텍스트를 복사한다. 작은 섹션일 경우 섹션 이름만으로 충분하다.
  • 버그의 발현이 Emacs 오류 메시지일 경우, 오류 메시지의 정확한 텍스트, 그리고 Emacs에서 Lisp 프로그램이 오류에 도달하게 된 상황을 보여주는 backtrace도 함께 보고하는 것이 중요하다.
    오류 메시지 텍스트를 올바로 얻기 위해서는
    *Messages*
    버퍼로부터 버그 보고로 복사한다. 일부가 아니라 모두 복사하도록 한다.
    오류에 대한 backtrace 를 만들기 위해서는 오류가 발생하기 전에 M-x toggle-debug-on-error 를 사용한다(즉 그 명령어를 제공한 후 버그가 발생하도록 만들어야 한다는 말이다). 이로 인해 오류는 Lisp 디버거를 시작하게 만들어 backtrace 를 표시한다. 디버거의 backtrace 의 텍스트를 버그 보고에 복사한다. Edebug 패키지를 이용해 Emacs Lisp 프로그램을 디버깅하는 것과 관련된 정보는 Emacs Lisp Reference Manual 의 "Edebug"절을 참고한다.
    이러한 디버거의 사용은 버그를 다시 발생시키는 방법을 알고 있을 때에만 가능하다. 다시 버그를 발생시키지 못한다면 적어도 전체 오류 메시지를 복사하라.
    Emacs가 무한 루프 또는 매우 긴 연산에 갇힌 경우
    nil
    값이 아닌
    debug-on-quit
    변수와 함께 C-g 를 입력하면 Lisp 디버거가 시작되어 backtrace 를 표시할 것이다. 이러한 backtrace 는 긴 루프의 디버깅에 유용하므로 생성이 가능하다면 버그 보고에 복사한다.
    Emacs에게 C-g 로 응답하게 만들 수 없다면 (예:
    inhibit-quit
    이 설정되었다는 이유로) Emacs 외부로부터
    debug-on-event
    (기본값 SIGUSR2)가 명시한 시그널의 전송을 시도하여 디버거로 들어가도록 야기할 수 있다.
  • 초기화 파일을 포함해 사용자가 Lisp 세계에 로딩시킨 프로그램들이 Emacs의 기능에 영향을 미칠 수 있는 변수를 설정하였는지 확인한다. 또한 프로그램이 당신의 초기화 파일을 로딩하지 않고 새롭게 시작된 Emacs에서 발생하였는지도 확인한다(init 파일의 로딩을 금하려면
    -Q
    스위치로 Emacs 를 시작한다). 이때 문제가 발생하지 않는다면 문제를 발생시키기 위해 Lisp 세계로 로딩시켜야 하는 프로그램의 정확한 내용을 보고해야 한다.
  • Init 파일 또는 표준 Emacs 시스템에 해당하지 않는 Lisp 프로그램에서 문제가 발생하는 경우 관리자에게 먼저 문의하여 그러한 프로그램에서 발생한 버그가 아니라는 사실을 확인해야 한다. 관리자들은 Emacs를 정상적으로 사용하고 있음을 확인한 후 버그를 보고해야 한다.
  • GNU Emacs 소스에서 무언가 언급하고 싶다면 컨텍스트의 라인 몇 개와 함께 코드 라인을 표시한다. 라인 번호만 제시하지 말라.
    개발 소스에서 라인 번호는 사용자의 소스에 있는 라인 번호와 다르다. 당신의 버전에서 주어진 라인 번호에 어떤 코드가 있는지 확인하려면 관리자의 일이 더 늘어날 뿐 아니라 올바른 내용인지 확신할 수도 없다.
  • GDB 와 같은 C 디버거로부터 추가 정보를 활용하면 자신이 이용할 수 없었던 문제를 머신에서 찾을 수 있도록 해준다. GDB 의 사용 방법을 알지 못한다면 GDB 매뉴얼을 읽으면 되는데, 내용이 별로 길지 않기 때문에 GDB 의 사용은 쉽다. 온라인 형태로 된 GDB 매뉴얼을 포함해 GDB 배포판은 Emacs 배포판이 있는 거의 모든 곳에서 찾을 수 있다. GDB 에서 Emacs를 실행하려면 Emacs 가 컴파일된
    src
    하위디렉터리로 전환하여 '
    gdb emacs
    ' 를 실행한다.
    src
    디렉터리가 현재 디렉터리어야만 GDB 는 이 디렉터리에서
    .gdbinit
    파일을 읽을 수 있음을 명심한다.
    하지만 추가 정보를 수집할 때에는 버그를 야기한 내용을 표시하길 원하는지 생각해볼 필요가 있다.
    가령 많은 사람들은 backtrace를 보내는 데에 그치지만 그 자체만으로는 유용하지 못하다. 인자와 함께 단순히 backtrace를 전송하면 GNU Emacs에서 벌어지는 일에 대해서는 거의 전달하지 못하는데, backtrace에 열거된 인자 대부분은 Lisp 객체에 대한 포인터이기 때문이다. 포인터의 수치적 값은 의미가 없으며 중요한 것은 그것이 가리키는 객체의 내용이다(그리고 내용은 대부분 그 자체가 포인터다).
    유용한 정보를 제공하려면 Lisp 객체의 값을 Lisp 표기법으로 표시할 필요가 있다. Lisp 객체에 해당하는 각 값을 스택 하단 근처에 여러 스택 프레임에서 표시하라. 어떤 변수가 Lisp 객체인지는 소스를 확인해야 하는데, 이는 디버거가 그들을 정수로 생각하기 때문이다.
    Lisp 구문에서 변수의 값을 표시하려면 먼저 그 값을 출력한 후 사용자가 정의한 GDB 명령어
    pr
    을 이용해 Lisp 구문에 Lisp 객체를 출력한다. (다른 디버거를 사용해야 한다면 객체를 인자로 하여
    debug_print
    함수를 호출한다.)
    pr
    명령어는
    .gdbinit
    파일에 의해 정의되고, 실행 중인 프로세스를 (코어 덤프가 아니라) 사용자가 디버깅하고 있을 때에만 작동한다.
    Lisp 오류가 Emacs 를 중단시키고 GDB로 돌아가도록 만들기 위해서는
    Fsignal
    에 중단점을 놓는다. 실행 중인 Lisp 함수 목록이 짧은 경우 GDB 명령어인
    xbacktrace
    를 입력한다.
    .gdbinit
    파일은 Lisp 객체의 내용과 데이터 타입을 조사하는 데에 유용한 여러 명령어를 제공한다. 그들의 이름은 '
    x
    ' 로 시작된다. 이러한 명령어들은
    pr
    보다 낮은 수준에서 작업하며 덜 간편하지만
    pr
    이 작동하지 않는 경우, 가령 코어 덤프를 디버깅할 때나 Emacs 가 치명적(fatal) 시그널을 가질 때와 같은 경우에도 작동할 수 있다.
    Emacs 의 디버깅에 대한 상세한 조언이나 그 외 유용한 기법은 Emacs 배포판에 포함된
    etc/DEBUG
    파일에서 찾을 수 있다. 이 파일에는 Emacs 가 응답을 중단하는 문제를 살펴볼 수 있는 지시사항도 포함되어 있다(많은 사람들은 Emacs 가 "hung" 상태라고 추측하지만 사실상 무한 루프인 경우도 있다).
    Emacs 설치판에서
    etc/DEBUG
    파일을 찾으려면
    data-directory
    변수에 저장된 디렉터리명을 사용한다.


버그 보고에 꼭 포함시킬 필요가 없는 사항이 몇 가지 있다:

  • 재생 가능한(reproducible) 버그의 경우 버그 envelope 에 대한 설명은 필요하지 않다. 버그를 경험하는 사람들은 종종 입력 파일에 어떠한 변경 내용이 버그를 사라지게 만드는지, 그리고 어떠한 변경 사항이 버그에 영향을 미치지 않는지를 조사하는 데에 많은 시간을 허비한다.
    이는 시간 소모적이고 유용하지만은 않은 작업으로, 우리는 일련의 예제에서 이론적으로 제하는 것이 아니라 중단점을 이용해 디버거에서 하나의 예제만 실행하여 버그를 발견할 것이기 때문이다. 추가 예제를 검색하지 않아 시간 소모를 줄일 수 있다. 버그 보고를 바로 전송하고 다시 편집으로 돌아가서 보고할 또 다른 버그를 찾는 편이 낫다.
    물론 원본이 아니라 보고할만한 더 간단한 예제를 찾을 수 있다면 편리할 것이다. 출력에 있는 오류는 포착하기가 더 쉽고 디버거에서 실행 시 더 적은 시간이 소요될 것이다.
    하지만 꼭 단순화시킬 필요는 없으므로 이를 실행할 수 없거나 시간이 부족하다면 원본 테스트 케이스로 버그를 보고하도록 한다.
  • 코어 덤프 파일.
    코어 덤프의 디버깅은 유용할지는 모르지만 자신의 Emacs 실행 파일을 이용해 자신의 머신에서만 실행될 수 있다. 따라서 코어 덤프 파일을 Emacs 관리자에게 보내는 것은 유용하지 않다. 무엇보다 이메일 버그 보고에 코어 덤프를 포함시키지 말라! 큰 메시지는 매우 불편하다.
  • Emacs 실행에 대한 시스템 호출 추적(system-call trace).
    시스템 호출 추적은 특정 유형의 특별한 디버깅에 매우 유용하지만 대부분의 경우 유용한 정보를 제공하는 일이 드물다. 따라서 많은 사람들은 충돌에 관한 정보를 보고하는 방식이 시스템 호출 추적을 전송하는 것이라고 생각한다. 이는 소스 코드나 디버깅 심볼이 없는 프로그램을 디버깅한 경험에서 형성된 습관일지도 모른다.
    대부분의 프로그램에서 backtrace 는 주로 시스템 호출 추적보다 훨씬 유용하다. Emacs에서도 일반적으로는 간단한 backtrace가 더 유용하긴 하지만 전체적인 정보를 제공하려면 변수 값을 표시하고
    pr
    을 이용해 (위 내용 참고) 그 값을 Lisp 객체로서 출력함으로써 backtrace를 보완해야 한다.
  • 버그에 대한 패치.
    버그에 대한 패치는 적정한 내용을 가질 때에만 유용하다. 하지만 패치만으로 충분하다고 가정하여 버그 보고에서 필요로 하는 다른 정보, 즉 테스트 케이스와 같은 정보를 빼먹지는 말라. 당신의 패치에서 발생한 문제를 확인하고 다른 방식으로 문제를 수정할 수도 있고, 문제를 전혀 이해하지 못할 수도 있다. 당신이 수정하려는 버그가 무엇인지 혹은 패치가 어떻게 개선사항에 해당하는지 우리가 전혀 이해할 수 없다면 설치해서는 안 될 것이다.
  • 버그가 무엇인지 혹은 버그가 무엇에 의존하는지에 대한 짐작.
    그러한 짐작은 주로 틀린 것이다. 전문가들조차 디버거를 먼저 사용하여 사실을 입증하지 않고서는 그러한 사항에 대해 올바로 짐작할 수가 없다.


GNU Emacs에 대한 패치 전송하기(Sending Patches for GNU Emacs)

GNU Emacs에 대한 버그 수정이나 개선 사항을 써준다면 매우 유용할 것이다. 우선 변경 사항을 전송할 때는 아래의 지침을 따라 관리자들이 사용하기 쉽도록 해줄 것을 부탁한다. 지침을 따르지 않을 시 당신의 정보가 유용하더라도 사용하기까지 추가 작업이 소요될 것이다. GNU Emacs를 유지하는 데에는 최상의 상태에서도 많은 수고가 필요하며, 최선을 다해 도와주지 않으면 우리도 계속하기가 힘들 것이다.

  • 어떠한 문제를 수정하는지 혹은 어떠한 사항이 개선될 것인지에 대해 설명하라. 기존 버그에 대한 수정이라면 'bug-gnu-emacs' 목록과 관련된 논의 또는 http://debbugs.gnu.org 에서 GNU Bug Tracker 내 버그 엔트리에 답을 하는 것이 최선의 방법이다. 왜 그러한 변경 내용이 버그를 수정하는지 설명하라.
  • 수정했다고 생각되는 문제에 대해 적절한 버그 보고를 항상 포함하라. 설치 전에 변경 사항이 올바르다는 사실을 우리 스스로 납득해야 한다. 올바르다 하더라도 문제를 다시 발생시킬 방법이 없다면 이해에 어려움을 겪을 수 있다.
  • 향후에 소스를 읽는 사람들에게 왜 이러한 변경이 필요한지 이해시키기에 적절한 코멘트를 포함시켜라.
  • 여러 용도로 만들어진 변경 사항을 섞지 말라. 개별적으로 전송하라.
    두 가지 이유로 두 가지 변경 사항을 적용한 경우 두 가지를 모두 설치하는 것을 원치 않을 수도 있다. 그 중 하나만 설치하길 원할 수도 있다는 의미다. 이를 하나의 diffs 집합에 모두 합쳐서 전송한다면 둘을 구분하는 데에, 즉 변경 내용의 어떤 부분이 어떤 목적에 맞는지 알아내는 데에 작업이 필요하다. 시간이 충분하지 않을 경우 제시한 변경 사항을 모두 무시할 수도 있다.
    변경 사항을 하나씩 작성하는 즉시 설명과 함께 전송할 경우, 두 가지 변경 사항이 전혀 얽히지 않으므로 둘을 구분하는 데에 수고를 들이지 않고 개별적으로 고려할 수 있다.
  • 변경이 완료되는 즉시 각 변경 사항을 전송한다. 가끔 사람들은 모든 변경 사항을 모아서 한 번에 보내야만 도움이 된다고 생각한다. 앞서 말했듯이 이것은 최악의 행동이다.
    각 변경 사항은 구분하여 전송해야 하므로 하나씩 작성하는 즉시 보내도 상관없다. 중요한 내용이라면 즉시 설치할 수 있는 기회가 되기 때문이다.
  • '
    diff -c
    ' 를 이용해 diffs를 만든다. 컨텍스트가 없는 diffs는 신뢰성 있게 설치하기가 힘들다. 무엇보다 그러한 diffs는 공부하기가 힘든데, 패치를 설치할 것인지 결정하기 위해서는 항상 공부를 먼저 해야 하기 때문이다. Unidiff 포맷은 컨텍스트가 없는 diffs보다 낫지만 '
    -c
    ' 포맷만큼 읽기가 쉽지는 않다.
    GNU diff를 갖고 있다면 C 코드의 diffs를 만들 때 '
    diff -c -F'^[_a-zA-Z0-9$]+ *('
    ' 를 사용한다. 이는 각 변경 사항이 발생한 함수명을 표시한다.
  • 어떤 것이 오래된 버전이고 어떤 것이 새로운 버전인지에 대해 모호성을 피한다. 오래된 버전은 diff에 대한 첫 번째 인자로 만들고, 새로운 버전은 두 번째 인자로 만든다. 또한 버전에는 그것이 오래된 버전인지 혹은 새로 변경된 버전인지를 나타내는 이름을 제공하길 바란다.
  • 변경 사항에 대한 변경 로그 엔트리를 작성한다. 우리가 그것을 작성해야 하는 수고를 덜어주고, 당신이 제시한 변경 사항을 우리가 이해하도록 설명하는 데에 도움이 된다.
    변경 로그의 목적은 변경된 사항을 찾을 곳을 사람들에게 보여주기 위함이다. 따라서 자신이 변경한 함수에 대해 구체적일 필요가 있으며, 큰 함수의 경우 함수 내에서 변경 사항이 위치한 곳을 나타내는 데에 도움이 된다.
    반면 변경 사항을 어디서 찾을 것인지 사람들에게 보여주고 나면 변경 로그에 그 목적을 설명할 필요가 없다. 따라서 새로운 함수를 추가했다면 이제 함수가 새 것이라는 사실만 알려주면 된다. 용도에 대한 설명이 필요하다고 생각된다면 코드 내 주석에 설명을 넣길 바란다. 그곳이 더 유용할 것이다.
    어떤 종류의 정보를 넣을 것인지 확인하고 우리가 어떤 스타일을 사용하는지 학습하기 위해서는 최근 커밋에 대한 변경 로그 엔트리를 살펴본다. 관련 내용은 297 페이지의 25.2절 [변경 로그(Change Log)]를 참고한다.
  • 수정(fix)을 작성할 때에는 다른 시스템을 해칠 수 있는 변경 사항은 우리도 설치할 수 없음을 유념한다. 자신의 변경 사항이 다른 유형의 시스템에 컴파일될 때 가져올 효과에 대해서 생각하길 바란다.
    가끔 사람들은 일반적으로 개선이 될 수 있는 수정을 전송하지만 확신을 갖기는 힘들다. 그러한 변경 사항은 매우 주의 깊게 연구해야 하기 때문에 설치하기가 힘들다. 물론 변경 사항이 올바르다고 결론을 내리게 된 추론을 올바르게 설명한다면 납득하는 데에 도움이 될 것이다.
    가장 안전한 변경 사항은 특정 머신에서 설정 파일에 대한 변경 사항이다. 이들은 다른 머신에서 새로운 버그를 생성할 수 없으므로 안전하다.
    설치에 안전한 형태로 패치를 설계하여 우리가 업무를 계속할 수 있도록 도와주길 바란다.


Emacs 개발에 기여하기 (Contributing to Emacs Development)

Emacs 를 향상시키는 데에 참여하고 싶다면 emacs-devel@gnu.org 를 통해 관리자에게 연락을 취하길 바란다. 타인이 제시한 프로젝트를 요청해도 좋고 자신만의 아이디어를 제시해도 좋다.


이미 작성한 경험이 있다면 알려주길 바란다. 작업을 시작하지 않았다면 시작하기 전에 emacs-devel@gnu.org 로 연락을 취하라. 나머지 Emacs에 더 잘 들어맞는 확장(extension)을 만드는 방법을 제시해줄 수 있다.


Emacs 의 개발 버전은 개발자 집단이 적극적으로 관리하는 저장소에서 다운로드할 수 있다. 상세한 내용은 Emacs 프로젝트 페이지 http://savannah.gnu.org/projects/emacs/ 를 참고한다.


Emacs 에 기여하는 방법에 관한 정보는 Emacs 배포판의

etc/CONTRIBUTE

파일을 참고한다.


GNU Emacs를 이용해 도움을 얻는 방법 (How To Get Help with GNU Emacs)

GNU Emacs의 설치, 사용 또는 변경에 도움이 필요할 경우 두 가지 방법이 있다.

  • help-gnu-emacs@gnu.org 메일링 리스트로 메시지를 보내거나 자신의 요청 사항을 뉴스그룹 gnu.emacs.help에 포스팅해도 좋다. (해당 메일링 리스트와 뉴스그룹은 서로 연결되어 있으므로 어떤 것을 사용하든 상관없다.)
  • 수수료를 지불하고 도움을 줄 사람을 구한다면 서비스 디렉터리를 참고한다 (http://www.fsf.org/resources/service/).


Notes