Is there a easy/automated way to configure flycheck or flymake to show error annotations while writing on a file in the linux kernel source tree? Assuming I am working on fs/proc/cmdline.c I would like flycheck to go down two directories and do a "make fs/proc/cmdline.o" and then annotate the result. Assuming ARCH and CROSS_COMPILE is set externally.
3 Answers
I'd been thinking of doing this myself - here's what I've got:
You need to find the base of the kernel source tree, so the default flymake
deal of looking for Makefile
is counter productive. We'll add our own file which doubles for locating the source base, and for wrapping the normal kernel makefile:
Add a file flymake.mk
to the base of the kernel source tree (configure for your own cross-compilation needs):
ARCH=mips
CROSS_COMPILE=mips-linux-gnu-
export ARCH
export CROSS_COMPILE
.PHONY: check-syntax
check-syntax:
make -f Makefile $(patsubst %_flymake.o,%.o,$(patsubst %.c,%.o,$(CHK_SOURCES)))
The gist is to strip out "_flymake.c" and only compile the real file, and build the file for real, rather than just for syntax. This avoids us accidentally creating file_flymake.o
We'll need to convince flymake to look for flymake.mk
and run check-syntax
against it - add these to your .emacs:
;; Build a custom command-line using flymake.mk
(defun flymake-get-kernel-make-cmdline (source base-dir)
(list "make"
(list "-s"
"-f"
"flymake.mk"
"-C"
base-dir
(concat "CHK_SOURCES=" source)
"SYNTAX_CHECK_MODE=1"
"check-syntax")))
;; Search for flymake.mk to locate kernel tree base
(defun flymake-kernel-make-init ()
(flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "flymake.mk" 'flymake-get-kernel-make-cmdline))
;; Register against .c files under /linux/ or /kernel/
;; Since the list is parsed in order use `push`
(push '(".+/\\(linux\\|kernel\\)/.+\\.c$" flymake-kernel-make-init) flymake-allowed-file-name-masks)
Limitations:
- Can't parse header files
- Can't parse flymake temp files
source_flymake.c
(make sure you ignore flymake markup until it has run over the saved files). I have a keystroke that forcefully re-runs flymake. - No support for flymake in external modules
- Needs pre-registration of the path-matcher (see
push
line above) - I don't know enough about flymake to allow it to override a single buffer as a one-off.
The header, temp and external modules limitations could be overcome by patching the kernel Makefile itself, which for now I wanted to avoid.

- 2,549
- 2
- 24
- 30
-
Hi, thanks for the flymake snippet. I fiddled around a bit and came up with the below flycheck snippet (see post below). Greetings Konrad – Konrad Eisele Apr 22 '15 at 17:14
Similar to Gregs flymake snippet here is one for flycheck i have come up with:
(defun utils/flycheck-search-linux-makefile ()
"Search for linux top `Makefile' "
(labels
((find-makefile-file-r (path)
(let* ((parent (file-name-directory path))
(file (concat parent "Makefile")))
(cond
((file-exists-p file)
(progn
(with-temp-buffer
(insert-file-contents file)
(if (string-match "VERSION = [0-9]+[[:space:]]*PATCHLEVEL" (buffer-string))
(throw 'found-it parent)
(find-makefile-file-r (directory-file-name parent))
))))
((equal path parent) (throw 'found-it nil))
(t (find-makefile-file-r (directory-file-name parent)))))))
(if (buffer-file-name)
(catch 'found-it
(find-makefile-file-r (buffer-file-name)))
(error "buffer is not visiting a file"))))
(flycheck-define-checker utils/flycheck-linux-makefile-checker
"Linux source checker"
:command
(
"make" "C=1" "-C" (eval (utils/flycheck-search-linux-makefile))
(eval (concat (file-name-sans-extension (file-relative-name buffer-file-name (utils/flycheck-search-linux-makefile))) ".o"))
)
:error-patterns
((error line-start
(message "In file included from") " " (file-name) ":" line ":"
column ":"
line-end)
(info line-start (file-name) ":" line ":" column
": note: " (message) line-end)
(warning line-start (file-name) ":" line ":" column
": warning: " (message) line-end)
(error line-start (file-name) ":" line ":" column
": " (or "fatal error" "error") ": " (message) line-end))
:error-filter
(lambda (errors)
(let ((errors (flycheck-sanitize-errors errors)))
(dolist (err errors)
(let* ((fn (flycheck-error-filename err))
(rn0 (file-relative-name fn default-directory)) ; flycheck-fix-error-filename converted to absolute, revert
(rn1 (expand-file-name rn0 (utils/flycheck-search-linux-makefile))) ; make absolute relative to "make -C dir"
(ef (file-relative-name rn1 default-directory)) ; relative to source
)
(setf (flycheck-error-filename err) ef)
)))
errors)
:modes (c-mode c++-mode)
)
(defun utils/flycheck-mode-hook ()
"Flycheck mode hook."
(make-variable-buffer-local 'flycheck-linux-makefile)
(setq flycheck-linux-makefile (utils/flycheck-search-linux-makefile))
(if flycheck-linux-makefile
(flycheck-select-checker 'utils/flycheck-linux-makefile-checker))
)
(add-hook 'flycheck-mode-hook 'utils/flycheck-mode-hook)
- utils/flycheck-search-linux-makefile : This searches for a top-level linux Makefile that contains VERSION = .. PATCHLEVEL = ...
- utils/flycheck-linux-makefile-checker : The flycheck checker, it uses "make" "C=1" "-c" "..." that requires sparse to be installed
not perfect but usable.

- 3,088
- 20
- 35
I am using a flymake.mk
makefile like
## case 2: called within docker and cross env
ifeq (${_FLYMAKE_WRAPPED},)
_c_sources := $(filter %.c,$(CHK_SOURCES))
_h_sources := $(filter %.h,$(CHK_SOURCES))
_make_wrapped = $(MAKE) \
kbuild-file=$(abspath $(firstword ${MAKEFILE_LIST})) \
_FLYMAKE_WRAPPED=$1 _FLYMAKE_TYPE=$2 M=$(dir $*) $3
check-syntax: $(addprefix .check-syntax_,${_c_sources} ${_h_sources})
$(addprefix .check-syntax_,${_c_sources} ${_h_sources}):.check-syntax_%:
+$(call _make_wrapped,2,c)
## case 3: checking the files
else ifeq (${_FLYMAKE_WRAPPED},2)
-include $(dir ${CHK_SOURCES})/Makefile
-include $(dir ${CHK_SOURCES})/Kbuild
# Reset object/module list
obj-y :=
obj-m :=
lib-y :=
lib-m :=
always :=
targets :=
subdir-y :=
subdir-m :=
__build: check-syntax
.PHONY: check-syntax
clean_checkflags = $(filter-out -M% -g% -Wp,-M%,$1)
check-syntax: ${CHK_SOURCES}
$(CC) $(call clean_checkflags,$(c_flags)) -c -o /dev/null -S $<
endif
It works both with headers files and uses the temporary flymake files.

- 6,704
- 14
- 22