はじめに

次の業務が 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 のリンクをはっておきます.

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 されているよう.


(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)

Special Thanks