Windows上のNTEmacsでC++を書くための設定をしました

"EmacsをVisualStudioみたいにしてやるぜ!"って書くとビッグマウスが過ぎる気がしたので地味なタイトルにしたのですが、目指すところはそこです。

Windows + cygwin + NTEmacsでやっていきます。

お品書き

  • 下準備 NTEmacsとauto-install.elとcygwin
  • auto-complete-clang-async.elで補完
  • c-eldocで関数とかの宣言を見る
  • gtagsで関数の定義にジャンプ
  • flymakeで文法チェック
  • smart-compileで簡単コンパイル
  • GDBデバッグ

下準備 NTEmacsとauto-install.elとcygwin

http://sourceforge.jp/projects/gnupack/releases/?package_id=10839
からemacsの最新バージョンをダウンロードして解凍して適当なところにおいてください(2013/03/03現在emacs-24.2-20121208.exe)。

bin/runemacs.exeからemacsを実行できます。

なくても良いのですがあると便利なのでauto-install.elをインストールします。

http://www.emacswiki.org/emacs/download/auto-install.el
からauto-install.elをダウンロードして~/.emacs.d/site-lisp/においてください。
(フォルダがなければ作成してください)

次に~/.emacsに以下を追加してください。
(なければ作成してください)

(add-to-list 'load-path "~/.emacs.d/site-lisp/")
(add-to-list 'load-path "~/.emacs.d/auto-install/")
(require 'auto-install)

あとcygwinも使うのでインストールしてcygwin/binにパスを通しておいてくださいね。

auto-complete-clang-async.elで補完

EmacsにおけるC++の補完は、ちゃんとソースを解析して候補を出してくれるものに限ると多分clangとgccsenseの2つしかないと思います。

一応CEDETもあるけど、なんか巨大なうえになんかよくわからんというか。。。 以前試してみたけど全く動かせなかったのでとりあえず今回は却下としておきます。ひい。

gccsenseはDebianで動かせて良い感じだったのですが、Windowsでは(僕は)動かすことが出来なかったので今回は却下です。
(VMWareDebianを入れてsshで接続して... 見たいな事も試しましたがいちいちVMを立ち上げるのがめんどくさくてやめました)

clangはauto-complete-clang.elというものがあったので以前試してみたのですが、僕の貧弱な環境だと遅くて使い物にならない感じでした。

auto-complete-clang-async.elは補完候補を非同期で集めてくれるんだと思います。しらんけど。

とにかくこれが僕の環境でも使えるくらいにははやかったのでこれを採用することにします。

参考URL
http://boronology.blogspot.jp/2012/09/emacscemacs-clang-complete-async.html

まず、auto-complete.elをインストールします。

M-x auto-install-batch auto-complete development version

~/.emacs.d/site-lisp/ac-dictフォルダを作成しておいてください。

.emacsに以下を追加します。

;; auto-complete
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/site-lisp/ac-dict")
(ac-config-default)

次に、LLVMとclangをインストールします。

cygwinインストーラllvmとclangで検索にひっかかったものをとりあえず全部インストールしてください。

最後にemacs-clang-complete-asyncをインストールします。

$ git clone git://github.com/Golevka/emacs-clang-complete-async.git
$ cd emacs-clang-complete-async
$ make

を実行して作成されたclang-complete.exeをパスの通ったフォルダにおいてください。そして、auto-complete-clang-async.elを~/.emacs.d/site-lisp/においてください。そして、以下を.emacsに追加するのです。

;; auto-complete-clang-async
(require 'auto-complete-clang-async)

(defun ac-cc-mode-setup ()
  (setq ac-clang-complete-executable "~/.emacs.d/site-lisp/clang-complete")
  (setq ac-sources '(ac-source-clang-async))
  (ac-clang-launch-completion-process)
)

(defun my-ac-config ()
  (global-set-key "\M-/" 'ac-start)
  ;; C-n/C-p で候補を選択
  (define-key ac-complete-mode-map "\C-n" 'ac-next)
  (define-key ac-complete-mode-map "\C-p" 'ac-previous)

  (add-hook 'c-mode-common-hook 'ac-cc-mode-setup)
  (add-hook 'auto-complete-mode-hook 'ac-common-setup)
  (global-auto-complete-mode t))

(my-ac-config)

これで、

vector<int> v;
v.

みたいなコードを書くと補完候補を出してくれます。

関数を補完したときに引数が勝手に入っちゃってたりとか、親クラスの関数を補完しようとするとへんなのがくっついちゃったりとかして挙動が微妙なとこが何点かありますが今後に期待というかんじでしょうか。

c-eldocで関数とかの宣言を見る

たまにしか使わない関数の引数とか覚えてるわけないですよね。

何をしてくれる関数か分かっていて、引数の順番が分からないだけなのにいちいちドキュメントを引くのもめんどうですよね。

ということでeldocです。

以下のSSを見れば何をしてくれるか分かると思います。

参考URL
http://d.hatena.ne.jp/mooz/20100421/p1

インストール方法は以下です。

M-x auto-install-from-emacswiki c-eldoc.el

でc-eldoc.elを入手します。

そして、以下を.emacsに追加します。

;; c-eldoc
; コマンドを/bin/cpp から変更
(setq c-eldoc-cpp-command "C:\\cygwin\\bin\\cpp-3 ")

(load "c-eldoc")
(setq c-eldoc-includes "-I./ -I../ ")
(add-hook 'c-mode-hook 'c-turn-on-eldoc-mode)
(add-hook 'c++-mode-hook
	  (lambda ()
	    (set (make-local-variable 'eldoc-idle-delay) 0.20)
	    (c-turn-on-eldoc-mode)))

注意が必要なのが、cppのパスを変更すること(とcpp-3の後にちゃんとスペースを入れること!)と、cpp-3の(Windows的な意味での)実行権限を自分に与えておくことです。cpp-3.exeのプロパティから設定しておいてください。

gtagsで関数の定義にジャンプ

"この関数の定義を見たい!"ってときはよくありますよね。grepかけても良いですがいちいち面倒ですよね。
そこでgtags(GNU Global)です。

参考URL
http://cha.la.coocan.jp/doc/gnu_global.html
http://qiita.com/items/d9e686d2f2a092321e34

まず以下からバイナリを落としてきます。
http://adoxa.3eeweb.com/global/index.html

解凍してパスが通ったフォルダにおいといてください。

次に、gtags.elを落としてきます。

M-x auto-install-from-url https://raw.github.com/voins/gtags/master/gtags.el

ほんで.emacsに以下を追加します。

; GTAGS
;--- GNU GLOBAL(gtags) gtags.el ---

(require 'gtags)

(global-set-key "\C-o" 'gtags-find-tag)     ;関数の定義元へ
(global-set-key "\M-r" 'gtags-find-rtag)    ;関数の参照先へ
(global-set-key "\M-s" 'gtags-find-symbol)  ;変数の定義元/参照先へ
(global-set-key "\C-cp" 'gtags-find-pattern)
(global-set-key "\C-cf" 'gtags-find-file)    ;ファイルにジャンプ
(global-set-key "\M-o" 'gtags-pop-stack)   ;前のバッファに戻る

;; update GTAGS
(defun update-gtags (&optional prefix)
  (interactive "P")
  (let ((rootdir (gtags-get-rootpath))
        (args (if prefix "-v" "-iv")))
    (when rootdir
      (let* ((default-directory rootdir)
             (buffer (get-buffer-create "*update GTAGS*")))
        (save-excursion
          (set-buffer buffer)
          (erase-buffer)
          (let ((result (process-file "gtags" nil buffer nil args)))
            (if (= 0 result)
                (message "GTAGS successfully updated.")
              (message "update GTAGS error with exit status %d" result))))))))
(add-hook 'after-save-hook 'update-gtags)

(add-hook 
 'c-mode-common-hook 
 '(lambda()
    (gtags-mode 1)))

gtagsは"どのファイルの何行目に関数hogehogeの定義がある"みたいな情報をまとめたファイル(タグファイル)をあらかじめ作成しておいて、
"hogehogeどこー?"って言われたときにそのタグファイルから関数の定義位置をかえす、みたいなことをするので、ファイルを書き換えたら
タグファイルを更新してやらなければなりません。手動でやるのは面倒ですが、この設定だとファイル保存時に自動で更新してくれます。

flymakeで文法チェック

セミコロンを付け忘れたとか、閉じ括弧が一個足りなかったとか、そういうしょうもないミスでコンパイルが失敗するのはめんどくさいですよね。

flymakeは文法エラーをその都度教えてくれます。

参考URL
http://d.hatena.ne.jp/suztomo/20080905/1220633281

インストール方法は以下です。

.emacsに以下を追加します。

;; flymake
(require 'flymake)

(defun flymake-cc-init ()
  (let* ((temp-file   (flymake-init-create-temp-buffer-copy
                       'flymake-create-temp-inplace))
         (local-file  (file-relative-name
                       temp-file
                       (file-name-directory buffer-file-name))))
    ; g++ を g++-4に変更
    (list "g++-4" (list "-Wall" "-Wextra" "-fsyntax-only" local-file))))

(push '("\\.cpp$" flymake-cc-init) flymake-allowed-file-name-masks)

(add-hook 'c++-mode-hook
          '(lambda ()
             (flymake-mode t)))

これも同様にg++-4の実行権限を追加しておいてください。

flymake自体はemacsに含まれているのでauto-installとかはしなくても大丈夫です。

smart-compileで簡単コンパイル

ある程度の規模のプロジェクトであればちゃんとしたMakefileとかを作ると思うので

M-x compile

コンパイルできるのですが、ちょっとしたテストコードとかだとこうはいかないので、わざわざ端末から

g++ hoge.cpp -o hoge & ./hoge

見たいな事をしなきゃいけません。

これを一発でやりたいなというのをかなえてくれるのがsmart-compile.elです。

インストールは以下です。

auto-install-from-emacswiki smart-compile.el

そして以下を.emacsに追加します。

;; smart-compile
(require 'smart-compile)

(setq smart-compile-alist '(
  (emacs-lisp-mode    . (emacs-lisp-byte-compile))
  (html-mode          . (browse-url-of-buffer))
  (nxhtml-mode        . (browse-url-of-buffer))
  (html-helper-mode   . (browse-url-of-buffer))
  (octave-mode        . (run-octave))
  ("\\.c\\'"          . "gcc -O2 %f -lm -o %n")
;;  ("\\.c\\'"          . "gcc -O2 %f -lm -o %n && ./%n")
  ("\\.[Cc]+[Pp]*\\'" . "g++-4 -O2 %f -lm -o %n && %n.exe")
;;  ("\\.[Cc]+[Pp]*\\'" . "g++ -O2 %f -lm -o %n")
  ("\\.m\\'"          . "gcc -O2 %f -lobjc -lpthread -o %n")
  ("\\.java\\'"       . "javac %f")
  ("\\.php\\'"        . "php -l %f")
  ("\\.f90\\'"        . "gfortran %f -o %n")
  ("\\.[Ff]\\'"       . "gfortran %f -o %n")
  ("\\.cron\\(tab\\)?\\'" . "crontab %f")
  ("\\.tex\\'"        . (tex-file))
  ("\\.texi\\'"       . "makeinfo %f")
  ("\\.mp\\'"         . "mptopdf %f")
  ("\\.pl\\'"         . "perl -cw %f")
  ("\\.rb\\'"         . "ruby -cw %f")))
(global-set-key (kbd "C-x C-x") 'smart-compile)

こうしておくとC-x C-xと入力することでコンパイルと実行が出来ます。
デバッガにかけたいときとかはC-x C-xのあとにミニバッファに表示されるコマンドをいじくってやればよいでしょう。

GDBデバッグ

デバッガなしで開発をするっていうのは、結構厳しいものがあると思います。

参考URL
http://d.hatena.ne.jp/higepon/20090505/p1

higepon先生の設定をまるパクリさせてもらえば良いと思います。

;;; GDB 関連
;;; 有用なバッファを開くモード
(setq gdb-many-windows t)

;;; 変数の上にマウスカーソルを置くと値を表示
(add-hook 'gdb-mode-hook '(lambda () (gud-tooltip-mode t)))

;;; I/O バッファを表示
(setq gdb-use-separate-io-buffer t)

;;; t にすると mini buffer に値が表示される
(setq gud-tooltip-echo-area nil)

まとめ

ここまでやるとそれなりには、"VisualStudioっぽい"感じというか、IDEでよくある機能をEmacsでも実現できると思います。
何点か微妙な部分もありますが、僕はおおむね満足しています。

意図的に扱わなかった内容として、

があります。
プロジェクト管理はeproject.elとか使えばよさそうだったのですが、プロジェクト内検索をうまくやる方法が良く分からなかったので扱いませんでした。
(anything-project.elがよさそうだったのですが、ackに依存していて、Windowsコマンドプロンプトからうまくackを呼べなかったので使えませんでした。)
とりあえずは、moccur-grep-findとか使えばいいとおもいます。

リファクタリングツールは、そもそもフリーのものが見つけられなかったので扱いませんでした。