Emacs as C++ IDE

The C++ IDE environment in Emacs is configured mainly:

  • using irony-mode and gtags;
  • and, using company as auto-completion engine.

Requirements

install software in OS

  1. use pip to install cpplint for google-cpp-style

  2. have cmake installed

  3. install clang/LLVM and compile irony-server

    • install LLVM by brew install llvm
    • compile irony-server as follows:

      • make a clean build directory
      • run

        1
        cmake -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/5.0.0/ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON ~/.emacs.d/elpa/   irony-20170828.1218/server/
      • build and run make && ./bin/irony-server --version

      • copy ./bin/irony-server under your .emacs.d/bin

install packages in emacs

Adding a header for the exported .el file.

; =====================================================
;; Programming Environment for C/C++ (modern)
; =====================================================

Install the additional packages to support the modern C/C++ environment.

;; check and install essential pkgs
(setq custom/modern-cc-packages
      '(irony
        company-irony
        company-irony-c-headers
        flycheck-irony
        irony-eldoc
        helm-make))
(custom/install-packages custom/modern-cc-packages)

(Notes: the old script used before rewriting custom/install-packages)

(unless (custom/packages-installed-p custom/modern-cc-packages)
  (package-refresh-contents)
  (dolist (pkg custom/modern-cc-packages)
    (unless (package-installed-p pkg)
      (package-install pkg))))

C++ Coding styles

Default style for C/C++

(require 'cc-mode)
(setq-default c-default-style "linux")
(setq-default c-basic-offset 4)

Basic edit enhancement for C/C++

  1. Auto insert pair of symbols using smartparens

    Install smartparens mode and enable it by (require 'smartparens), which has been enabled in .emacs globally.

    ;; /smartparens/: insert pair of symbols
    ;; when you press RET, the curly braces automatically add another newline
    (sp-with-modes '(c-mode c++-mode)
      (sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET")))
      (sp-local-pair "/*" "*/" :post-handlers '(("| " "SPC") ("* ||\n[i]" "RET"))))
    

Google C++ style and its flymake checker

Install google-c-style and flymake-google-cpplint. You also need to install Python package cpplint by pip.

;; /google-c-style/ and /flymake-google-cpplint/ style checker
(when y:enable-google-cpp-style
  (require 'google-c-style)
  (add-hook 'c-mode-common-hook 'google-set-c-style)
  (add-hook 'c-mode-common-hook 'google-make-newline-indent)
  (defun y:flymake-google-init ()
    (require 'flymake-google-cpplint)
    (setq flymake-google-cpplint-command
      (if (string-equal system-type "darwin")
          "/usr/local/bin/cpplint" "/usr/bin/cpplint"))
    (flymake-google-cpplint-load))
  (add-hook 'c-mode-hook 'y:flymake-google-init)
  (add-hook 'c++-mode-hook 'y:flymake-google-init))

Source code navigation using gtags

See emacs-init-gtags.el, which also supports tag-based code navigation of other languages.

Source code completion using irony

Prerequisites (For Mac OS X)

Download a pre-compiled package from llvm.org to install irony-server. (change the 4.0.1 version with the latest (the greatest!))

  • Download clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz from http://llvm.org/releases/download.html

  • Extract it somewhere (e.g: ~/Programs/) (Warning: you need to keep it on your computer to allow irony-server to work!)

  • make a clean build directory (e.g. cd ~/tmp && mkdir build && cd build)

  • run

1
cmake -DCMAKE_PREFIX_PATH=/Users/oracleyue/Programs/clang+llvm-4.0.1-x86_64-apple-macosx10.9.0/ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON /Users/oracleyue/.emacs.d/elpa/irony-20170828.1218/server/
  • build and run make && ./bin/irony-server --version

  • cp irony-server to your .emacs.d/bin/

Setup

Install irony-mode from MELPA and add the following to your emacs init file:

;; /irony/+/company-irony/: code completions
(add-hook 'c++-mode-hook 'irony-mode)
(add-hook 'c-mode-hook 'irony-mode)
(add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options)

(setq irony--server-executable (expand-file-name "~/.emacs.d/bin/irony-server"))
(add-to-list 'irony-additional-clang-options "-std=c++11")

NOTE: Like RTags, Irony requires a compilation database. To create one run the following:

$ cd /path/to/project/root
$ cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=1

The first time you run irony you must install the irony-server by runing the command: M-x irony-install-server.

Using Company with Irony

To use company-mode with Irony, install company-irony from melpa and add the following to your emacs init file:

(add-hook 'irony-mode-hook 'company-irony-setup-begin-commands)
(setq company-backends (delete 'company-semantic company-backends))
;; (eval-after-load 'company
;;   '(add-to-list 'company-backends 'company-irony))

Header file completion with company-irony-c-headers

To add support for completing C++ headers:

  • Install company-irony-c-headers from MELPA
  • Remove the following to your emacs init file:

    (eval-after-load 'company
      '(add-to-list 'company-backends 'company-irony))
    
  • Add the following to your emacs init file:

    (require 'company-irony-c-headers)
    (defun y:add-company-backend-irony ()
      (setq-local company-backends
                  (append '((company-irony-c-headers company-irony))
                          company-backends)))
    (add-hook 'c-mode-hook 'y:add-company-backend-irony)
    (add-hook 'c++-mode-hook 'y:add-company-backend-irony)
    

Show eldoc for C/C++ mode via irony (disabled)

Enable the minor mode irony-eldoc, as well as eldoc-mode. For an example, place point on top of a symbol, or inside a function call.

(add-hook 'irony-mode-hook #'irony-eldoc)

Auto-generate .clang_complete

.clang_complete - A file at the root of your project containing the compilation flags, one per line.

To generate the .clang_complete file automatically, we use cc_args.py, which has a copy in your ~/.emacs.d/git/. Copy it to the folder in your PATH search paths. Then, in your build folder, e.g. <your-project-root>/build,

  • run CXX='cc_args.py g++' cmake ..
  • run make and then you find .clang_complete under your build folder.
  • copy it to your project root.

Syntax checking with Flycheck

Prerequisites

Install flycheck from MELPA and add the following to your emacs init file:

;; /flycheck/: syntax checker
(add-hook 'c++-mode-hook 'flycheck-mode)
(add-hook 'c-mode-hook 'flycheck-mode)

Integrating RTags with Flycheck (disabled)

To enable RTags and flycheck integration add the following to your emacs init file:

(require 'flycheck-rtags)

(defun my-flycheck-rtags-setup ()
  (flycheck-select-checker 'rtags)
  (setq-local flycheck-highlighting-mode nil) ;; RTags creates more accurate overlays.
  (setq-local flycheck-check-syntax-automatically nil))
;; c-mode-common-hook is also called by c++-mode
(add-hook 'c-mode-common-hook #'my-flycheck-rtags-setup)

Integrating Irony with Flycheck

Install flycheck-irony from MELPA and add the following to your emacs init file:

(eval-after-load 'flycheck
  '(add-hook 'flycheck-mode-hook #'flycheck-irony-setup))

Keybindings

  • C-c ! n and C-c ! p: jump to next or previous errors
  • C-c ! l: list errors
  • C-c ! c: menually run checker

More supports for C/C++ programming

Compilation supports for C/C++, cmake and makefile

Install helm-make package, and setup as below. To compile the whole project, use C-c p c (helm-make-projectile); otherwise, simple run M-x helm-make or M-x compile.

;; Compile commands in c/c++ and makefile modes
;; use helm-make
(global-set-key (kbd "C-c p c") 'helm-make-projectile)
(add-hook 'c-mode-common-hook
          (lambda () (define-key c-mode-base-map
                       (kbd "C-c C-c") 'helm-make)))
;; default mode for Makefile in gnome
(add-hook 'makefile-gmake-mode-hook
          (lambda () (define-key makefile-gmake-mode-map
                       (kbd "C-c C-c") 'helm-make)))
;; default mode for Makefile in Mac OS X
(add-hook 'makefile-bsdmake-mode-hook
          (lambda () (define-key makefile-bsdmake-mode-map
                       (kbd "C-c C-c") 'helm-make)))
;; compilation setup for cmake-mode
(add-hook 'cmake-mode-hook
          (lambda ()
            (setq compile-command "cd build/ && cmake .. && make")
            (define-key cmake-mode-map (kbd "C-c C-c") 'compile)))

If the Makefile is in different directories, e.g. created by cmake, we need to specify the location of Makefile. .dir-locals.el file is needed for this purpose. .dir-locals.el should be placed in project root. The file content looks like this:

((c++-mode (helm-make-build-dir . "build/")))

Due to the local variable settings, Emacs will ask if the variable helm-make-build-dir is safe. Put the configuration in init file to prevent it.

(put 'helm-make-build-dir 'safe-local-variable 'stringp)

Major modes to edit CMake files

;; /cmake-mode/: cmake-mode.el
(require 'cmake-mode)
;; /cmake-font-lock/: to add more fontifying features
(add-to-list 'load-path "~/.emacs.d/git/cmake-font-lock")
(autoload 'cmake-font-lock-activate "cmake-font-lock" nil t)
(add-hook 'cmake-mode-hook 'cmake-font-lock-activate)
;; adding /company-cmake/ for ac-complete
(load-file (expand-file-name "git/company-cmake.el"
                             user-emacs-directory))
(add-to-list 'company-dabbrev-code-modes 'cmake-mode)
(defun y:company-cmake-setup ()
  (setq-local company-backends
              (append '((company-cmake company-dabbrev-code))
                      company-backends)))
(add-hook 'cmake-mode-hook 'y:company-cmake-setup)

Major modes for doxygen documentations (disabled)

To use doxymacs, setup the following in your init file:

;; /doxymacs/ to manipulate doxygen documentations
(add-to-list 'load-path "~/.emacs.d/git/doxymacs-1.8.0")
(require 'doxymacs)
(add-hook 'c-mode-common-hook 'doxymacs-mode)
; fontify the doxygen keywords
(defun my-doxymacs-font-lock-hook ()
  (if (or (eq major-mode 'c-mode) (eq major-mode 'c++-mode))
      (doxymacs-font-lock)))
(add-hook 'font-lock-mode-hook 'my-doxymacs-font-lock-hook)

Ends

(provide 'emacs-init-cc-modern)
;; ================================================
;; emacs-init-cc-modern.el ends here