altebute.hatenablog.com

犬も歩けば規格にあたる

Visual Studioで単一のプロジェクト内に同名のソース・ファイルが含まれていてもビルドが通るようにする方法

以下のコードはVisual Studio 2013のデフォルト設定ではエラーとなる。

// ./a/func.hpp 
void func_a();

// ./b/func.hpp
void func_b();

// ./a/func.cpp
#include <iostream>
#include "func_a.hpp"
void func_a()
{
  cout << "a" << endl;
}

// ./b/func.cpp
#include <iostream>
#include "func_b.hpp"
void func_b()
{
  cout << "b" << endl;
}

// ./main.cpp
#include "./a/func.hpp"
#include "./b/func.hpp"
int main()
{
  func_a();
  func_b();
  return 0;
}

原因は、./a/func.cpp./b/func.cppから生成される.objファイルが競合するためである。Visual Studio側の挙動については、以下の記事が詳しい。

Visual Studio 2008では同名のソースファイルを扱うことが出来ない件 - How to disappear completely
http://d.hatena.ne.jp/heisseswasser/20110602/1307014324

結論から先に書きますと、Visual Studio 2008では同名のソースがプロジェクトに含まれていると、どれかコンパイルされるかはファイルの更新日時に依存するようです。
...
一番古いファイルがビルドの対象となるようです。

また、上記の記事からリンクされている記事に、以下のような記述がある。

同名.cppファイルの自動解決は出来ないのか
https://social.msdn.microsoft.com/Forums/ja-JP/3c4e0904-d0ff-4f72-b619-6703f87e03f0/cpp?forum=vcexpressja

②ほかの設定法がある(たとえばプロジェクト→プロパティ→C/C++→出力ファイルに入れるべき適切なマクロが存在する)

以下のように設定することで、生成される.objファイルが競合せず、ビルドが通るようになる。

  1. ソリューションエクスプローラーからプロジェクトを選択
  2. プロジェクト(p)->プロパティ(p)->構成プロパティ->C/C++->出力ファイルを開く
  3. ASM リストの場所及びオブジェクト ファイル名$(IntDir)から$(IntDir)%(RelativeDir)に変更する

上記のようにすることで、Visual Studioが各.cppファイルをコンパイルする過程で、先にコンパイルされたファイルが後でコンパイルされたファイルに上書きされる事が無くなる。各.cppファイルから生成される.objファイルは、元の.cppファイルの相対パスを保持したディレクトリに出力される。

デフォルト設定では、相対パスを無視して、ファイル名のみ保持するため、各.cppファイルをコンパイルする過程で、ファイル名が衝突すると先にコンパイルされたファイルが後でコンパイルされたファイルに上書きされてしまう。