Emacs 的智能编译

Emacs 提供了一个编译接口,可以使用 M-x compile 来输入编译命令,然后 Emacs 会以很友好的方式把编译结果显示出来,并允许你快速定位编译产生的错 误、警告等。然而这样还是有些麻烦,通常把它绑定到一个快捷键,然而这样还 是比较麻烦,需要自己输入编译命令,其实有很多时候一些编译命令是可以自动 分析出来的,比如通常在做练习的时候随手写一个 c 文件,那么应该是希望调 用 gcc 来编译,而如果是在做一个工程,通常目录下面有一个 Makefile ,则 希望调用 make 来完成编译。既然有想法,就肯定有实现:

我自己写的 smart-compile

我自己写了个 smart-compile ,他的功能是查找当前目录,如果找到 Makefile 之类的东西,就调用 make 直接编译,否则再根据 major-mode 来判断:

后来我发现这个有些不方便,有时候 Makefile 其实是在上一层目录的,但如果 把 Makefile 的搜索路径扩充到当前目录以及父目录以及父目录的父目录直到根 目录的话,有时候又会造成一些问题。我仔细分析自己的问题,通常我要编译的 东西都是一些零碎的小文件,直接用 gcc 就可以编译,而一般只有当我写一个 工程的时候才会用到 Makefile ,而工程的文件又是相对集中在某一个目录下面 的,因此其实直接用文件路径来判断也是一个很实用的方法,正好,我在网上看 到一个写好的 smart-compile 扩展: smart-compile.el 。

使用 smart-compile.el

smart-compile.el 提供一个 smart-compile 的函数,它查找当前目录下面有没 有 Makefile ,如果有,则会询问是否使用 make 进行编译。否则,他会通过查 看 smart-compile-alist 来根据当前的文件名以及 major-mode 来得到最合适 的编译命令。

可以在 EmacsWiki 上面下载到他的最新版本。加载之后就可以通过修改或添加项 目到 smart-compile-alist 来实现智能编译了!假如我现在在做一个工程,他 处于 /home/kid/project/foo/ 下面,我可以这样写:

但是这样也有一些问题,比如如果我工程里面分了模块,里面又分了子目录,而 Makefile 是放在工程目录的最顶层的:

project/foo/
           |-- Makefile
           |-- foo.c
           `-- bar/
                 |-- bar.c
                 `-- foobar.c

那么,假如我现在在编辑 bar.c ,编辑完之后使用 smart-compile 则会调用 make 来进行编译,然而这是不正确的,因为 Makefile 不在这儿。不过,也可 以给 make 指定路径来解决这个问题:

其他的也参照设置一下就可以了,在编译命令那里可以使用几个预定义的变量:

最后,再把他绑定到一个自己喜欢的快捷键上面就万事大吉了!

另外,那个列表的每一项第二个参数并不一定要是作为 shell 命令运行的字符串, 也可以是一个 lisp 语句,例如,我让他在 muse-mode 的时候使用 muse-project-publish 来进行编译,则可以这么写:

这样,我写到这儿,就可以按一下 F9 ,就发布当前页面了,而不是调用 compile 来进行编译。另外,从他的源代码里面可以看到,如果通过前面查找 Makefile 以及 smart-compile-alist 的办法都没有办法确定如何编译的时候, 他会查看文件的头两个字符,如果是 ``#!'' 的话,则编译命令就是当前文件名, 这个设计与其说是编译,倒不如说是运行了,但是由于 ``#!'' 又是非常灵活的, 所以这也是一个值得利用的地方,但是如果当前文件没有可执行权限的话,这个 命令是会运行失败的,也许可以修改一下,题取出 ``#!'' 后面的命令来作为编 译命令,或者说,这种情况下的编译命令就是为当前文件加上可执行权限。