syghの新フラグメント置き場

プログラミングTipsやコード断片の保管場所です。お絵描きもときどき載せます。

Visual C++ 2010以降の追加ディレクトリ

(これは2010-05-04に書いた故OCNブログの記事を加筆修正したものです)

2015-12-03追記:
Visual C++ 2015にも言及するように修正しました。

VC++ 2008までは、「ツール」→「オプション」→「プロジェクトおよびソリューション」→「VC++ディレクトリ」で設定できていた、全プロジェクトというかコンパイラーやリンカーに対するグローバルな「追加のインクルード ディレクトリ」や「追加のライブラリ ディレクトリ」などのことです。

VC++ 2010以降では、このグローバル追加ディレクトリの編集をIDEからGUIを使って行なうことができなくなっています(厳密にはできないわけではありませんが、完全互換ではありません)。

以前と似たようなUIによる設定機能は、「プロジェクト」→「<プロジェクト名>のプロパティ」→「構成プロパティ」→「VC++ディレクトリ」に移動しています。でも、これはあくまでプロジェクト ファイル(.vcxproj)ごとの設定になってしまうので、結局「C/C++」→「全般」→「追加のインクルード ディレクトリ」や「リンカー」→「全般」→「追加のライブラリ ディレクトリ」で設定した場合と同じ意味しか持たないと思います。

以前のようにグローバル設定したい場合は、直接ユーザー プロパティ シートなるXMLファイルをいじる必要があります。具体的には、UTF-8対応のテキストエディターを使って、下記のファイルのIncludePathタグとLibraryPathタグに(セミコロン区切りで)パスを追加設定する必要があります。なお、VS 2008がすでにインストールされている環境にVS 2010をインストールすると、設定を引き継いでくれますが、以後は自分で更新する必要があります。

・Win32 (x86) 用

%LocalAppData%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user.props

サンプルファイル

Win64 (x64) 用

%LocalAppData%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.x64.user.props

サンプルファイル

Windows Vista/7/8の場合、エクスプローラーの右上にある検索ボックスから、「.user.props」でAppDataフォルダー以下を検索すればすぐに見つかります(ただしAppDataフォルダーは隠しフォルダーになっているので、エクスプローラーの設定で表示できるようにしておくこと)。

なお、%LocalAppData%環境変数Windows Vista以降に追加されたものなので、Windows XPの場合は下記になります。XPには%AppData%環境変数は存在するけど、%LocalAppData%とは別物なんですよね(本当にまぎらわしい)……

%UserProfile%\Local Settings\Application Data\Microsoft\MSBuild\v4.0\

スタンドアローンの旧DirectX SDKは、インストール時にVC 2005やVC 2008に対してグローバル追加ディレクトリを自動設定してくれていたのですが、VC 2010の場合はIDE側の仕様変更により設定してくれません。手動でXMLファイルを書き換える必要があります。

実は <D3D10_1.h> や <d2d1.h> などのDirectXコアライブラリのヘッダーは、スタンドアローンの旧Windows SDK 7.xにも含まれているんですが、DX SDKに含まれているヘッダーのほうが新しいので、このプロパティ シート(.user.props)でDX SDKのインクルード パス(C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include)やライブラリパス(C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86)を設定する際には、$(IncludePath)や$(LibraryPath)よりも前のほうに記述することで優先度を上げます。さもないと、<D3DCommon.h> まわりでコンパイル エラーになります。
ただし、VC 2012/2013/2015でWindows SDK 8.0/8.1/10を使い、DirectX 11.1/11.2/11.3/12アプリを開発する場合、旧DirectX SDK(June 2010など)のディレクトリ優先度をWindows SDKディレクトリ($(IncludePath)および$(LibraryPath)に含まれる)よりも上げるのはNGです。要するに必ず新しいほうの優先度を上にする必要があります。
そういった経緯もあって、Visual C++ 2010以降ではIDEグローバル設定よりもプロジェクト単位での追加ディレクトリ設定が推奨されるようになったのかもしれません。

プロパティ マネージャーを使用する方法(バグあり)

実はここで「プロパティ マネージャー」を使用したWindowsログイン ユーザーごとのグローバル追加ディレクトリ設定を行なうための詳しい方法が紹介されていました。MSDNにも一応ここに説明があります。ただプロパティ マネージャーを使う場合はIDEに何らかのVC++プロジェクト ファイルを読み込ませた状態でないとダメらしいです。

しかしこの「プロパティ マネージャー」には致命的な欠陥があります。
Visual C++ 2012/2013/2015は2010と同じ.user.propsファイルを使うようになっているんですが、「プロパティ マネージャー」を使用した方法だと、VC++ 2012でWindowsストア アプリを開発するときに問題が発生します。

具体的にいうと、UIを使った編集を行なって保存した場合、.user.propsファイルの

  <ItemDefinitionGroup />

タグが、

  <ItemDefinitionGroup>
    <ClCompile>
      <AdditionalIncludeDirectories>
      </AdditionalIncludeDirectories>
    </ClCompile>
  </ItemDefinitionGroup>

となってしまう模様(おそらくIDEのバグ)。

後者の状態になると、Visual C++ プロジェクトごとの「追加のインクルード ディレクトリ」の値は、デフォルトの

$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)

ではなく、空の設定値になってしまいます。
この状態でXAMLを使ったストア アプリのC++プロジェクトをそのままビルドしようとすると、App.xaml.h で app.g.h のインクルードに失敗するなどの影響が出てしまいます。
したがって、VC++ 2010以降のグローバル ディレクトリの設定は、プロパティ マネージャーのUIを使わずに、やはり.user.propsの直接編集で対応するようにしたほうが良いでしょう。

ちなみにVS 2012/2013/2015ではx86、x64に加えてARM版も開発できるようになっていますが、ARMの設定も要領は同じです。

総評

おうちのプログラミング環境はVS 2012/2013/2015に移行しましたが、使っているうちに、.user.propsを使うように仕様変更されたおかげでバックアップや設定値コピーがしやすくなったので、今思えばかえって良い仕様変更だったとすら感じます。ただ、コンパイラーのバージョンごとにディレクトリの優先順位を変更したい場合や、リンクするライブラリ ファイルを変えたい場合は、プロジェクト ファイル側でディレクトリ設定値をオーバーライドするか、コンパイラーのバージョンごとにライブラリ ファイル パスを変える方向で対応する必要があります。_MSC_VERマクロや#pragma comment(lib, "*.lib")ディレクティブを使って、ソースコード側にリンカー指令を記述する手もあります。

なお、.user.propsファイルを直接編集する場合は、誤って編集ミスしても簡単にロールバックできるように、VSインストール直後のファイルをバックアップしておくことをお勧めします。この設定ファイルはWindowsログインユーザーごとのファイルなので、たとえ編集ミスしてもそこまで致命的な結果にはなりませんが。