Task could not find "AL.exe" でエラーが出た時の対応

開発者の環境では出ないエラー

テスト用のビルドは本番とほぼ同様の環境で行うようにしているため、Visual Studio のような開発者が使う IDE はインストールせず、Jenkins から MSBuild を叩いてビルドするようにしています。
ですが、その環境の中で妙なエラーがでました。そして、そのエラーは IDE の入った開発者の PC では一切起きないものでした。

(GenerateSatelliteAssemblies target) ->
  c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(2342
,9): error MSB3086: Task could not find "AL.exe" using the SdkToolsPath "" or t
he registry key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v
7.0A". Make sure the SdkToolsPath is set and the tool exists in the correct pro
cessor specific location under the SdkToolsPath and that the Microsoft Windows
SDK is installed

ちょうど Windows 環境での Git の改行コードを勝手に変更する問題で別のビルドエラーにも苦しんでいた状態だったので訳の分からないビルドエラーにかなーりイライラ。。

AL.exe とは何か?

AL.exe アセンプリ リンカー - MSDN
お恥ずかしながら正直初めて出会ったのですが、アセンブリマニフェストを含むファイルを作成できると書いてあります。まあ、いろいろ説明を斜め読みしていると、どうやらエラーになったビルドにはそのコミットから埋め込みのリソースファイルが入っている事が分かりました。表示文字列をリソースで入れ替えられるような対応をしていたので、おそらくその影響でかなーと。

そして、興味深い一文が。

このツールは Visual Studio および Windows SDK と一緒に自動的にインストールされます

IDE はおろか、Windows SDK も入ってねぇ。。なるほど、確かにエラーメッセージにも「Microsoft SDKs\Windows\v
7.0A」みたいな文字が並んでいます、おそらくそれをインストールすればOKという事でしょう。

Windows SDK を探す

さっそく Winodws SDK をダウンロードしようとしたものの、どうも v7.0A というのが見つからない。見つかるのは 7.1 なのです。

Microsoft Windows SDK for Windows 7 and .NET Framework 4

試しにダウンロード・インストールしてみましたが、エラーメッセージは一向に変わらず。。まあ、バージョン違いますもんね。

v7.0A とは

調べていくと、どうやら Visual Studio 2010 をインストールすると入る SDK のバージョンのようで、普通にインストールする事は難しそうでした。まあ、開発者の PC からディレクトリ毎コピーしてくるという手もあるのですが、どうもやり方として気に入らないので、事例を探しました。

v7.0A のレジストリを作ってしまう

いろいろ調べていると、てっとり早くは、やはり開発マシンから v7.0A を一式コピーしてくるというものでした。レジストリもインポートしてしまえば問題無さそうな事が書いてあります。

もっと簡単な方法は無いか?

私の目的は v7.0A 自体を使う事というよりは、要は AL.exe でビルドさえできればいい。つまり、v7.0A でも v7.1 でもいいのです。もちろん、それで問題が出れば v7.0A を使うしかないのだけれど、なんとか普通にダウンロードしてこれる v7.1 でビルドしたい。というか v7.0A をコピーしてくるのは IDE 依存な気がしていまいちだなーと。

v7.0A のレジストリを v7.1 に向けてしまえばいいのでは?

という事を思いつきました。ヒントは上述したリンクの2つ目の以下の部分でした。

I have found that if you only install Windows SDK 7.1 and .NET 4.0. MSBuild does not set proper paths to SDK40ToolsPath and SDK35ToolsPath. To fix it, I had to change a few entries in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0: "SDK40ToolsPath"="$(Registry:HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v7.1\\WinSDK-NetFx40Tools-x86@InstallationFolder)" Similarly change "v7.0A" to "v7.1" in SDK35ToolsPath and FrameworkSDKRoot

SDKToolsPath の向き先をレジストリレベルで変えてしまえば良いのではという提案です。
いろいろ試行錯誤していると、結果的に私の状況を改善するには、以下のレジストリの変更だけで十分である事がわかりました。

以下のキーを追加。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A

キーに対して以下のように文字列値を追加。

名前: InstallationFolder
データ: C:\ProgramFiles\Microsoft SDKs\Windows\v7.1\


おそらく他の SDK の機能を使うケースがあれば、v7.0A のレジストリをそのままインポートしてしまって、v7.1 に書き換えてしまう方が良いのかもしれません。いずれにしろ、もう少し SDK がどういう役割をしているのかも把握しないと、思わぬ所でハマってしまいそうです。

ようやく私の周りで IDE からの直接発行ではなく、MSBuild でビルドするという流れになりましたが、結構 IDE はよしなにやってくれている事が多いのだなーと思いますね。ビルドを自動化するためには、ちょっとずつ IDE からの依存を切っていかないといけないので、まだまだ先は長そうです。