はじめに
次の業務が C/C++ をつかいそうなので, Emacs で C/C++ 開発環境を構築してみました.
題名は, なぜかけっこうアクセス数のあった Ruby 編にあやかった.
[toc]
IDE が備えるべき機能
優れた IDE が備えるべき機能と Emacs での代表的な実現方法は以下.
- シンタックスハイライト/ インデント
- major-mode
- 検索・置換
- たくさんあるよ.
- タグジャンプ
- gtags
- ggtags
- コード補間
- auto-complete
- company
- エラーチェック
- flymake
- flycheck
- リファクタリング
- emacs-refactor
- インタープリタ・デバッカ
- emacs-dbgr
- プロジェクト管理
- projectile
- ドキュメント参照
- eldoc
最近, 以下の記事を見つけたので, 刺激をうけてまとめた.
Eclipse よりも Emacs が好き
かつて, Eclipse に洗脳されていた若き日の自分は, Eclipse における C/C++ の開発環境を徹底的に調べた.
Emacs と Eclipse どちらが優れているか?
機能的には, 優劣つけがたい. あとは好き嫌いだと思う.
- ゴテゴテの Eclipse の UI が嫌い
- Emacs のテキスト操作における圧倒的優位性
を考慮すると, 今は Emacs のほうが好きだ.
ただ, Emacs は 以下に書くように 設定が大変 なので,
- 導入が面倒なひと
- 初心者
- サラリーマン
は Eclipse CDT でよいのでは??
実際の設定
github の dotfiles のリンクをはっておきます.
- https://github.com/tsu-nera/dotfiles/blob/master/.emacs.d/inits/30_programming.org
- https://github.com/tsu-nera/dotfiles/blob/master/.emacs.d/inits/31_c_cpp.org
major-mode
C 言語・ C++ のためのモード.
cc-mode
C, C++, Objc, Java などなどをいっぺんに設定するモード
マニュアル.
c-mode-common-hook は java にも適用されてしまうようだ.
(require 'cc-mode)
;; c-mode-common-hook は C/C++ の設定
(add-hook 'c-mode-common-hook
(lambda ()
(setq c-default-style "k&r") ;; カーニハン・リッチースタイル
(setq indent-tabs-mode nil) ;; タブは利用しない
(setq c-basic-offset 2) ;; indent は 2 スペース
))
c++-mode
C++ 言語固有設定.
以下の記述でヘッダファイルが c++ として認識される.
(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
Error Check
今は, flymake よりも, flycheck でしょう.
flycheck
gcc, clnag, cppcheck が default のチェッカーとして用意されている.
参考: 今は自分で定義しなくても build-in されているよう.
- https://github.com/jedrz/.emacs.d/blob/master/setup-flycheck.el
- Emacs - flycheck で C/C++ のエラーチェック定義を追加する - Qiita
(add-hook 'c-mode-common-hook 'flycheck-mode)
- checker の変更は M-x flycheck-select-checker
- helm-flycheck で helm i/f から エラーを選択.
gcc
gcc だとなにも検出してくれない.なんでだろう. -> 結果が日本語表示だったから
(defmacro flycheck-define-clike-checker (name command modes)
`(flycheck-define-checker ,(intern (format "%s" name))
,(format "A %s checker using %s" name (car command))
:command (,@command source-inplace)
:error-patterns
((warning line-start (file-name) ":" line ":" column ": 警告:" (message) line-end)
(error line-start (file-name) ":" line ":" column ": エラー:" (message) line-end))
:modes ',modes))
(flycheck-define-clike-checker c-gcc-ja
("gcc" "-fsyntax-only" "-Wall" "-Wextra")
c-mode)
(add-to-list 'flycheck-checkers 'c-gcc-ja)
(flycheck-define-clike-checker c++-g++-ja
("g++" "-fsyntax-only" "-Wall" "-Wextra" "-std=c++11")
c++-mode)
(add-to-list 'flycheck-checkers 'c++-g++-ja)
Refactoring
semantic-refactoring
Semantic Refactor is a refactoring tool for C/C++.
ついに見つけた, extract method. menu で番号を選択するとバグっているので, Enter で選択.(そのうちなおるかと)
(require 'srefactor)
(define-key c-mode-map (kbd "M-RET") 'srefactor-refactor-at-point)
(define-key c++-mode-map (kbd "M-RET") 'srefactor-refactor-at-point)
Completion
auto-complete-c-headers
ヘッダの情報源
(require 'auto-complete-c-headers)
(add-hook 'c++-mode-hook '(setq ac-sources (append ac-sources '(ac-source-c-headers))))
(add-hook 'c-mode-hook '(setq ac-sources (append ac-sources '(ac-source-c-headers))))
clang-complete-async
clang を利用した 補完. 構造体とかもばっちり!
(require 'auto-complete-clang-async)
(defun ac-cc-mode-setup ()
(setq ac-clang-complete-executable "~/.emacs.d/el-get/repo/clang-complete-async/clang-complete")
(setq ac-sources (append ac-sources '(ac-source-clang-async)))
(ac-clang-launch-completion-process))
(defun my-ac-config ()
(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)
function-args
C/C++ 用の 補完. CEDET のモダンな置き換え.
moo-complete で構造体やクラス変数が置換できるのがうれしい.
- M-o moo-complete semantic な補完
- M-i fa-show 関数ヒントをポップアップ
- M-j fa-jump-maybe ポップアップ状態でオスとジャンプ
- moo-propose-overide オーバーライドを suggest
- moo-propose-variable 変数を suggest
(require 'function-args)
(fa-config-default)
(define-key function-args-mode-map (kbd "M-o") nil)
(define-key c-mode-map (kbd "C-M-:") 'moo-complete)
(define-key c++-mode-map (kbd "C-M-:") 'moo-complete)
(custom-set-faces
'(fa-face-hint ((t (:background "#3f3f3f" :foreground "#ffffff"))))
'(fa-face-hint-bold ((t (:background "#3f3f3f" :weight bold))))
'(fa-face-semi ((t (:background "#3f3f3f" :foreground "#ffffff" :weight bold))))
'(fa-face-type ((t (:inherit (quote font-lock-type-face) :background "#3f3f3f"))))
'(fa-face-type-bold ((t (:inherit (quote font-lock-type-face) :background "#999999" :bold t)))))
rtags
clang をつかった便利機能詰め合わせ.
設定が大変そうだな.. これは今回は挫折.
fixit って, 自動エラー修正? スゴそう.
Document
ggtags
ggtags も c 言語ように eldoc 機能を提供している. ggtags は後述.
c-eldoc
C 言語用 eldoc 機能.
(require 'c-eldoc)
(add-hook 'c-mode-hook 'c-turn-on-eldoc-mode)
(add-hook 'c++-mode-hook 'c-turn-on-eldoc-mode)
(setq c-eldoc-buffer-regenerate-time 60)
Debugger
gdb
M-x gdb 標準搭載.
emacs-dbgr
デバッグ用 統一 I/F M-x realgud:gdb
gdb との違いはよくわからない.
(require 'realgud)
その他
タグジャンプ
ggtags
タグジャンプ用のツール. GNU Global を利用.
(require 'ggtags)
(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode 'asm-mode)
(ggtags-mode 1))))
;; use helm
(setq ggtags-completing-read-function nil)
;; use eldoc
(setq-local eldoc-documentation-function #'ggtags-eldoc-function)
;; imenu
(setq-local imenu-create-index-function #'ggtags-build-imenu-index)
(define-key ggtags-mode-map (kbd "C-c g s") 'ggtags-find-other-symbol)
(define-key ggtags-mode-map (kbd "C-c g h") 'ggtags-view-tag-history)
(define-key ggtags-mode-map (kbd "C-c g r") 'ggtags-find-reference)
(define-key ggtags-mode-map (kbd "C-c g f") 'ggtags-find-file)
(define-key ggtags-mode-map (kbd "C-c g c") 'ggtags-create-tags)
(define-key ggtags-mode-map (kbd "C-c g u") 'ggtags-update-tags)
(define-key ggtags-mode-map (kbd "M-,") 'pop-tag-mark)
helm-gtags
helm I/F を利用した gtags 操作. 自分は ggtags をつかってる.
projectile
プロジェクト管理用の デファクトスタンダード.
自動でプロジェクトのルートディレクトリを探して, それ以下のファイルを見つけたり色々できる.
.projectile ファイルをマニュアルで作成することで, そのフォルダを Route Folder と認識出来る.(要 Emacs 再起動)
(require 'projectile)
(projectile-global-mode)
;; windows indexing 高速化のおまじない.
(setq projectile-indexing-method 'alien)
;; 大きいプロジェクトだと劇的に速度が改善するらしい.
(setq projectile-enable-caching t)
GNU Global と組み合わせるには, ggtags が必要.(gtags ではないので注意)
以下で GTAGS を作成.
- projectile-regenerate-tags
(when (executable-find "gtags")
(setq projectile-tags-file-name "GTAGS")
(setq projectile-tags-command "gtags")))
helm-make
C 言語といったら make でしょう. make 用 helm I/F.
(require 'helm-make)
(eval-after-load 'makefile-mode
'(define-key makefile-mode-map (kbd "M-\"") 'helm-make-projectile))
(define-key c-mode-map (kbd "M-\"") 'helm-make-projectile)
(define-key c++-mode-map (kbd "M-\"") 'helm-make-projectile)