这篇文章原本是『走近 Emacs』的内容,当时因为考虑到 Emacs 的用户未必写 C/C++ 代码,所以就将它隔离了出来。
当你用 Emacs 打开或新建一份扩展名为 .c
的文件时,Emacs 会自动开启内置的 C 模式。这个模式提供了语法高亮、自动缩进等基本功能。同时 Emacs 也允许用户深度定制符合自己使用习惯的代码编辑功能,前提是你需要对 Emacs Lisp 扩展语言有一定了解。
C/C++ 代码编辑基本配置
如果你不熟悉也不打算学习 Emacs Lisp 语言,那就只能将他人写好的配置代码扔到 $HOME/.emacs
或 $HOME/.emacs.d/init.el
文件中。现在推荐使用后者作为 Emacs 的配置文件。
很多年前我从一个我忘记了他的网络 ID 的家伙那里抄来一段 C 代码的配置:
;;;; c mode ;;;;
(defvar xgp-cfsi-left-PAREN-old nil
"Command used to input \"(\"")
(make-variable-buffer-local 'xgp-cfsi-left-PAREN-old)
(defun xgp-cfsi-modify-alist (alist term new)
(let ((tl (assq term (symbol-value alist))))
(if tl
(setcdr tl new)
(add-to-list alist (cons term new)))))
(defun xgp-cfsi (style)
"Deciding whether using CFSI."
(interactive "Style: ")
(c-set-style style)
(setq indent-tabs-mode
nil
c-hanging-semi&comma-criteria
(quote (c-semi&comma-inside-parenlist)))
(xgp-cfsi-modify-alist 'c-hanging-braces-alist 'class-open nil)
(xgp-cfsi-modify-alist 'c-hanging-braces-alist 'class-close nil)
(local-set-key " " 'self-insert-command))
(defun xgp-cfsi-erase-blanks ()
"Erase all trivial blanks for CFSI."
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "[ \t]+$" nil t)
(replace-match "" nil nil))))
(defun linux-c-mode()
(define-key c-mode-map [return] 'newline-and-indent)
(setq imenu-sort-function 'imenu--sort-by-name)
(interactive)
(imenu-add-menubar-index)
(which-function-mode)
(c-toggle-auto-state)
(c-toggle-hungry-state)
(setq indent-tabs-mode nil)
(xgp-cfsi "linux"))
(add-hook 'c-mode-common-hook 'linux-c-mode)
这样配置之后,C/C++ 代码编辑功能会强大一些。例如,敲击 Backspace 键可以连续删除多行空行;在代码行尾键入 ; 会自动换行;代码缩进长度变为 8 个空白字符……这些配置,我用了很多年,到现在也不知道它具体都做了些什么。
C++ 的代码,因为我平时写的不太多,所以没作配置。不过上述的 C 模式配置的这些功能,也适合 C++ 代码的编辑。
C/C++ 代码自动提示
你现在所用的 Emacs 版本应该是 >= 24,如果不是,想办法升级吧。否则本节内容不太适合你阅读,除非你懂得如何手动安装 Emacs 扩展包。
如果用过 Visual C++.net 或者 Eclipse,想必会对它们的代码编辑器提供的代码自动提示功能念念不忘,因而抱怨 Emacs 的 C 模式未提供此功能。事实上是有的,但是要实现 C/C++ 代码的自动提示,这需要 Emacs 懂得如何去解析 C/C++ 代码,似这类繁重又专业的任务让一个文本编辑器来做,不合常理,更何况 Emacs 并非 C/C++ 程序员的专用编辑器。
Emacs 能够做到的事情必须要与文本编辑直接相关,但是它有能力借助其他工具弥补自身不足。像 C/C++ 代码分析这样的任务,交给一个专业的 C/C++ 编译器最好不过了。虽然借助我们所熟悉的 gcc 是可行的,但它不如另一款编译前端 clang 好用,因为后者在设计时就考虑到了与代码编辑器的整合。
安装 clang
我们所要做的首先是想办法安装 clang。Gentoo Linux 用户只需:
$ sudo emerge -avt clang
然后先去干别的事吧,clang 毕竟是 C++ 写的 C/C++ 编译器,是个挺大的项目,编译耗时会挺长,长的我都忘记了到底需要多久,似乎比编译 libreoffice 或者 firefox 快一些。
安装 company
Emacs 本身是无法与 clang 沟通的,但是 Emacs Lisp 可以强大到允许 Emacs 用户自行编写扩展包以实现 Emacs 与 clang 的沟通。于是就有人写出了 company 这个扩展包。
在 Emacs 24 之前的时代,要为 Emacs 安装扩展包,需要从网络上下载扩展包,然后复制到 Emacs 所能搜索到的目录,最后在 Emacs 配置文件中对扩展包进行配置。
从 Emacs 24 开始,Emacs 对扩展包进行统一管理,极大程度上简化了扩展包的搜索与安装过程。打开 Emacs,然后执行 M-x list-packages
,如果网速足够快,应该很快就能看到 Emacs 官方提供的扩展包列表。
待软件包列表出现后,执行 C-s M-r ^ +company
,回车即可让光标跳到 company 扩展包信息所在的文本行,继而敲击 i
键(表示要安装该扩展包),再敲击 x
键(表示执行安装过程),稍等片刻,Emacs 会自动从下载 company 扩展包并安装至 $HOME/.emacs.d
目录。
提示:
C-s
是开启 Emacs 查找模式,M-r
是将查找模式切换为正则表达式查找模式,而^ +companyy
是用于匹配『位于行首且由多个空格与company
字符串构成的字符串』的正则表达式。
如果以后要删除 company 扩展,步骤与安装步骤类似,只是将 i
键替换为 d
键(表示删除)。
配置 company
company 安装完毕后,在 Emacs 配置文件中做以下配置:
;; 代码补全
(add-hook 'c-mode-hook 'company-mode)
(add-hook 'c++-mode-hook 'company-mode)
这样便可将 company 挂接到 Emacs C 模式上。这样,每当 Emacs 打开 C/C++ 文件时company 模式便会被自动开启。
下图是 company 与clang 成功『沟通』后的结果:
由于 clang 默认会去 Linux 标准目录 /usr/include
中去搜索库的头文件,但是有些库的头文件是安装在非标准位置的。例如 PCL 库的头文件,默认安装在 usr/include/pcl-1.7
,若要对 PCL 库函数进行自动补全,那么就需要将这个路径告诉 clang。eigen 库也存在这个问题。解决方法是在项目源码的顶层目录下创建 .dir-locals.el
文件,内容类似于:
((nil . ((company-clang-arguments . ("-I/usr/include/pcl-1.7/"
"-I/usr/include/eigen3/")))))
如果谁有更好的让 clang 自动搜索库的头文件路径的方法,还请不吝赐教。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。