物置き

quickrun.vimからVisualC++コンパイラを使う

quickrun.vimという便利なスクリプトがあって、
これを使うと、Pythonほか様々な言語での「ちょっとしたコードを書く->動作確認」という作業をVim上で簡単に実行できるわけなんですが、
Windows環境(非Cygwin)でVisualStudio付属のコンパイラを使って動かせるようにはなっていません。


VisualStudioをしばしば使う者としては、
VCコンパイラでビルドできるようにしたいと思ったので
試行錯誤してみたところ、できたのでここに設定を晒します。

" VisualC++のためのquickrun.vim設定 {{{
if has('win32')

" vsvar32.batへのパス
" (ここを変更することにより使用するVisualStudioのバージョンを切り替えられる)
if exists("g:qr4vc_vsvars32_path")==0
  "	let g:qr4vc_vsvars32_path = 'C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat'
  let g:qr4vc_vsvars32_path = 'C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat'
endif

" コンパイラオプション
if exists("g:qr4vc_options")==0
  let g:qr4vc_options = '/nologo /MDd /EHsc /GR'
endif

" リンクする.libファイルの一覧
" (user32.lib Gdi32.libは強制リンク)
if exists("g:qr4vc_libs")==0
  " MFCを使う場合は下一行を有効に(VCバージョンに対応した.libを指定する必要がある)
  "let g:qr4vc_libs = 'mfc71d.lib'
endif

" quickrunから起動されるバッチファイルのパスを保持するための辞書
let s:qr4vc_batch_path={}
" (Vim終了時に)生成したバッチファイルをクリア
function! s:qr4vc_clear()
  for _ in keys(s:qr4vc_batch_path)
    if filereadable(s:qr4vc_batch_path[_])
      silent! call delete(s:qr4vc_batch_path[_])
    endif
  endfor
endfunction
autocmd VimLeavePre * call s:qr4vc_clear()

" quickrun設定のオーバーライド
" a:ext : 拡張子(0:'c' 1:'cpp')
function! s:qr4vc_regist(ext)
  if exists('g:qr4vc_vsvars32_path') == 0 && execuable('cl')==0 | return | endif
  let keyval = printf("%s%s", g:qr4vc_vsvars32_path, a:ext !=0 ? 'cpp' : 'c')
  if has_key(s:qr4vc_batch_path, keyval) == 0
  let libfiles = 'user32.lib Gdi32.lib '
  if exists('g:qr4vc_libs')
  let libfiles .= g:qr4vc_libs
  endif
  let coptions = ''
  if exists('g:qr4vc_options')
  let coptions .= g:qr4vc_options
  endif
  let extOpt = a:ext!=0 ? '/TP' : '/Tc'
  let cmdlines = [
  \ '@echo off',
  \ '',
  \ executable('cl')==0&&filereadable(g:qr4vc_vsvars32_path)==0 ? 'echo File does not exist - vsvars32.bat&exit' : '',
  \ executable('cl')==0 ? 'call "'. g:qr4vc_vsvars32_path . '" > nul 2>&1' : '',
  \ 'pushd %TMP%',
  \ 'cl ' . coptions . ' /Fea.exe '. extOpt . ' %1 /link ' . libfiles,
  \ 'popd',
  \ 'if "%errorlevel%"=="0" %TMP%\a.exe&del %TMP%\a.exe* %TMP%\%~n1.obj',
  \]
  " NOTE: 後入れのライブラリ(Boost,STLportなど)を使う場合はvsvars32.batにパスを追加する

  let _bat = tempname().'.bat'
silent! call writefile(cmdlines, _bat)
  let s:qr4vc_batch_path[keyval] = _bat
  endif
  let b:quickrun_command = s:qr4vc_batch_path[keyval]
endfunction

augroup quickrun-for-vc
  autocmd!
  autocmd Filetype c  call s:qr4vc_regist(0)
  autocmd Filetype cpp  call s:qr4vc_regist(1)
augroup END

endif
"}}}

上の設定を.vimrcあたりに書いておくと、
ファイルタイプがC/C++の時のquickrunの設定をオーバーライドして、
VCコンパイラを使うよう設定されます。


(やたらと長い感じがしますが、これは中間ファイルを削除したり、
Vim終了時に動的に生成したビルド用バッチファイルを削除したりしているためです。)


以下、注意点メモ書き


VS2003とVC2008Expressでしか動作確認していません


上の設定ではVC2008Expressを利用します。
他のバージョンのVCコンパイラを利用するにはg:qr4vc_vsvars32_pathを適宜修正する必要があります。


エントリポイントはmain関数でもWinMain関数でもいいみたいです。


MFCフレームワークを利用したアプリケーション(CWinApp派生クラスを使うアプリケーション)を実行したい場合
ダミーのエントリポイントを用意してやる必要があります。
(もっとスマートな解決方法がありそうですが)
こんな感じ

#include <afxwin.h>

// ダミーのエントリポイント
int AFXAPI AfxWinMain(HINSTANCE, HINSTANCE, LPTSTR, int);
int WINAPI WinMain(HINSTANCE h1, HINSTANCE h2, LPTSTR p, int n) {
	return AfxWinMain(h1, h2, p, n);
}

struct CMyApp: public CWinApp
{
	virtual BOOL InitInstance();
};
//以下略
...

今までは、ちょっとしたコードを書いて実行するときには
あらかじめ用意してあるSandBox的プロジェクト上でコードを書いていたのですが、
今後はVim上だけでおkということでちょう便利な予感。しばらく使ってみよう

追記(2009-10-15)

上の設定はquickrun.vim 1.2でのものです。


あと、同名の別のQuickRun.vimがあって、こちらはスクリプト本体側でVCコンパイラを使うよう実装されているようです。
ということで、Windows環境でVCコンパイラを使うことを目的として使うのであれば、
そちらを使うのが楽かもしれません。