#+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]] - [[#cquery-server][cquery server]] - [[#configuration][Configuration]] - [[#basic][Basic]] - [[#selecting-an-alternate-lsp-server][Selecting an alternate LSP server]] - [[#semantic-highlighting][Semantic highlighting]] - [[#cache-directory-absolute-or-relative][Cache directory (absolute or relative)]] - [[#additional-configuration-options][Additional configuration options]] - [[#example-dotspacemacs-configuration-layers-entry][Example dotspacemacs-configuration-layers entry]] - [[#completion][Completion]] - [[#debugger-dap-integration][Debugger (dap integration)]] - [[#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]] - [[#cquery--ccls][cquery / 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=, [[https://github.com/cquery-project/cquery][cquery]] 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 in 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 - =lsp-cquery= using cquery 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. 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 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 three available backends (all based on libclang). - [[https://clang.llvm.org/extra/clangd/][clangd]] - [[https://github.com/cquery-project/cquery][cquery]] - [[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 =company-lsp= - Semantic highlighting (=cquery=, =ccls=) - See more on [[https://github.com/cquery-project/cquery/wiki/Emacs]] - 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 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 not provided by clangd. Note that prebuild binaries exist for most Linux distros and MacOS using Homebrew. ***** cquery server Install the =cquery= server. See [[https://github.com/cquery-project/cquery/wiki][instructions]]. This implementation appears to be unmaintained and continued support is provided here purely for existing users. It is recommended to use the =lsp-ccls= backend instead if you can. 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 ***** Semantic highlighting Currently only available for =lsp-ccls= and =lps-cquery=. 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 the method used to highlight the text relies on the =font-lock= mechanism of Emacs which is the fastest. More accurate but also slower method is to use the overlays. To use the overlays set the layer variable =c-c++-lsp-semantic-highlight-method= to ='overlay=. ***** Cache directory (absolute or relative) Currently only available for =lsp-ccls= and =lps-cquery=. All LSP backends are configured to store their index cache in a subdirectory of =.emacs.d/cache=. This can be overridden by specifying an explicit =c-c++-lsp-cache-dir=. Setting this value to a relative path will cause the index cache to be placed in a subdirectory of your current project root. ***** Additional configuration options See the full list of configuration options you can set at: - [[https://github.com/MaskRay/ccls/wiki/Emacs][Emacs section of =ccls= wiki]] - [[https://github.com/cquery-project/cquery/wiki/Emacs][Emacs section of =cquery= 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-executable (file-truename "~/dev/cpp/ccls/Release/ccls") c-c++-lsp-enable-semantic-highlight 'rainbow))) #+END_SRC **** Completion =company-lsp= provides completion functionality. Client-side cache and sorting have been disabled in favour of server, as recommended by =cquery=/=ccls= wikis. **** Debugger (dap integration) 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. *** 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]]. N.B. 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 =auto-completion= layer is included). 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 Mode for header files is auto detected by `c-or-c++-mode' in Emacs > 26.1+. Older 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 [[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++-enable-organize-includes-on-save= to =t= in the dotfile: #+BEGIN_SRC emacs-lisp (setq-default dotspacemacs-configuration-layers '((c-c++ :variables c++-enable-organize-includes-on-save t))) #+END_SRC ** clang-format [[http://clang.llvm.org/docs/ClangFormat.html][clang-format]] allows 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 any of its parent directories. If no =.clang-format= 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 neeed 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 =cquery= and =ccls= wikis, but should be more generally applicable. * Key bindings ** LSP The default key bindings for LSP implementations are defined by/documented in the [[file:../../+tools/lsp/README.org][LSP layer]]. *** cquery / ccls The key bindings listed below are in addition to A ~[ccls]~ or ~[cquery]~ 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~ | 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~ | rename symbol | | ~SPC m g s~ | print source arguments | | ~SPC m g S~ | display summary | | ~SPC m g T~ | taglist | | ~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 |