Frogtoss Games
     
 
     
             

Featured Game

Verticube Logo Verticube Screenshots

Break Blocks to Bright Beats!


Emacs Versus Visual Studio

Michael
Apr 2nd, 2003 (Updated and reposted from Kuro5hin July 31st, 2004)


Table of contents

Emacs users have reason to be jealous. The Visual Studio 7 IDE offers features that are seemingly unavailable in Emacs, and are certainly not 'on' by default. Admit it, it doesn't feel good to consider switching from Emacs to Visual Studio, and it certainly doesn't work well to have them both open at the same time.

What's not hopeful is the amount of help out there for aspiring Emacs users who are less than excited about using the Visual Studio 7 IDE, or feel themselves shamefully being wooed away from The One True Editor by the admittedly slick functionality of Visual Studio 7. The goal of this document is to pave the way for Emacs users to integrate with Visual Studio 7, something that is not covered in any depth elsewhere. I focus on Visual C++ (unmanaged), as this is what I spend all my time working with, though a C# programmer would probably see the majority of these tips as a good start.

I attack each issue that I consider important point-by-point. Keep in mind that these are my solutions, which means they're all in use by me, and that you may have a better idea. I'd love to hear it. I hope you find them a good start. It should also be mentioned that I use GNU Emacs 21.1.1 under Windows 2000 with the cygwin tools installed.

Hopefully reading on will fix one or more of your pet peeves with the one true editor, and keep you plugging away on Free Software as much as possible.

Syntax Highlighting

Although I do enjoy Emacs' font-lock mode, it does leave something to be desired after seeing the very fine-grained syntax highlighting of Visual Studio 7. In graphics heavy code such as the code I write, a lot of array lookups are done in tight loops. Visual Studio highlights operators, such as the '[' and ']' operators, which makes array heavy code much more readable. Emacs does not, by default.

Solution: Write new font-lock rules for c++-mode. I haven't included all of the syntax here, but this is what works for me without looking too fruity.

Apologies to regex pros. I get the job done, but I'm not great.

There are multiple ways to assign a face. You will want to do it in a way that is similar to anything you already have customized.

Status compared to Visual Studio: Emacs is a perfectly acceptable alternative. If you turn off precaching of syntax highlighting, it's a bit slower to load a file. Jumping around a 60,000 line c++ source tree on my 1.2ghz Athlon is still easily within acceptable ranges.

Visual Studio 7 lets you right click on a component of a statement (usually a function, variable or typedef) and go to it's definition. This handy feature lets you jump around a source tree in a snappy fashion. Emacs has a similar feature out of the box. You need to build a tags table, which is essentially a precached list of all of the definitions. Go to the root of your source tree, and type:

etags `find -iname "*.cpp"` `find -iname "*.h"`

This produces a file called 'TAGS' in the current working directory. Next, in Emacs, type M-x visit-tags-table and select the TAGS file.

In true Emacs fashion, the best way of navigating the tags is through the bindings. M-. will find a tag. M-* brings your cursor back to the place it was at before the most recent tag find. (Yes, this works recursively!) C-TAB completes the current keyword from the tags table database.

Status compared to Visual Studio: Not quite as smart or accurate as the Visual C++ tag finder. I find myself having to revert to M-x grep from time to time, or M-x occur (try it). On the bright side, there is no latency: the precaching in Emacs makes for one of those rare situations where Emacs is actually faster than Visual Studio in it's default state. I'm also a huge fan of the ability to push and pop my navigation points through the source tree. Mixed bag. I'd choose Emacs over Visual Studio if I had to take one implementation over the other, overall.

Compiling

Getting Visual Studio 7 projects to compile through Emacs is one of the thorniest issues addressed here. If you used Visual C++ 6.0, you know that used to be able to export Makefiles. Well, in its infinite wisdom, Microsoft has removed this ability from Visual Studio 7. Instead, you must invoke the IDE from the command line and get it to build from the .sln file.

If you were to bring up a shell (with devenv.exe and .com in your $PATH), you could type "devenv.com foo.sln /build Debug /out output.log" and have it compile your project from the command line. Caveat - if you don't specify devenv.com, you get devenv.exe, which, for seemingly no good reason, sends it's output somewhere else than stdout, which ensures that you won't see it unless you're running cmd.exe. Always specify devenv.com when building from the command line.

In the simplest case of directory structures, all you need to do to compile a Visual Studio 7 project in Emacs is to set the default compile command:

(setq compile-command "devenv.com foo.sln /build Debug")

The usual C-` to step through the compiler errors works just fine withn the compile buffer's output.

Honestly, I maintain a multi-directory project with some complications, so I call a perl script which actually goes ahead and calls devenv with the proper build configuration. I don't mind keeping that logic out of Emacs. Compiling a Single File

One thing I hate about Visual Studio is what happens when I make a small change in a file, and the entire project's dependancies are checked before a single file is compiled. If you're like me, and you have a ton of dependancies in a big project, it can take upwards of around a minute to compile your single line change. Unfortunately, this minute can become two or three minutes if you muck your changes up and need to recompile. I'd rather compile the file by itself to make sure all of the changes are done and final before calling in the dependancy checker and the linker with the above step. In Visual Studio, I could hit ctrl-F7, but that's the grace an IDE gives you.

We can shell out and run Visual Studio's cl.exe (assuming it's in your path). But, with what arguments and environment? Good question.

You need to set the INCLUDE environment variable for the single file compilation environment. When loading my project, I run this command.

Your mileage will vary. Don't copy this directly, but instead follow the directions above for aquiring your own INCLUDE environment variable set. Compile your project in Visual Studio, and check out the generated buildlog.htm. It will list off the environment the program was compiled in. Grab the contents of the INCLUDE line, and use it in Emacs, remembering to escape the slashes.

Next, we need to address the cl.exe syntax. We want to build the source file similar to the already-built obj files so it will drop in nicely when it's linked. Open the buildlog.htm back up. Near the bottom, there will be talk of options put into a temp file and then passed to cl.exe. We want these in emacs. Therefore, set this variable, which we'll use in a second.

Given that we have defined c++-compile-current-file, the following LISP function compiles against it:

(defun c++-compile-current ()
(interactive)
(let ((compile-command
(concat c++-compile-current-file (buffer-file-name))))
(save-buffer)
(recompile)
))

It'd be cool if I had a Perl script to generate the required LISP based on the contents of a buildlog.htm. I haven't done that yet, though.

Status compared to Visual Studio: A bit of a bitch to get working, but once it works, you're there. Compiling a single file isn't recommended for small projects, as it's a bit of an effort to get working, but you wouldn't need the speed gains on a small project anyway. Considering Visual Studio does this out of the box, there is no contest as to which I'd prefer. But, let's face it, you're taking a chunk of logic usually reserved for IDEs, and making it execute through Emacs. Not bad, considering.

Running Your Program

After you build a binary, you're going to want to run it, right? I simply execute a shell script which sets up the current working directory properly, and runs the debug executable. Consider the following:

(defun shell-run-debug ()
(interactive)
(shell-command "sh rundebug.sh"))

Status compared to Visual Studio: Visual Studio 7 rearranges your windows, sometimes needlessly, when you enter debug mode. In this case, you are waiting for a crash before you are taken into the Visual Studio debugger. In practice, the executable starts up slightly faster. I am annoyed less, but ymmv. Both get the job done.

Page 2


Michael
Apr 2nd, 2003 (Updated July 31st, 2004)