#+TITLE: C/C++ layer

#+TAGS: general|layer|multi-paradigm|programming

[[file:img/ccpp.jpg]]

* Table of Contents                     :TOC_5_gh:noexport:
- [[#description][Description]]
  - [[#features][Features:]]
- [[#install][Install]]
  - [[#layer][Layer]]
  - [[#backends][Backends]]
    - [[#lsp][LSP]]
      - [[#features-1][Features]]
      - [[#external-dependencies][External dependencies]]
        - [[#clangd][clangd]]
        - [[#ccls-server][ccls server]]
      - [[#configuration][Configuration]]
        - [[#basic][Basic]]
        - [[#selecting-an-alternate-lsp-server][Selecting an alternate LSP server]]
        - [[#path-to-lsp-server-executables][Path to LSP server executables]]
        - [[#semantic-highlighting][Semantic highlighting]]
        - [[#cache-directory-absolute-or-relative][Cache directory (absolute or relative)]]
        - [[#example-dotspacemacs-configuration-layers-entry][Example dotspacemacs-configuration-layers entry]]
      - [[#completion][Completion]]
      - [[#debugger-dap-integration][Debugger (dap integration)]]
        - [[#adapter-selection][Adapter selection]]
        - [[#microsoft-adapter-installation][Microsoft adapter installation]]
        - [[#codefreak-adapter-installation][CodeFreak adapter installation]]
        - [[#lldb-adapter-installation][LLDB adapter installation]]
    - [[#rtags][rtags]]
      - [[#external-dependencies-1][External dependencies]]
      - [[#configuration-1][Configuration]]
  - [[#default-mode-for-header-files][Default mode for header files]]
  - [[#organize-file-header-includes-on-save][Organize file header includes on save]]
  - [[#clang-format][clang-format]]
  - [[#enable-google-set-c-style][Enable google-set-c-style]]
  - [[#newlines][Newlines]]
  - [[#projectile-sub-project-adoption][Projectile sub-project adoption]]
- [[#key-bindings][Key bindings]]
  - [[#lsp-1][LSP]]
    - [[#ccls][ccls]]
      - [[#backend-language-server][backend (language server)]]
      - [[#goto][goto]]
      - [[#gotohierarchy][goto/hierarchy]]
      - [[#gotomember][goto/member]]
    - [[#debugger][debugger]]
  - [[#rtags-1][RTags]]
  - [[#additional-key-bindings][Additional key bindings]]
    - [[#disassemble][Disassemble]]
    - [[#formatting-clang-format][Formatting (clang-format)]]
    - [[#open-matching-files][Open matching files]]
    - [[#refactor][Refactor]]

* Description
This layer adds configuration for C/C++ language.

** Features:
- Multiple backends support:
  - LSP with either =clangd= or [[https://github.com/MaskRay/ccls][ccls]]
  - [[https://github.com/Andersbakken/rtags][rtags]] (gtags)
  - [[https://github.com/abingham/emacs-ycmd][emacs-ycmd]]
- Support for debuggers [[https://github.com/realgud/realgud][realgud]] and [[https://github.com/emacs-lsp/dap-mode][dap]] (with LSP backend)
- Support syntax checking via flycheck (=syntax-checking= layer required)
- Auto-completion via company (=auto-completion= layer required)
- Support code reformatting with [[http://clang.llvm.org/docs/ClangFormat.html][clang-format]].
- Support for disassembly of code with [[https://github.com/jart/disaster][disaster]].
- =sematic= layer integration:
  - Function or variable definition at the bottom
  - Current function cursor is at the top. See [[https://github.com/tuhdo/semantic-stickyfunc-enhance][stickyfunc-demos]] for
    demos in some programming languages.
  - Support common refactoring with [[https://github.com/tuhdo/semantic-refactor][semantic-refactor]]. See [[https://github.com/tuhdo/semantic-refactor/blob/master/srefactor-demos/demos.org][srefactor-demos]] for
    demonstration of refactoring features.
- =cscope= layer integration:
  - code navigation

* Install
** Layer
To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =c-c++= to the existing =dotspacemacs-configuration-layers= list in this
file.

** Backends
Supported backends are:
- =lsp-clangd= using clangd LSP server
- =lsp-ccls= using ccls LSP server
- =rtags= using [[https://github.com/Andersbakken/rtags][rtags]]
- =ycmd= using [[https://github.com/abingham/emacs-ycmd][emacs-ycmd]]

To choose a default backend set the layer variable =c-c++-backend=:

#+BEGIN_SRC elisp
  (c-c++ :variables c-c++-backend 'lsp-clangd)
#+END_SRC

Alternatively the =lsp-clangd= backend will be automatically chosen if the layer
=lsp= is used and you did not specify any value for =c-c++-backend=.

*Note:* It is recommended to use a modern backend like the =lsp= ones.

The backend can be chosen on a per project basis using directory local variables
(files named =.dir-locals.el= at the root of a project), an example is to use the
=lsp-ccls= backend:

#+BEGIN_SRC elisp
  ;;; Directory Local Variables
  ;;; For more information see (info "(emacs) Directory Variables")

  ((c++-mode (c-c++-backend . lsp-ccls)))
#+END_SRC

*Note:* you can easily add a directory local variable with ~SPC f v d~.

*** LSP
LSP support is provided via the [[file:../../+tools/lsp/README.org][LSP layer]], using one of two available backends
(all based on libclang).
- [[https://clang.llvm.org/extra/clangd/][clangd]]
- [[https://github.com/MaskRay/ccls][ccls]]

They claim to be more efficient than existing tools at indexing large code bases.

**** Features
- Cross references (definitions, references, base/derived classes/methods, type instances, ...)
- Diagnostics
- Completion with =lsp=
- Semantic highlighting (=ccls= or =clangd=)
- Cross-platform - functional on Windows, Linux and macOS.

**** External dependencies
Install one (or more) of the following (=clangd= is used by default):

***** clangd
Install =clang= using a binary distribution downloaded from the [[http://releases.llvm.org/download.html][LLVM releases
page]] or via your package manager. This is the default implementation that's used by the
Emacs =lsp-mode= package and probably the easiest to install.
- [[https://clang.llvm.org/extra/clangd/Extensions.html][clangd protocol extensions page]]

***** ccls server
Install the =ccls= server. See [[https://github.com/MaskRay/ccls/wiki][instructions]]. This is currently the most fully
featured implementation, including semantic highlighting and some navigation/
introspection features that are not provided by clangd.

Note that prebuild binaries exist for most Linux distros and MacOS using
Homebrew.

**** Configuration
***** Basic
To use the default =clangd= language server, select =lsp-clangd= as the =c-c++=
layer backend by adding the following to your dotfile:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables c-c++-backend 'lsp-clangd)))
#+END_SRC

***** Selecting an alternate LSP server
To choose an alternate LSP server set the layer variable =c-c++-backend= to
another supported backend, for instance =lsp-ccls=:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables c-c++-backend 'lsp-ccls)))
#+END_SRC

***** Path to LSP server executables
LSP expects to find the LSP server executables in your =PATH=. If you want to
specify the location of an executable then you need to set the appropriate
variable:

| Server | Variable name                   |
|--------+---------------------------------|
| clangd | =lsp-clients-clangd-executable= |
| ccls   | =ccls-executable=               |

***** Semantic highlighting
Currently only available for =lsp-ccls= and =clangd=. Semantic highlighting
can precisely highlight identifiers.

Semantic highlighting is disabled by default. To enable it set the layer
=c-c++-lsp-enable-semantic-highlight= to non-nil. It is possible to give a
different color for each identifier by setting the variable to ='rainbow=.

When semantic highlighting is enabled then the method that's used to highlight the text
relies on Emacs' fastest =font-lock= mechanism. A more
accurate but also slower method is to use overlays. To use overlays set
the layer variable =c-c++-lsp-semantic-highlight-method= to ='overlay=.

***** Cache directory (absolute or relative)
=clangd= cache directoy is =.clangd= and cannot be changed.

=ccls= default directory is =.ccls-cache=, it can be changed by setting the
=:cache= option in the variable =ccls-initialization-options=.

See the full list of configuration options you can set at:
- [[https://github.com/MaskRay/ccls/wiki/Emacs][Emacs section of =ccls= wiki]]

***** Example dotspacemacs-configuration-layers entry
#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables
                         c-c++-adopt-subprojects t
                         c-c++-backend 'lsp-ccls
                         c-c++-lsp-enable-semantic-highlight 'rainbow)))
#+END_SRC

**** Completion
=company-capf= provides completion functionality. Client-side cache and sorting
have been disabled in favour of server,
as recommended by =ccls= wikis.

**** Debugger (dap integration)
***** Adapter selection
To select the active adapters, configure the =c-c++-dap-adapters= layer variable.
By default only the Microsoft extension is available.

| Adapter      | Supported debuggers               | DAP mode       |
|--------------+-----------------------------------+----------------|
| Microsoft    | gdb, lldb, Visual Studio Debugger | =dap-cpptools= |
| CodeFreak    | gdb, lldb                         | =dap-gdb-lldb= |
| LLVM Project | lldb                              | =dap-lldb=     |

Example configuration with two adapters selected:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables
                         c-c++-dap-adapters '(dap-lldb dap-cpptools)))
#+END_SRC

***** Microsoft adapter installation
To install the debug adapter you may run =M-x dap-cpptools-setup= when you are
on Linux.

***** CodeFreak adapter installation
To install the debug adapter you may run =M-x dap-gdb-lldb-setup= when you are
on Linux or download it manually from [[https://marketplace.visualstudio.com/items?itemName=webfreak.debug][Native Debug]] and adjust the
=dap-gdb-lldb-path= variable.

***** LLDB adapter installation
Install the =lldb-vscode= program. It usually comes with =lldb= from your
distribution's package repository.
Alternatively build directly following the [[https://github.com/llvm/llvm-project/tree/main/lldb/tools/lldb-vscode#installation-for-visual-studio-code][official installation instructions]].

Adjust the =dap-lldb-debug-program= variable to match the executable.

*** rtags
rtags is a well established clang-based source code indexing tool.

**** External dependencies
Install the RTags server via [[https://formulae.brew.sh/formula/rtags][homebrew]], the [[https://aur.archlinux.org/packages/rtags/][aur]] or from source according to the
instructions [[https://github.com/Andersbakken/rtags][here]].

*Note:* RTags is not supported on Windows at the time of
writing, although there is an [[https://github.com/Andersbakken/rtags/issues/770][open issue with some recent activity]] on github.

**** Configuration
To enable support for =rtags=, set the layer variable =c-c++-backend=:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables c-c++-backend 'rtags)))
#+END_SRC

This will also enable =company-rtags= to be used as a backend for
auto-completion (when the =auto-completion= layer is enabled).
To prevent this, while retaining the rest of Rtags' functionality,
set the variable =c-c++-rtags-completion= to =nil=:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables
                         c-c++-backend 'rtags
                         c-c++-enable-rtags-completion nil)))
#+END_SRC

** Default mode for header files
The mode for header files is auto detected by `c-or-c++-mode' in Emacs > 26.1+.
Older versions of Emacs will open header files in =c-mode= by default, you can open them in
=c++-mode= by setting the variable =c-c++-default-mode-for-headers= as follow.

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables c-c++-default-mode-for-headers 'c++-mode)))
#+END_SRC

*Note:* To set the variable for a given project, create a directory local
variable at the root of your project. More info on directory local variables
can be found in the manual: [[http://www.gnu.org/software/emacs/manual/html_node/elisp/Directory-Local-Variables.html][dir-locals]].

** Organize file header includes on save
To organize the file header includes on save, set the layer variable
=c-c++-enable-organize-includes-on-save= to =t= in the dotfile:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables c-c++-enable-organize-includes-on-save t)))
#+END_SRC

** clang-format
[[http://clang.llvm.org/docs/ClangFormat.html][clang-format]] allows for reformatting either a selected region of code
(=clang-format-region=) or a whole buffer (=clang-format-buffer=) according to a
style defined in a =.clang-format= file. This file is either located in the same
directory as the file being edited, or in any of its parent directories. If no
=.clang-format= file is found, then a default style will be used.

To enable automatic buffer formatting on save, set the variable
=c-c++-enable-clang-format-on-save= to =t=:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
                '((c-c++ :variables c-c++-enable-clang-format-on-save t)))
#+END_SRC

** Enable google-set-c-style
If you have clang enabled with =clang-format= as described earlier in this page
you may not have a lot of need for =google-set-c-style= if you are already
using a mode based on Google mode for most of your projects.

However, if you don't have (or want) =clang-format=, or if you have to do a lot
[[https://www.emacswiki.org/emacs/TrampMode][Tramp]] remote editing on systems that don't have =clang-format= installed, you
may want =google-c-style= enabled and added to your common hooks.

To get =google-c-style= actually install itself into your C/C++ common hooks,
you need to have =c-c++-enable-google-style= defined to true when you load the
C-C++ lang in Spacemacs. In your =~/.spacemacs= file, a possible way that this
would look is that in your list of =dostpacemacs-configuration-layers= you have
an entry like

#+BEGIN_SRC emacs-lisp
  (c-c++ :variables c-c++-enable-google-style t)
#+END_SRC

Additionally, if you have =c-c++-enable-google-newline= variable set then
=`google-make-newline-indent= will be set as a =c-mode-common-hook=. You would
set that up like this:

#+BEGIN_SRC emacs-lisp
  (c-c++ :variables c-c++-enable-google-style t
                    c-c++-enable-google-newline t)
#+END_SRC

** Newlines
You can enable the =Auto-newline= minor mode that automatically adds newlines
after certain characters by setting the =c-c++-enable-auto-newline= variable.

#+BEGIN_SRC emacs-lisp
  (c-c++ :variables c-c++-enable-auto-newline t)
#+END_SRC

** Projectile sub-project adoption
To prevent projectile from using subproject root when visiting files in a subproject,
set =c-c++-adopt-subprojects= to =t=.

#+BEGIN_SRC emacs-lisp
  (c-c++ :variables c-c++-adopt-subprojects t)
#+END_SRC

This is based on a recommendation on the =ccls= wikis, but should be more
generally applicable.

* Key bindings
** LSP
The default key bindings for the LSP implementations are defined and documented in
the [[file:../../+tools/lsp/README.org][LSP layer]].

*** ccls
A ~[ccls]~ suffix indicates that the binding is for the indicated backend only.

**** backend (language server)

| Key binding | Description                              |
|-------------+------------------------------------------|
| ~SPC m b f~ | refresh index (e.g. after branch change) |
| ~SPC m b p~ | preprocess file                          |

**** goto

| Key binding | Description               |
|-------------+---------------------------|
| ~SPC m g &~ | find references (address) |
| ~SPC m g R~ | find references (read)    |
| ~SPC m g W~ | find references (write)   |
| ~SPC m g c~ | find callers              |
| ~SPC m g C~ | find callees              |
| ~SPC m g v~ | vars                      |
| ~SPC m g f~ | find file at point (ffap) |
| ~SPC m g F~ | ffap other window         |

**** goto/hierarchy

| Key binding   | Description                 |
|---------------+-----------------------------|
| ~SPC m g h b~ | base class(es)              |
| ~SPC m g h d~ | derived class(es) [ccls]    |
| ~SPC m g h c~ | call hierarchy              |
| ~SPC m g h C~ | call hierarchy (inv)        |
| ~SPC m g h i~ | inheritance hierarchy       |
| ~SPC m g h I~ | inheritance hierarchy (inv) |

**** goto/member

| Key binding   | Description             |
|---------------+-------------------------|
| ~SPC m g m h~ | member hierarchy        |
| ~SPC m g m t~ | member types [ccls]     |
| ~SPC m g m f~ | member functions [ccls] |
| ~SPC m g m v~ | member variables [ccls] |

*** debugger

| Key binding   | Description                     |
|---------------+---------------------------------|
| ~SPC m d d d~ | start debugging                 |
| ~SPC m d d l~ | debug last configuration        |
| ~SPC m d d r~ | debug recent configuration      |
|---------------+---------------------------------|
| ~SPC m d c~   | continue                        |
| ~SPC m d i~   | step in                         |
| ~SPC m d o~   | step out                        |
| ~SPC m d s~   | next step                       |
| ~SPC m d v~   | inspect value at point          |
| ~SPC m d r~   | restart frame                   |
|---------------+---------------------------------|
| ~SPC m d .~   | debug transient state           |
|---------------+---------------------------------|
| ~SPC m d a~   | abandon current session         |
| ~SPC m d A~   | abandon all process             |
|---------------+---------------------------------|
| ~SPC m d e e~ | eval                            |
| ~SPC m d e r~ | eval region                     |
| ~SPC m d e t~ | eval value at point             |
|---------------+---------------------------------|
| ~SPC m d S s~ | switch session                  |
| ~SPC m d S t~ | switch thread                   |
| ~SPC m d S f~ | switch frame                    |
|---------------+---------------------------------|
| ~SPC m d I i~ | inspect                         |
| ~SPC m d I r~ | inspect region                  |
| ~SPC m d I t~ | inspect value at point          |
|---------------+---------------------------------|
| ~SPC m d b b~ | toggle a breakpoint             |
| ~SPC m d b c~ | change breakpoint condition     |
| ~SPC m d b l~ | change breakpoint log condition |
| ~SPC m d b h~ | change breakpoint hit count     |
| ~SPC m d b a~ | add a breakpoint                |
| ~SPC m d b d~ | delete a breakpoint             |
| ~SPC m d b D~ | clear all breakpoints           |
|---------------+---------------------------------|
| ~SPC m d '_~  | Run debug REPL                  |
|---------------+---------------------------------|
| ~SPC m d w l~ | list local variables            |
| ~SPC m d w o~ | goto output buffer if present   |
| ~SPC m d w s~ | list sessions                   |
| ~SPC m d w b~ | list breakpoints                |

** RTags

| Key binding | Description                     |
|-------------+---------------------------------|
| ~SPC m g .~ | find symbol at point            |
| ~SPC m g ,~ | find references at point        |
| ~SPC m g ;~ | find file                       |
| ~SPC m g /~ | find all references at point    |
| ~SPC m g [~ | location stack back             |
| ~SPC m g ]~ | location stack forward          |
| ~SPC m g >~ | c++ tags find symbol            |
| ~SPC m g <~ | c++ tags find references        |
| ~SPC m g B~ | show rtags buffer               |
| ~SPC m g d~ | print dependencies              |
| ~SPC m g D~ | diagnostics                     |
| ~SPC m g e~ | reparse file                    |
| ~SPC m g E~ | preprocess file                 |
| ~SPC m g f~ | find dead functions             |
| ~SPC m g F~ | fixit                           |
| ~SPC m g G~ | guess function at point         |
| ~SPC m g h~ | print class hierarchy           |
| ~SPC m g I~ | c++ tags imenu                  |
| ~SPC m g L~ | copy and print current location |
| ~SPC m g M~ | symbol info                     |
| ~SPC m g O~ | goto offset                     |
| ~SPC m g p~ | set current project             |
| ~SPC m g r~ | display reference tree at point |
| ~SPC m g R~ | rename symbol                   |
| ~SPC m g s~ | print source arguments          |
| ~SPC m g S~ | display summary                 |
| ~SPC m g t~ | symbol type                     |
| ~SPC m g T~ | taglist                         |
| ~SPC m g u~ | display include dependency tree |
| ~SPC m g v~ | find virtuals at point          |
| ~SPC m g V~ | print enum value at point       |
| ~SPC m g X~ | fix fixit at point              |
| ~SPC m g Y~ | cycle overlays on screen        |

** Additional key bindings
*** Disassemble

| Key binding | Description                      |
|-------------+----------------------------------|
| ~SPC m D~   | disaster: disassemble c/c++ code |

*** Formatting (clang-format)

| Key binding | Description                     |
|-------------+---------------------------------|
| ~SPC m = =~ | format current region or buffer |
| ~SPC m = f~ | format current function         |

*** Open matching files

| Key binding | Description                                                   |
|-------------+---------------------------------------------------------------|
| ~SPC m g a~ | open matching file                                            |
|             | (e.g. switch between .cpp and .h, requires a project to work) |
| ~SPC m g A~ | open matching file in another window                          |
|             | (e.g. switch between .cpp and .h, requires a project to work) |

*** Refactor

| Key binding | Description                         |
|-------------+-------------------------------------|
| ~SPC m r .~ | srefactor: refactor thing at point. |
| ~SPC m r i~ | organize includes                   |
