Visual Studio のコマンドラインクライアントのラッパー vf1s を作った

Visual Studioコマンドラインクライアントのラッパー vf1s を作った。

開発経緯

そもそもは

  1. 会社のルールでバイナリもsvn commitするが、Release版だけでなく、Debug版も用意しなくてはいけない
  2. VBNetには〈バッチビルド〉がなく、一括ビルドできない
  3. 手動で Release選択→ビルド実行→ Debug選択→ビルドすると、Releaseに状態を戻し忘れる
  4. どうせ、提出先ファイルサーバーへのコピーとかはバッチファイル使ってるし、バッチファイルから devenv .com を呼び出して、全部ビルドしたい
  5. devenv .comのディレクトリに場所にパスを通す Visual Studio Command Prompt は起動が重い。そんなに環境変数全部いらんよ
  6. 環境変数が設定されてなくても devenv .com のフルパスさえ分かっていればビルドはできる
  7. devenv .com の場所、VS2015 までと VS2017 以降では探し方が違う。また複数インストールしていると、どちらを呼ぶかの判断もあるので決め打ちは危険
  8. ソリューションファイルが必要としている Visual Studio のバージョンを自動で判断して、適切なバージョンの devenv .com のフルパスを調べて、ついでにわかりにくいオプションも分かりやすいしたツールがあると便利
  9. それ、Go で作ろう

使用するソリューションファイルの決定ルール

  • 引数で指定されていたら、その *.sln ファイルを読む
  • 指定されていなければ、カレントディレクトリにある *.sln を使う。複数ある時はエラー終了

実行する Visual Studio の決定ルール

  • -2010-2019 のオプションがついている時は、それを必ずそのバージョンの Visual Studio を使う。インストールされてなさそうな時はエラー終了
  • どの Visual Studio を実行するかは *.sln ファイルのコメント欄から推定する。( # Visual Studio 2010 などという行が 2,3行目に存在している)
  • *.sln ファイルで指定された Visual Studio がない場合は 2019 から順にインストールされている Visual Studio を探し、見つかった最も新しい Visual Studio を使用する。

Visual Studio クライアント devenv.com の検索ルール

Visual Studio 2010~2015

環境変数に Tools フォルダーにパスが格納されている。

  • 2015 → %VS140COMNTOOLS%
  • 2013 → %VS120COMNTOOLS%
  • 2010 → %VS100COMNTOOLS%

この環境変数に格納されているパスの Tools 部分を IDE に置換すると、devenv.com のあるフォルダー名となる。

Visual Studio 2017~2019

環境変数は廃止されている。そのかわり 2017~2019 では

C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe

というコマンドがある。これの出力から devenv.exe の場所が特定できる。

$ vswhere | findstr productPath
productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe
  • devenv.exe は devenv.com と基本機能は同じだが、コンソールに何も出力されない。コンソール出力を見たいので、拡張子を .com に変えておく。
  • 32bit Windows では C:\Program Files (x86) は存在しない。また、Program Files が C: ドライブ固定とみなすべきではない。vswhere.exe は環境変数 %ProgramFiles% と %ProgramFiles(x86)% 双方の下の Microsoft Visual Studio\Installer から探すようにする。

その上で

  • 最新のみ → vswhere latest
  • 2019 → vswhere -version [16.0,17.0)
  • 2017 → vswhere -version [15.0,16.0)

とすれば Visual Studio のバージョンを指定できる

以上を元にして、我々が呼び出した適切な Visual Studio の devenv.com のフルパスを検出することがほぼ出来るようになった。

使い方

-h オプション、もしくはソリューションファイルがある場所で引数なしで起動すると、ヘルプがでる。

$ vf1s -h
WorkReport.sln: word '2010' found.
%VS100COMNTOOLS% is not set.
look for other versions of Visual Studio.
found 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.com'
  -2010
        use Visual Studio 2010
  -2013
        use Visual Studio 2013
  -2015
        use Visual Studio 2015
  -2017
        use Visual Studio 2017
  -2019
        use Visual Studio 2019
  -a    build all configurations
  -c string
        specify the configuraion to build
  -d    build configurations contains /Debug/
  -i    open ide
  -ll
        list products
  -ls
        list products
  -n    dry run
  -r    build configurations contains /Release/
  -re
        rebuild

使用例:

  • vf1s -a … すべてのコンフィギュレーションの組み合わせ ( Win32 or x64 | Debug or Release ) でビルドする
  • vf1s -d … Debug という単語が含まれているコンフィギューレーションをビルドする
  • vf1s -r … Release という単語が含まれているコンフィギューレーションをビルドする
  • vf1s.exe -2019 -c "Release|x86" -re WorkReport.slnVisual Studio 2019 指定で、 WorkReport.sln というソリューションのRelease|x86 というコンフィギュレーションをリビルドする(全部指定)
  • vf1s -i … ビルドはせず、IDE を起動する
  • vf1s -ls … ビルドはせず、ソリューションファイルから作成される予定のプロダクト(EXE/DLL)のファイル名を標準出力に二重引用符で囲んでタブ区切りで出力する
  • vf1s -ll … ビルドはせず、ソリューションファイルから作成される予定のプロダクト(EXE/DLL)のファイル名を標準出力に改行区切りで出力する

なお、そのソリューションにどういうコンフィギュレーションがあるか、どういうファイルが作成されるかについては、ソリューションファイルとプロジェクトファイル(*.vcxproj,*.csproj,*.vbproj)を真面目に読んで推定している。この解析も結構たいへんだったのだが、今回は説明を見送る(XMLencoding/xml で単純に読んで分かる範囲でがんばっているが、まだ完璧とはいえないので)

MSBuild について

Microsoft は devenv .com ではなく MSBuild を使った方がよいと言っている。だが、VBNet の DLL をビルドする時、なぜか拡張子が .dll.dll という名前で生成されてしまう現象が確認されている(Visual Studio 2013か2015くらいだったと思う)。リネームすればよいのだが、それもあまりスマートとは思えないため、自分は devenv.com を使う方が無難と判断している。

最後に

今日、バイナリもアップロードしたので、よかったら使ってみてください。気に入ったら、チャンネル登録お願いします(まぁ、★でもつけてやってください)

以上