介绍了三种在 Emacs 编译 VS 项目的方案。

在 Windows 开发比较大型的 C/C++ 项目,往往还是得借助微软的 Visual Studio (C++),但对于重度 Emacs 使用者,离开了用起 VC 来总是各种蹩脚。关于如何在 Emacs 中搭建 VC 的开发环境,fangzhzh 的一篇博文 《Emacs 中开发 VC 程序》 已经做了比较好的讨论。唯一不足的地方是对 Emacs 调用 VC 编译缺乏更深入的探讨。编译 VC 基本上还是要靠微软自家的工具,经过我的摸索,一共有三种不同的方案,针对不同的需要,用户可以自行选择。

总体说来,这三种方案各自的特点比较如下:

序号 调用工具 读取文件格式 特点
1 envdev *.sln 可以编译整个VS的解决方案。缺点在于编译后没有给出错误提示。
2 nmake *.mak 使用微软自家的 make 工具来编译单个工程。缺点在于生成 *.mak 文件比较麻烦。
3 msdev *.dsw VC 6.0 提供的单个工程编译工具。在VS 2005之后就被 envdev 取代了。

现在就让我们来深入探讨一下如何在 Emacs 中编译 Visual Studio (C++)  Emacs图 1 Emacs的项目。

1 方案一:envdev + .sln

在Visual Studio中,可以把所有的项目看作一个解决方案,这个解决方案就用 *.sln 文件来记录,并通过 devenv 工具来读取、分析和编译。它位于VS目录下的 Common7IDE 目录中。

为了方便直接在 Emacs 下调用 envdev ,可以先把 devenv 所在的目录加进系统 环境变量。例如,我的 devenv 所在的目录为“D:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE”,则可以将该路径添加到 PATH 环境变量中。  Visual Studio图 2 Visual Studio

完成后,打开cmd,执行

1
$ devenv -h

将可以看到如下的提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
e://josephcodesCV_01CV_01>devenv -h
devenv -h
Microsoft (R) Visual Studio Version 9.0.30729.1.
Copyright (C) Microsoft Corp. All rights reserved.
Invalid Command Line. Unknown Switch : h.
Use:
devenv [solutionfile | projectfile | anyfile.ext] [switches]
The first argument for devenv is usually a solution file or project
file. You can also use any other file as the first argument if you
want to have the file open automatically in an editor. When you enter
a project file, the IDE looks for an .sln file with the same base name
as the project file in the parent directory for the project file. If
no such .sln file exists, then the IDE looks for a single .sln file
that references the project. If no such single .sln file exists, then
the IDE creates an unsaved solution with a default .sln file name that
has the same base name as the project file.
Command line builds:
devenv solutionfile.sln /build [ solutionconfig ] [ /project
projectnameorfile [ /projectconfig name ] ]
Available command line switches:
/Build Builds the solution or project with the specified solution
configuration. For example "Debug". If multiple
platforms are possible, the configuration name must be
enclosed in quotes and contain platform name. For
example: "Debug|Win32".
...
To attach the debugger from the command line, use:
VsJITDebugger.exe -p <pid>

按照提示,在VS中创建一个sln工程文件后,使用devenv编译的命令为:

1
$ devenv solutionfile.sln /build [ solutionconfig ] [ /project projectnameorfile [ /projectconfig name ] ]

其中的 /build 等选项可以替换成 /run 等其他选项。

之后可以配置 Emacs,让我们在按下 F7 键后选择各种编译选项。在 .emacs 文件中加入以下内容:

然后将 dev-studio-build 绑定到 F7 键上,例如:

1
2
3
4
(defun my-c-mode-common-hook()
(define-key c-mode-base-map [(f7)] 'dev-studio-build)
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

2 方案二:nmake + .mak

直接编译*.sln文件的缺点在于编译后只会给出结果,而没有错误提示,这样不利于调试。除了直接编译*.sln文件之外,另外的选择是使用微软自家的 make 工具 —— nmake 来编译 Makefile 1 1这里指的 Makefile 是指适用于微软的 nmake 的 Makefile 文件。微软的 nmake 使用了自己的一套标准。如果需要得到适用于GNU Linux 的 Makefile,可以试试 sln2mak 工具。 或者 .mak 文件。但 VS 使用 *.sln 和 *.vcproj 来管理工程项目,并不提供 .mak 文件。为了得到这个文件,可以使用一个 python 脚本 vcproj2mak.py 。使用命令为:

1
$ python vcproj2mak.py 工程文件.vcproj -O makefile文件.mak

执行这个脚本需要满足两个条件:

  1. Python 2.x 或 3.x,安装的时候注意选择注册环境变量,省得自己添加;
  2. 生成的 .mak 文件需要调用 mkdir 指令来创建文件夹,而这个指令是 Unix 下的工具。所以建议装一个 GnuWin 套件,这个套件提供了大量有用的 Unix 工具。

在脚本执行过程中可能会报“unknown encoding”错误,这个原因是 vcproj 文件在 Windows 下的默认编码是 gb2312 的,而 python 似乎不支持 gb2312 。解决的方法是使用 Emacs 打开那个 vcproj 文件,然后 C-x Ret r ,选择 UTF-8 将文件编码改为 UTF-8 格式,并将第一行

1
<?xml version="1.0" encoding="gb2312"?>

中的 “gb2312” 改为 “utf-8” 即可。完成后可以调用 nmake 来执行编译,调用格式为:

1
$ nmake -f mak文件名 编译选项

其中 编译选项 是你的编译方案,一般可以选择 Debug 或者 Release

另外一个问题是当调用过一次 nmake 后,nmake 就会在当前目录下创建 Debug 或者 Release 目录,此时再调用一次 nmake 会提示文件夹创建错误。例如:

1
2
$ mkdir Debug
"d:/Program Files/Git/bin/mkdir.EXE": cannot create directory `Debug': File exists

解决这个问题的方法是修改生成的 .mak 文件,在其中的 “mkdir Debug” 和 "mkdir Release" 两行语句的前面加一个减号 “-” ,表示无论 mkdir 过程中出现什么错误,都不要报错继续执行。更一劳永逸的做法是修改那个 python 脚本,将第207行

1
mkwrite ( fh, "tmkdir %s" % cfname )

改为

1
mkwrite ( fh, "t-mkdir %s" % cfname )

即可。

到这里还没结束,为了让 Emacs 更方便的调用 nmake,可以将 nmake 作为主要的编译工具。在 .emacs 文件中加入这一行:

1
2
;; Set up for Visual C++ compiling
(setq compile-command "nmake -f ")

还有一个更好的做法是再写一个总的 Makefile ,以便于选择编译选项:

1
2
3
4
5
6
7
PROJECT=MyProject
all: debug
debug: FORCE
nmake /f $(PROJECT).mak CFG="$(PROJECT) - Win32 Debug"
release: FORCE
nmake /f $(PROJECT).mak CFG="$(PROJECT) - Win32 Release"
FORCE:

3 方案三:msdev + .dsw

VC 6.0 使用一个更古老的工具 msdev.exe 来编译VC的工程文件。直接调用msdev.exe,即启动Visual studio的UI界面,同时msdev.exe也接受命令行调用。我们看其帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
msdev /?
msdev /?
Usage:
MSDEV [myprj.dsp|mywksp.dsw] - load project/workspace
[] - load source file
/? - display usage information
/EX - execute a vs.ript macro
/OUT - redirect command line output to a file
/USEENV - ignore tools.options.directories settings
/MAKE [] [...] - build specified target(s)
[
-
]
[[
|ALL] - [DEBUG|RELEASE|ALL]]
/CLEAN - delete intermediate files but don't build
/REBUILD - clean and build
/NORECURSE - don't build dependent projects

示例语句:

1
C:Program Files/Microsoft Visual Studio/VC98binmsdev.exe test2.dsw /Make /NORECURSE

同样,使用clean,rebuild可以清除、重编译该工程。将test2 改为test21,test23,即改变编译对象。 总这样写也很麻烦,而且为了在Emacs中调用 ,我们将其写成一个批处理。

1
2
3
4
5
6
7
d:
cd d:Mydocumentsworkbench
set project=%1
set target=%2
if project == set project=test2
if target == set target=/NORECURSE
msdev test2.dsw /Make %target%

保存为makTest2.bat。调用方式为:

1
$ makeTest2 [工程 [目标]]

默认为编译test2 的 /NORECURSE。如果要编译test23的rebuild,调用方式为:

1
$ makeTest2 test23 /REBUILD