Emacs で C/C++ の開発環境をめちゃガチャパワーアップしたまとめ

    はじめに

    次の業務が 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