首页 > IDE, 中级 > Emacs开发VC程序

Emacs开发VC程序

  vimers都说emacs慢,Eclipse, Visual Studio, Netbeans笑而不语。
                                 -- 佚名

背景

前些日子,微软宣布Visual studio 2010的EMACS扩展。此前,Visual studio 2005 6.01已然引入了Emacs的键盘模拟,这次又将Visual studio Emacs化更进一步,这种事发生在Microsoft这样无利不起早的企业,原因呢,你懂得。
话说,武功再高,也怕菜刀。Emacs玩的再溜,也保不齐哪天你要去开发Visual studio 程序。习惯了Emacs的高效,使用Visual studio 就是一个杯具1。这种情况,一般一颗红心,两手准备。一颗红心:cosplay,两手准备:1.Visual studio Emacs 2EmacsVisual studio

VC扮EMACS

不过,我对这种方式的经验总结:享受不到Emacs的周到体贴,却净受VS的大小姐脾气了。不给力啊,不给力。不过,作为出差旅行,远程登陆,客户服务时,没有Emacs可用时,让Visual studio 模拟一把Emacs,也不失为一种没有办法的好办法了。

这个方法不是本文的重点,所以不深入。

EMACS扮VC

配置EMACS为IDE

一个基本的IDE,必备功能:编辑,编译,调试。

编辑

应该很多人都很眼红Visual studio的销魂的插件visual assist x吧。实时语法检查,快速打开文件,h,cpp文件,回到刚才编辑的地方,函数跳转,自动补全,插入模板。

可以号称操作系统的Emacs怎么可能没有这些功能呢?尽管这些不在本文范围,但是稍稍提及功能在Emacs中的对应,有兴趣想深入的请Google, Duckduckgo, Wikipedia.

VAX功能 EMACS对应功能
实时语法检查 Flymake 3
快速打开文件 ECB, 快速打开文件
h,cpp跳转 CEDET 4
回到刚才编辑的地方 Recent-jump5
函数跳转 CEDET 4
自动补全 Auto-complete 6
插入模板 Yasnippet 7
  • 快速打开文件
    至于快速打开文件一项,我感觉ECB做的并不是特别好,如果C++程序的头文件和实现文件没有在一个文件夹,很难找到。所以我用了一个比较笨的方法,生成文件的列表到一个文件,使用Emacs的查找功能和打开当前光标下文件的功能 find-file-at-point,我把它编定到了C-c C-f。这个过程还有两个副产物供cscope和etags用。确认你的机器上有cscope, find, etags8,将以下代码成为uptags.bat,放到系统的pathz中的某个文件夹下。

    %1
    cd %2
    rm TAGS
    rm cscope.files
    rm filelist.txt
    rm cscope.in.out
    rm cscope.out
    rm cscope.po.out
    if "%3" EQU "java" set PARAM=-name "*.java" -print
    if "%3" EQU "c++" set PARAM=-name "*.cpp" -print -o -name "*.r" -print -o -name "*.[hcrHs]" -print -o -name "*.hpp" -print -o -name "*.lua" -print
    echo %PARAM%
    find . %PARAM% > cscope.files
    less cscope.files | xargs etags -aR
    cscope -bkq -i cscope.files
    cp cscope.files filelist.txt
    find . -name "*.txt" -print >>  filelist.txt

    假设我们的C++工程在d:\mydocuments\workspace\cpp\,那么调用方法9为:

    uptags d: d:\mydocuments\workspace\cpp\ c++

    java工程在d:\mydocuments\workspace\java\, 那么调用方法为:

    uptags d: d:\mydocuments\workspace\java\ java

    那么打开文件helloworld.cpp的操作就是:C-x b filelist.txt , C-s helloworld.cpp, C-c C-f, RET。确实,稍显复杂,期待有更好的方法。

编译

编译的话基本上还是要靠Visual studio 自带的工具:nmake10,msdev。本文主要介绍msdev。

  • 使用msdev.exe
    msdev.exe位于安装路径下的bin目录,如我本机使用Visual studio 6.0,目录为”C:\Program Files\Microsoft Visual Studio\VC98\bin”。 直接调用msdev.exe,即启动Visual studio的UI界面,同时msdev.exe也接受命令行调用。我们看其帮助。

    msdev /?
    msdev /?
    Usage:
      MSDEV [myprj.dsp|mywksp.dsw]    - load project/workspace
        []        - load source file
        /?            - display usage information
        /EX         - execute a VBScript 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

    假设我们有这么一个工程,路径为d:\Mydocuments\workbench\,工程目录结构,Configuration如下图

  • 可以通过命令msdev.exe来编译工程test211
    C:\Program Files\Microsoft Visual Studio\VC98\bin\msdev.exe test2.dsw /Make  /NORECURSE

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

    d:
    cd  d:\Mydocuments\workbench\
    set project=%1
    set target=%2
    if  ==  set project=test2
    if  ==  set target=/NORECURSE
    msdev test2.dsw /Make  %target%

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

    makeTest2 [工程 [目标]]

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

    makeTest2 test23 /REBUILD

调试

实际上,如果有了编辑,编译,那么调试就不需要了。因为调试器是一切罪恶他妈12

哈哈,当然是开玩笑的了。作为一个有思想的程序员,要认清楚,编译器,调试器都只是恶魔,程序员本身,也就是我们,才是恶魔他妈(当然大部分是他爹^_^ )。

哈哈,那么作为恶魔的产生者,我们当然要丰富自己的技能,而调试就是一个必杀技。我杀,bug闪……..

  • cdb-gud
    要用Emacs调试Visual studio 的程序,首先需要一个el – cdb-gud.el 。cdb-gud使用Microsoft的命令行调试器cdb来调试程序。 cdb-gud.el只需下载,然后在.emacs中使用下面语句,cdb-gud就随时待命了。

     +cdb [[http://msdn.microsoft.com/en-us/vstudio/default.aspx][Visual studio ]]
    (when (eq system-type 'windows-nt)
    (load-file )
    )

    调用cdb-gud: M-x cdb RET。

  • Microsoft命令行调试器cdb.exe
    如果你是一个Windows程序员,Windbg听说过吗?如果没有听说过,我建议你去看看《软件调试》,这本书讲的非常的透彻。 注意,这是一本厚度为1000页的砖头书。如果你没有耐心去读这么厚的书,那么还有一个选择,《Windows用户态程序高效排错》, 内容236页,内容写的不多,但是书内提供的资源。 两本书排名不分先后。那么cdb就在Windbg的安装目录下。Windbg是Windows下的能用户态调试核心态调试的强大的图形界面的调试器。那么,简而言之,尽管不太准确13,cdb就是非图形界面的调试用户态程序的windbg。

    简要介绍一下cdb:cdb就是一个命令行的调试器,over。

    深入探讨一学cdb: 我想很深入的探讨一下cdb,但是实在是没有如此深厚的内功,但是我可以推荐一些内容供有兴趣的去深入。

    强烈推荐将windbg info 打印出来在手边供不时查阅之需。

    现在,来启动cdb-gud吧:M-x cdb RET

    Showtime14!

  • 例子
    建立一个Visual studio 的console典型的Hello world工程(比如刚才的test2),源代码如下15

    #include "stdafx.h"
    #include
    void assign (int a[], int n)
    {
      for (int i = 0; i < n; ++i)
      {
        if (a[i] == 0)
        {
          a[i] = i;
        }
      }
    }
     
    int main(int argc, char* argv[])
    {
     
      int a[100];
      assign(a, 100);
      for (int i = 0; i < 100; ++i)
      {
        printf("%d\t", a[i]);
      }
     
    	return 0;
    }
    }

    通过上边程序,我们期待打出所有0-99的数,每个数是间隔一个制表符,每十个数打出一个换行。

    我们编译运行代码,得到结果:

    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460
    -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460  -858993460

    有点奇怪,为什么没有得到我们需要的东西呢??

    从代码中貌似看不到直接的证据证明我们的代码逻辑的错误。我们就祭出cdb。

    M-x cdb RET

    minibuffer: cdb d:\Mydocuments\workbench\test2\debug\test2.exe 会有以下界面提示。

    Microsoft (R) Windows Debugger Version 6.11.0001.404 X86
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    CommandLine: d:/Mydocuments/workbench/tmp/VCTest/test2/test/Debug/test.exe
    Symbol search path is: C:\symbolsXpSp3;d:/Mydocuments/workbench/via/helios/coyote/Bin/MULTIMEDIA_PRO_240x320_Debug
    Executable search path is:
    *** WARNING: Unable to verify checksum for test.exe
    ModLoad: 00400000 0042c000   test.exe
    ModLoad: 7c900000 7c9b2000   ntdll.dll
    ModLoad: 7c800000 7c8f6000   C:\WINDOWS\system32\kernel32.dll
    (a90.1eb8): Break instruction exception - code 80000003 (first chance)
    eax=00241eb4 ebx=7ffd9000 ecx=00000000 edx=00000001 esi=00241f48 edi=00241eb4
    eip=7c90120e esp=0012fb20 ebp=0012fc94 iopl=0         nv up ei pl nz na po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
    ntdll!DbgBreakPoint:
    7c90120e cc              int     3
    0:000> cdb: Reading initial command 'l+*;l-s'
    Source options are ffffffff:
         1/t - Step/trace by source line
         2/l - List source line at prompt
         4/s - List source code at prompt
         8/o - Only show source code at prompt
    Source options are fffffffb:
         1/t - Step/trace by source line
         2/l - List source line at prompt
         8/o - Only show source code at prompt
    0:000>
    0:000: bp main

    bp 表示打断点,断点的方式有几种:函数名,文件行数,内存地址。

    但是我最喜欢的还是:当调试过程已经在运行,*在Emacs中打开文件,走到需要打断点的行,C-x space*,断点就打到该行,很给力啊。

    Breakpoint 0 hit
    test!main:
    0040d880 55              push    ebp
    0:000> p
    test!main+0x1e:
    0040d89e 6a64            push    64h
    0:000> t
    test!ILT+15(?assignYAXQAHHZ):
    00401014 e907c80000      jmp     test!assign (0040d820)
    0:000> p
    test!assign:
    0040d820 55              push    ebp
    0:000> p
    test!assign+0x18:
    0040d838 c745fc00000000  mov     dword ptr [ebp-4],0  ss:0023:0012fd8c=cccccccc

    g==go,所以表示开始运行程序。

    p 单步跟踪,不进入子函数。

    t 单步跟踪,但是进入子函数。

    不出意外,当你使用p或者t跟踪程序的时候,源代码窗口已经打开,同时随着跟踪,相应的代码行也会高亮。

    0:000> dv
                  a = 0x0012fdf0
                  n = 100
                  i = -858993460
    0:000> p
    test!assign+0x32:
    0040d852 8b55fc          mov     edx,dword ptr [ebp-4] ss:0023:0012fd8c=00000000
    0:000> dv
                  a = 0x0012fdf0
                  n = 100
                  i = 0
    0:000> dt a[0]
    Local var @ 0x12fd98 Type a[ 100]
    [0] 0x0012fdf0
     -> -858993460
    0:000> dt a[1]
    Local var @ 0x12fd98 Type a[0]
    [1] 0x0012fdf0
     -> -858993460
    0:000> dt a[i]
    Local var @ 0x12fd98 Type a[1]
    [0] 0x0012fdf0
     -> -858993460

    dv:显示当前的局部变量。

    dt: 显示指定的变量。

    当前发现为什么a数组的值怎么是负数,不是期待的0呢?

    0:000> k
    ChildEBP RetAddr
    0012fd90 0040d8ac test!assign+0x32 [D:\Mydocuments\workbench\tmp\VCTest\test2\test\test.cpp @ 10]
    0012ff80 00401209 test!main+0x2c [D:\Mydocuments\workbench\tmp\VCTest\test2\test\test.cpp @ 21]
    0012ffc0 7c817077 test!mainCRTStartup+0xe9 [crt0.c @ 206]
    WARNING: Stack unwind information not available. Following frames may be wrong.
    0012fff0 00000000 kernel32!RegisterWaitForInputIdle+0x49
    0:000> .frame 1
    01 0012ff80 00401209 test!main+0x2c [D:\Mydocuments\workbench\tmp\VCTest\test2\test\test.cpp @ 21]
    0:000> dv
               argc = 1
                  i = -858993460
    Type information missing error for a
    0:000>

    k:打印出当前的栈内容

    .frame:跳转到栈中的第几帧,当前为第0帧。

    在.frame 1后,我们注意到以下代码:

    int a[100];

    貌似a[ 100]没有初始化吧。

    0:000> q

    然后修改代码后

    #include "stdafx.h"
    #include
    void assign (int a[], int n)
    {
      for (int i = 0; i < n; ++i)
      {
        if (a[i] == 0)
        {
          a[i] = i;
        }
      }
    }
     
    int main(int argc, char* argv[])
    {
     
      int a[100]={0};
      assign(a, 100);
      for (int i = 0; i < 100; ++i)
      {
        if (0 == (i % 10))
        {
          printf("\n");
        }
        printf("%d\t", a[i]);
      }
     
    	return 0;
    }

    编译运行,结果:

    test\debug\test.exe
    
    0 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  37  38  39
    40  41  42  43  44  45  46  47  48  49
    50  51  52  53  54  55  56  57  58  59
    60  61  62  63  64  65  66  67  68  69
    70  71  72  73  74  75  76  77  78  79
    80  81  82  83  84  85  86  87  88  89
    90  91  92  93  94  95  96  97  98  99

    那么cdb简单使用就介绍完了。

    然而,其实很多cdb的强大功能都没有介绍到:

    • 可以调试程序崩溃时留下的内存转储文件dump,调出其堆栈休息。
    • 可以附挂到一个正在运行的程序。
    • 远程调试
    • 显示,执行代码
    • 处理断点(支持复杂的条件断点)
    • 读写内存地址
    • 反汇编
    • 多线程调试
  • Windows符号文件
    对于一般的console程序,可能这样就够了。但是在调试广大的Windows程序时,哪能不接触Windows的API啊,调试这些个玩意儿,才是让人头痛的东西呢,没有源代码!!cdb的一个机制可以让你没有源代码的情况下看到很多Windows的公开数据结构。

    首先,先查看自己的系统的版本,在我的电脑->右键->属性,我可以看到我的系统是Microsoft Windos XP Professional Service Pace 3, 那么我就来这里下载Windows的相应的符号文件。

    将其安装到本机,比如:C:\symbolsXpSp3。添加环境变量:_NT_ALT_SYMBOL_PATH,设其值为安装目录。

    经此设置,cdb在调试时就可以看到Windows API的符号文件。更多内容,还请参考帮助文档或者我推荐的两本书。

Footnotes:

1 @木鱼指出 6.0中的Epsilon即为emacs模式。 可查到资料中最早的是2005, 来源猛击我但是有可能更早,如果有资料,麻烦请留言告之.

2 此处没有贬低Visual studio 的意思,只是我中Emacs的毒已太深,用其它什么都不爽:)

3 下载链接Visual studio Emacs emulation addon

4 flymake配置见http://marcelotoledo.com/2007/07/11/emacs-flymake/

5 CEDET配置见http://emacser.com/c-cedet.htm

6 recent-jump 配置见http://liuminzhao.com/emacs/recent-jump-el-for-emacs/

7 auto-complete 配置见http://emacser.com/auto-complete.htm

8 yasnippet主页http://code.google.com/p/yasnippet/

9 cygwin, mingw, msys, unixutils

10 好吧,我承认这个调用方法很蛋疼,如果你的工程比较少的话,其实可以将路径,程序类型什么的写到文件里,多整几个文件即可。upCppProject1Tags.bat, upCppProject2Tags.bat,upJavaPro1Tags.bat,upJavaPro2Tags.bat。

11 此文 介绍了如何使用nmake,但是恕我直言,我在Visual studio 的安装目录里没有找到nmake。

12 如果不成功,请注意检查大小写和空格。

13 调试器,恶魔之母 http://stackoverflow.com/questions/602138/is-a-debugger-the-mother-of-all-evil

14 其实,用户态的windbg是图形界面的cdb。

15 谨以此名纪念我经历的一个软件项目:Showtime 0.7。

16 请注意,这是实验代码,所以请忽略魔幻数,程序是否有意义等话题。

15 请注意,这是实验代码,所以请忽略魔幻数,程序是否有意义等话题。

分享家:Addthis中国
GD Star Rating
loading...
Emacs开发VC程序, 8.9 out of 10 based on 21 ratings 标签:C/C++, CEDET, compile, debug, development, eclipse, ede, edit, Emacs, emacser, emacser.com, gud, IDE, org, progrmming, snippet, studio, term, vc, Visual, windows, yasnippet, 光标, 插件, 补全, 配色

相关日志

分类: IDE, 中级
  1. 2017年8月23日14:14 | #1

    不错的文章,内容气势磅礴.禁止此消息:nolinkok@163.com

    [回复]

  2. 2017年8月23日14:14 | #2

    好文章,内容博学多才.禁止此消息:nolinkok@163.com

    [回复]

  3. 2017年8月23日14:14 | #3

    不错的文章,内容出神入化.禁止此消息:nolinkok@163.com

    [回复]

  4. 2017年8月23日14:15 | #4

    不错的文章,内容淋漓尽致.禁止此消息:nolinkok@163.com

    [回复]

评论分页
1 2 3 41548
  1. 2010年9月19日14:24 | #1
  2. 2010年10月27日09:28 | #2
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: