LIBRENEITOR

How to setup Emacs to edit the Linux Kernel

Mon, Jul 1, 2019

A small guide of how to setup your Emacs for Linux Kernel development

For this post I want to share how I set up my Emacs installation for C Linux Kernel development. But if for some reason you don’t like emacs, you should give a try to KDevelop, that is for sure one of the best if not the best C/C++ IDE out there for Unix.

The first question you may ask is: why Emacs? Because it is better than vim, and because you can use Emacs in the command line when you use a remote server.

The original idea of this post was to present Emacs as an IDE for C development, but after I kept digging more about different tools and workflows I decided that the best approach is to create multiple post where in which one I describe a different aspect of kernel development workflow.

When considering an Emacs setup for editing the Linux kernel we need to keep attention to at least two aspects:

Linux kernel Coding Style

“a infinite number of monkeys typing into GNU emacs would never make a good program” - Linus T

You can READ coding style explanation by Linus here. But the code is the following:

(setq-local indent-tabs-mode t)
(setq-local tab-width 8)
(setq-local c-indent-level 8)
(setq-local c-brace-imaginary-offset 0)
(setq-local c-brace-offset -8)
(setq-local c-argdecl-indent 8)
(setq-local c-label-offset -8)
(setq-local c-continued-statement-offset 8)
(setq-local backward-delete-char-untabify-method 'hungry)
(setq-local c-basic-offset 8)
(setq-local c-default-style "linux")

Basically, Emacs can’t indent your C code very well by default. We can make our lives easier with:

(define-key c-mode-map (kbd "RET") 'newline-and-indent)
(smartparens-global-strict-mode 1)
(ws-butler-mode 1)

Coding intelligence

By “Codding Intelligence” I’m referring to all the typical functionalities you expect in a IDE, like code completion, debugging, semantic completions, etc. If you want a full fledged tutorial step by step with the full code, you should visit this link.

In my personal case I decided to use gtags for code navigation.

;; bindings
(define-key helm-gtags-mode-map (kbd "C-c g a")
    'helm-gtags-tags-in-this-function)
(define-key helm-gtags-mode-map (kbd "C-c g r")
    'helm-gtags-resume)
(define-key helm-gtags-mode-map (kbd "C-c g s")
    'helm-gtags-show-stack)
(define-key helm-gtags-mode-map (kbd "C-j")
    'helm-gtags-select)
(define-key helm-gtags-mode-map (kbd "M-.")
    'helm-gtags-dwim)
(define-key helm-gtags-mode-map (kbd "M-,")
    'helm-gtags-pop-stack)
(define-key helm-gtags-mode-map (kbd "C-c <")
    'helm-gtags-previous-history)
(define-key helm-gtags-mode-map (kbd "C-c >")
    'helm-gtags-next-history)
;; vars and modes
(setq
 helm-gtags-ignore-case t
 helm-gtags-auto-update t
 helm-gtags-use-input-at-cursor t
 helm-gtags-pulse-at-cursor t
 helm-gtags-prefix-key "\C-cg"
 helm-gtags-suggested-key-mapping t)
(setq-local eldoc-documentation-function
    #'ggtags-eldoc-function)
(eldoc-mode 1)
(helm-gtags-mode 1)

Code completion:

(define-key c-mode-map (kbd "C-c TAB") 'company-complete)
(define-key c-mode-map (kbd "C-c SPC") 'helm-company)
(setq-local company-idle-delay nil) ; no invoke automatically
(auto-complete-mode 0)
(company-mode 1)

Function signature:

(define-key c-mode-map (kbd "C-c i") 'helm-semantic-or-imenu)
(semantic-mode 1)
(global-semantic-stickyfunc-mode 1)
(global-semantic-idle-summary-mode 1)
(setq-local eldoc-documentation-function #'ggtags-eldoc-function)
(eldoc-mode 1)

BTW, you can read my emacs.d folder from github.