在内核源代码树上使用 flycheck/flymake
Using flycheck/flymake on kernel source tree
有没有easy/automated配置flycheck或flymake的方法
在文件上写入时显示错误注释
在 linux 内核源代码树中?假设我正在工作
fs/proc/cmdline.c 我希望 flycheck 下降
两个目录并执行 "make fs/proc/cmdline.o" 和
然后注释结果。假设 ARCH 和 CROSS_COMPILE
外部设置。
我一直在考虑自己做这个 - 这就是我得到的:
您需要找到内核源代码树的基础,因此默认的 flymake
寻找 Makefile
的交易会适得其反。我们将添加我们自己的文件,该文件用于定位源代码库和包装普通内核 makefile:
添加一个文件flymake.mk
到内核源代码树的基础(根据您自己的交叉编译需要配置):
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)))
要点是去掉“_flymake.c”,只编译真实的文件,构建真实的文件,而不仅仅是语法。这避免了我们不小心创建 file_flymake.o
我们需要说服 flymake 寻找 flymake.mk
和 运行 check-syntax
反对它 - 添加这些到你的 .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)
限制:
- 无法解析头文件
- 无法解析 flymake 临时文件
source_flymake.c
(确保忽略 flymake 标记,直到它 运行 覆盖已保存的文件)。我有一个强制重新运行s flymake的击键。
- 外部模块不支持 flymake
- 需要预先注册路径匹配器(参见上面的
push
行)——我对 flymake 的了解还不够多,无法一次性覆盖单个缓冲区。
头文件、临时文件和外部模块的限制可以通过修补内核 Makefile 本身来克服,目前我想避免这种情况。
与 Gregs flymake 代码段类似,这是我想出的一个用于 flycheck 的代码段:
(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 :这将搜索包含 VERSION = .. PATCHLEVEL = ...
的顶级 linux Makefile
- utils/flycheck-linux-makefile-checker : flycheck 检查器,它使用 "make" "C=1" "-c" "..." 需要安装 sparse
不完美但可用。
我正在使用 flymake.mk
生成文件
## 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= _FLYMAKE_TYPE= M=$(dir $*)
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%,)
check-syntax: ${CHK_SOURCES}
$(CC) $(call clean_checkflags,$(c_flags)) -c -o /dev/null -S $<
endif
它既适用于头文件,也适用于临时的 flymake 文件。
有没有easy/automated配置flycheck或flymake的方法 在文件上写入时显示错误注释 在 linux 内核源代码树中?假设我正在工作 fs/proc/cmdline.c 我希望 flycheck 下降 两个目录并执行 "make fs/proc/cmdline.o" 和 然后注释结果。假设 ARCH 和 CROSS_COMPILE 外部设置。
我一直在考虑自己做这个 - 这就是我得到的:
您需要找到内核源代码树的基础,因此默认的 flymake
寻找 Makefile
的交易会适得其反。我们将添加我们自己的文件,该文件用于定位源代码库和包装普通内核 makefile:
添加一个文件flymake.mk
到内核源代码树的基础(根据您自己的交叉编译需要配置):
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)))
要点是去掉“_flymake.c”,只编译真实的文件,构建真实的文件,而不仅仅是语法。这避免了我们不小心创建 file_flymake.o
我们需要说服 flymake 寻找 flymake.mk
和 运行 check-syntax
反对它 - 添加这些到你的 .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)
限制:
- 无法解析头文件
- 无法解析 flymake 临时文件
source_flymake.c
(确保忽略 flymake 标记,直到它 运行 覆盖已保存的文件)。我有一个强制重新运行s flymake的击键。 - 外部模块不支持 flymake
- 需要预先注册路径匹配器(参见上面的
push
行)——我对 flymake 的了解还不够多,无法一次性覆盖单个缓冲区。
头文件、临时文件和外部模块的限制可以通过修补内核 Makefile 本身来克服,目前我想避免这种情况。
与 Gregs flymake 代码段类似,这是我想出的一个用于 flycheck 的代码段:
(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 :这将搜索包含 VERSION = .. PATCHLEVEL = ... 的顶级 linux Makefile
- utils/flycheck-linux-makefile-checker : flycheck 检查器,它使用 "make" "C=1" "-c" "..." 需要安装 sparse
不完美但可用。
我正在使用 flymake.mk
生成文件
## 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= _FLYMAKE_TYPE= M=$(dir $*)
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%,)
check-syntax: ${CHK_SOURCES}
$(CC) $(call clean_checkflags,$(c_flags)) -c -o /dev/null -S $<
endif
它既适用于头文件,也适用于临时的 flymake 文件。