vccompile written in perl

I have written a perl script which can compile all versions of Visual Studio from VS6 to VS2008 (AKA VS9). It requires no hacking of lisp code, the default compile mode will do the job.

The trick is to make the devenv or msdev (for VS6) output look like the output from make(1).

Caveat: you must be using cygwin version of Emacs, not the native win32 Emacs (that will require you to change the script, for the filename is converted to posix format, no longer win32 format). That said, you’d also need the cygwin (1.7 is preferred, which is in beta now), and perl and emacs23 is included in it.

Also, you need make the different versions of availabe in your PATH, by the name of, where N is the version number; a softlink will do, as this is my setup:

$l ~/bin/windows/vc*.com
lrwxrwxrwx 1 bhj None 78 2009-10-11 10:04 /q/bin/windows/ -> /cygdrive/c/Program Files/Microsoft Visual Studio/Common/MSDev98/Bin/MSDEV.COM*
lrwxrwxrwx 1 bhj None 82 2009-10-11 10:04 /q/bin/windows/ -> /cygdrive/c/Program Files/Microsoft Visual Studio .NET 2003/Common7/IDE/
lrwxrwxrwx 1 bhj None 74 2009-10-11 10:04 /q/bin/windows/ -> /cygdrive/c/Program Files/Microsoft Visual Studio 8/Common7/IDE/*
lrwxrwxrwx 1 bhj None 76 2009-10-11 10:04 /q/bin/windows/ -> /cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/IDE/*

(~/bin/windows is in my PATH).

Where to download it


There are other stuff in [[2]], you might find interesting. For e.g., you can also find my .emacs file, and msdn-help from Emacs, etc. Essentially it’s everything from my .bashrc/.inputrc to everything. For e.g., those softlinks are also in the svn, so that I don’t need to ln -s on a new computer, I only need make sure the Visual Studio is installed at its default location.


M-x compile <Enter> vccompile all all <Enter>

The above will compile all the projects (.dsp/.vcproj/.csproj) in your solution (.sln/.dsw) with both release and debug configuations.

It will seek for .dsw/.sln file in the pwd, if not found, look in the parent folder, and so on, so you don’t need to worry about the correct .dsw/.sln file most of the time, because you currect buffer most likely will be already editting the correct .c/.cpp/.cs etc. file, which means the path is also already correct.

vccompile project/all/'' release/debug/OTHER-CONFIG/all/'' (/clean) 

The above is the whole SYNOPSIS for invoking vccompile. The first argument is the project name, you can also specify all to mean all projects, or '' (empty) to mean the first project listed in the .sln/.dsw. The second is what configuration to do the compile. The optional 3rd argument will allow you to do what is like make clean.

Contact information can be found on the googlecode page.


Working with MS Visual Studio devenv command line.

The environment has to be set up before devenv will build from the command line. Here’s the code I have in my .emacs for this (the cmd-shell function needs EmacsW32), and this is for VisualStudio 2005 - obviously for 2003 and VS6 it will be different (look for your vcvars32.bat for clues).

(defun vc-x86-env ()
  (setenv "VSINSTALLDIR" "C:\\Program Files (x86)\\Microsoft Visual Studio 8")
  (setenv "VCINSTALLDIR" "C:\\Program Files (x86)\\Microsoft Visual Studio 8\\VC")
  (setenv "FrameworkDir" "C:\\WINDOWS\\Microsoft.NET\\Framework")
  (setenv "FrameworkVersion" "v2.0.50727")
  (setenv "FrameworkSDKDir" "C:\\Program Files (x86)\\Microsoft Visual Studio 8\\SDK\\v2.0")
  (setenv "CommonDevEnvDir" "C:\\Program Files (x86)\\Microsoft Visual Studio 8\\Common7")
  (setenv "DevEnvDir" 
	  (concat (getenv "CommonDevEnvDir") "\\IDE")) ;; "C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\\Common7\\IDE")
  (setenv "PATH" 
	  (concat (getenv "DevEnvDir") ;;"C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\\Common7\\IDE"
		   (concat (getenv "VCINSTALLDIR") "\\BIN") ;;"C:\\Program\ Files (x86)\\Microsoft\ Visual\ Studio 8\\VC\\BIN"
		   (concat (getenv "CommonDevEnvDir") "\\Tools") ;;  "C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\\Common7\\Tools"
		   (concat (getenv "CommonDevEnvDir") "\\Tools\\bin") ;;   "C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\\Common7\\Tools\\bin"
		   (concat (getenv "VCINSTALLDIR") "\\PlatformSDK\\bin") ;;  "C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\\VC\\PlatformSDK\\bin"
		   (concat (getenv "FrameworkSDKDir") "\\bin") ;; "C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\\SDK\\v2.0\\bin"
		   (concat (getenv "FrameworkDir") "\\" (getenv "FrameworkVersion")) ;;  "C:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727"
		   (concat (getenv "VCINSTALLDIR") "\\VCPackages") ;;  "C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\ 8\VC\VCPackages"
		   (getenv "PATH")))
  (setenv "INCLUDE"
	   (concat (getenv "VCINSTALLDIR") "\\ATLMFC\\INCLUDE")
	   (concat (getenv "VCINSTALLDIR") "\\INCLUDE")
	   (concat (getenv "VCINSTALLDIR") "\\PlatformSDK\\include")
	   (concat (getenv "VSINSTALLDIR") "\\SDK\\v2.0\\include")
	   (getenv "INCLUDE")))
  (setenv "LIB" (concat 
		 (concat (getenv "VCINSTALLDIR") "\\ATLMFC\\LIB")
		 (concat (getenv "VCINSTALLDIR") "\\LIB")
		 (concat (getenv "VCINSTALLDIR") "\\PlatformSDK\\lib")
		 (concat (getenv "VSINSTALLDIR") "\\SDK\\v2.0\lib")
		 (getenv "LIB")))
  (setenv  "LIBPATH" 
	    (concat (getenv "FrameworkDir") "\\" (getenv "FrameworkVersion")) ;;  "C:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727"
	    (concat (getenv "VCINSTALLDIR") "\\ATLMFC\\LIB")))

Commands like..

devenv Projects/MyProgram/Solution.sln /project Projects/MyProgram/Project.vcproj /Config "Debug|x86" /Clean

..can then be used in the shell buffer that is started by the command vc-x86-env. Obviously, paths may haye to change for different install locations, etc. And also for an x86/x64 setup. See devenv /help or MSDN for the full explanation!

For actually invoking devenv, here is a handy interactive function..

(defun is-devstudio-solution (filename)
   (null (file-name-extension filename))
   (string= (file-name-extension filename) "sln")))

(read-file-name "Solution: " nil nil t nil 'is-devstudio-solution) 

(defun extract-projects (sln-file)
      (insert-file sln-file)
      (goto-char (point-min))
      (let ((result nil)
	    (index 0))
	     "Project(\"{[-A-Z0-9]+}\")[ 	]+=[ 	]+\"\\([A-Za-z0-9_]+\\)\"[ 	]*,[ 	]+\"\\([\\A-Za-z0-9_.]+\\)\""
    (add-to-list 'result (cons (match-string-no-properties 1) (match-string-no-properties 2))))

(defun dev-studio-build ()
	(read-file-name "Solution: " nil nil t))
	(extract-projects solution-name))
	(completing-read "Action: " '(("Build" . 0) ("Clean" . 1) ("Run" . 2) ("RunExit" . 3))
			 nil t "Build"))
	(completing-read "Configuration: " '(("Debug" . 0) ("Release" . 1) ("Hybrid" . 2))
			 nil t "Debug"))
	(completing-read "Platform: " '(("Win32" .0) ("x86" . 1))
			 nil t "Win32"))
	(completing-read "Project " projects
			 nil t (caar projects))))
     (concat "Devenv \"" solution-name "\" /" action " \""  (concat configuration "|" platform) "\" /project \"" (cdr (assoc project projects)) "\""))))

A better longer term solution is to migrate away from microsofts platform specific solution building system towards something more platform neutral like make or scons or bjam or whatever, but if the pointy-haired-boss insists on Microsoft, this is at least, a useful band-aid. johnfredcee

Sending current file to Emacs from Visual Studio

If you use gnuserv, try VisEmacs.

If you use EmacsW32 which comes with emacsclient instead of gnuserv you can use the following macro in Visual Studio:

    Sub OpenInEmacs()
        Dim filename As String
        Dim linenumber As Integer
        Dim column As Integer
        linenumber = DTE.ActiveDocument.Selection.ActivePoint.Line
        column = DTE.ActiveDocument.Selection.ActivePoint.VirtualDisplayColumn
        filename = DTE.ActiveDocument.FullName
        DTE.StatusBar.Text = "Opening " + filename + ":" + linenumber.ToString + " in Emacs"
        Shell("emacsclientw.exe" + " -n +" + linenumber.ToString + ":" + column.ToString + " " + filename)
    End Sub

Simply bind it to a key or menu command and it will open the current file in Emacs at the current line.

Another way to do this, without a macro...

In visual Studio, Configure external tools. Add a tool with the following configuration:

Name: Emacs (for example)
Location: c:\path-to\emacsclientw.exe
Arguments: -n +$(CurLine):$(CurCol) $(ItemFileName)$(ItemFileExt) 
*note there is a variable button that will help you with the shortcuts like $(CurLine)
WorkingDirectory: $(ItemDirectory)

Sample for VS2010

Name: Emacs 
Location: c:\path-to\emacsclientw.exe
Arguments: -n +$(CurLine):$(CurCol) $(ItemPath)
*note there is a variable button that will help you with the shortcuts like $(CurLine)
WorkingDirectory: $(ItemDirectory)

Then bind whatever keys you prefer to the external tools (Will be called something like Tools.ExternalCommandn, with n depending on your tool order) in your keyboard preferences (I use Ctl-Alt-E).

See Also

Opening a visual studio solution in emacs:

For Visual Studio-style bookmarking: