자동 byte-compile 설정
이맥스에서도 ELISP 코드를 byte-compile해서 코드 성능을 향상 시킬 수 있다. Performance of Byte-Compiled Code를 읽어 보면 엄청나다고 광을 팔고 있긴 하지만, 사실 실 사용에서 그 정도까지 성능 향상이 되긴 어렵지 않을까 싶긴 한데 그래도 해 두면 일정 수준은 성능 향상을 기대 할 수 있긴 하다. 다만 설정 파일을 한번 만들어 놓고 나서 몇 주 동안 수정하지 않는 사람이라면 몰라도, 설정 파일을 모듈 별로 나눠 놓고 조금씩이나마 계속 하루에 한 번 이상은 이것 저것 건드려 대는 나 같은 사람이 설정파일 몇 줄 고치고 나서 byte-compile을 매번 일일히 하기에는 엄청나게 귀차니즘이 동반되기 때문에 사실상 손수 byte-compile을 한다는 건 불가능에 가깝지 않나 생각을 한다.
일단 여러 설정 파일들을 자동으로 byte-compile 하기 위해 아래와 같은 함수를 만든다
(defconst my:byte-compile-path '( "~/.emacs.d" "~/.emacs.d/utils" )) (defun my:byte-compile-updated () "Compile updated init files." (interactive) (dolist (dir my:byte-compile-path) (if (file-exists-p dir) (dolist (file (directory-files dir)) (when (string-match "\\.el\\'" file) (let* ((src (concat dir "/" file)) (target (concat src "c"))) (unless (and (file-exists-p target) (file-newer-than-file-p target src)) (byte-compile-file src))))))))
지정해 준 경로의 ELISP 파일을 찾아 byte-compile 된 것과 modified time 비교를 해서 ELISP 파일이 지난 번 byte-compile 때 이후로 변경되었다면 byte-compile-file을 호출해 준다. .emacs.d아래에는 내가 작성한 설정 파일 외에도 패키지 매니저를 통해 설치한 파일들도 많으므로 (그리고 그건 보통 설치시에 byte compile 해 놓고 건드리지 않으므로) 그냥 recursive하게 .emacs.d 아래의 ELISP 파일을 byte-compile 하는 것 보단 일일히 지정하는 편을 택했지만, 굳이 recursive 하게 하려면 아래와 같이 변형해 주면 된다.
(defun my:byte-compile-updated-recursively (&optional dir-input) "Compile updated init files." (interactive (list (read-directory-name "Directory: " "~/.emacs.d"))) (let ((dir (or dir-input "~/.emacs.d"))) (dolist (file (and (file-directory-p dir) (directory-files dir))) (if (and (file-directory-p (concat dir "/" file)) (not (member file '("." "..")))) (my:byte-compile-updated-recursively (concat dir "/" file)) (when (string-match "\\.el\\'" file) (let* ((src (concat dir "/" file)) (target (concat src "c"))) (unless (and (file-exists-p target) (file-newer-than-file-p target src)) (byte-compile-file src))))))))
...만, 애초에 recursive하게 할 거면 이 짓을 할 필요 가 없이 byte-recompile-directory 함수를 쓰면 된다.
이제 이 함수를 언제 호출할 것인가가 관건인데, 내가 생각하는 가장 적절한 타이밍은 역시 이맥스를 종료할 때 인 것 같다. kill-emacs-hook에 hook을 추가 해 주자.
(add-hook 'kill-emacs-hook 'my:byte-compile-updated)
이제 종료할 때 지정된 디렉토리에서 업데이트 된 ELISP 파일이 있으면 자동으로 업데이트 해 줄 것이다. 다만 이런 설정을 했을 때 문제점은 이맥스를 시작 하다가 my:byte-compile-updated이 evaluation 되기 전에 어떤 ELISP코드에서 에러가 날 경우, 에러를 수정해서 저장하고 종료하더라도 종료시에 수정된 사항을 반영하여 byte-compile을 다시하지 않을 것이므로 다음번 이맥스 시작시에 실제로 수정 사항이 반영되지 않는다는 점이다. 이 이유는 이맥스가 byte-compile된 .elc 파일이 존재할 경우 modification time에 상관 없이 우선적으로 byte-compile 된 파일을 읽어들이기 때문으로, 이 때는 수동으로 .elc을 지워줘야 하는 번거로움이 있긴 했다.
그래서 예전에는 위의 byte-compile 함수나 hook 설정을 설정 파일 초반에 넣어서 코드가 무조건 evaluation 되게 만들어 종료시에 byte-compile을 꼭 하도록 하는 방식으로 위와 같이 꼬이는 문제를 해결했지만, 다행히 GNU Emacs 24.4 이후로 load-prefer-newer라는 변수가 추가 되었는데 이 변수를 non-nil로 세팅해 주면, load나 require 함수를 호출해서 ELISP 파일을 로딩할 때 .elc가 존재하더라도 .el 파일의 수정일이 더 나중이라면 이 쪽을 로딩하도록 해 준다. 물론 변수 설정은 실제 라이브러리 로딩 하는 부분 이전에 세팅해줘야 하겠지만 어쨌든 이걸 쓰면 위의 문제는 해결된다.
'Emacs' 카테고리의 다른 글
Emacs의 ansi color 설정 (0) | 2016.03.07 |
---|---|
auto-complete-c-headers 설정 (1) | 2016.03.03 |
Emacsclient의 활용 (0) | 2016.03.02 |
Trailing white spaces 표시 하기 (0) | 2016.03.02 |
Emacs를 쓰고 싶지만 허들이 높아 보이는 사람들을 위한 조언 (0) | 2015.07.27 |