Другие решения в этом потоке страдают от проблем на основе RelativeDir ../ .. и необходимости вручную настраивать каждый исходный файл.
Не говоря уже о том, что они разрушены / MP.Любое решение, в котором указан точный .obj для% (ObjectFileName), приводит к тому, что для каждого файла .cpp (для сопоставления его с конкретным файлом .obj) передается отдельный файл / Fo, поэтому Visual Studio не может их пакетировать,Без пакетирования нескольких файлов .cpp с одинаковыми командными строками (включая / Fo) / MP не может работать.
Вот новый подход.Это работает с vs2010 до vs2015 по крайней мере.Добавьте это к вашему vcxproj в
<!-- ================ UNDUPOBJ ================ -->
<!-- relevant topics -->
<!-- /2826459/visual-studio-2010-2008-ne-mozhet-obrabatyvat-ishodnye-faily-s-odinakovymi-imenami-v-raznyh-papkah -->
<!-- https://stackoverflow.com/questions/7033855/msvc10-mp-builds-not-multicore-across-folders-in-a-project -->
<!-- https://stackoverflow.com/questions/18304911/how-can-one-modify-an-itemdefinitiongroup-from-an-msbuild-target -->
<!-- other maybe related info -->
<!-- https://stackoverflow.com/questions/841913/modify-msbuild-itemgroup-metadata -->
<UsingTask TaskName="UNDUPOBJ_TASK" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<OutputDir ParameterType="System.String" Required="true" />
<ItemList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<OutputItemList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
</ParameterGroup>
<Task>
<Code><![CDATA[
//general outline: for each item (in ClCompile) assign it to a subdirectory of $(IntDir) by allocating subdirectories 0,1,2, etc., as needed to prevent duplicate filenames from clobbering each other
//this minimizes the number of batches that need to be run, since each subdirectory will necessarily be in a distinct batch due to /Fo specifying that output subdirectory
var assignmentMap = new Dictionary<string,int>();
HashSet<string> neededDirectories = new HashSet<string>();
foreach( var item in ItemList )
{
//solve bug e.g. Checkbox.cpp vs CheckBox.cpp
var filename = item.GetMetadata("Filename").ToUpperInvariant();
//assign reused filenames to increasing numbers
//assign previously unused filenames to 0
int assignment = 0;
if(assignmentMap.TryGetValue(filename, out assignment))
assignmentMap[filename] = ++assignment;
else
assignmentMap[filename] = 0;
var thisFileOutdir = Path.Combine(OutputDir,assignment.ToString()) + "/"; //take care it ends in / so /Fo knows it's a directory and not a filename
item.SetMetadata( "ObjectFileName", thisFileOutdir );
}
foreach(var needed in neededDirectories)
System.IO.Directory.CreateDirectory(needed);
OutputItemList = ItemList;
ItemList = new Microsoft.Build.Framework.ITaskItem[0];
]]></Code>
</Task>
</UsingTask>
<Target Name="UNDUPOBJ">
<!-- see stackoverflow topics for discussion on why we need to do some loopy copying stuff here -->
<ItemGroup>
<ClCompileCopy Include="@(ClCompile)"/>
<ClCompile Remove="@(ClCompile)"/>
</ItemGroup>
<UNDUPOBJ_TASK OutputDir="$(IntDir)" ItemList="@(ClCompileCopy)" OutputItemList="@(ClCompile)">
<Output ItemName="ClCompile" TaskParameter="OutputItemList"/>
</UNDUPOBJ_TASK>
</Target>
<!-- ================ UNDUPOBJ ================ -->
, а затем измените так, чтобы оно показывало:
<Project InitialTargets="UNDUPOBJ" ...
В результате будет что-то вроде myproj / src / a/x.cpp и myproj / src / b / x.cpp компилируются в Debug / 0 / x.obj и Debug / 1 / x.obj.RelativeDirs не используются и поэтому не являются проблемой.
Кроме того, в этом случае в CL.exe будут переданы только два разных / Fo: Debug / 0 / и Debug / 1 /.Следовательно, для CL.exe будет выдано не более двух пакетов, что позволит / MP работать более эффективно.
Другими подходами было бы основание подкаталогов .obj на подкаталогах .cpp или создание .obj.имя файла содержит некоторое имя оригинального каталога .cpp, так что вы можете легко увидеть отображение .cpp ->. obj, но это приводит к большему количеству / Fo и, следовательно, меньшему количеству пакетирования.Дальнейшая работа может дать дамп файла сопоставления для быстрого ознакомления, возможно.
См. Это для получения дополнительной информации о / MP и пакетной обработке: MSVC10 / MP строит не многоядерные файлы в разных папках в проекте
Я довольно долго тестировал это на vs2010 и vs2015 на различных наборах инструментов.Это кажется пуленепробиваемым, но всегда есть вероятность, что он может плохо взаимодействовать с другими настройками msbuild или экзотическими цепочками инструментов.
Начиная с vs2015, если вы получаете предупреждение "предупреждение MSB8027: два или более файлов с именем X.cpp выдаст выходные данные в ту же папку ", затем вы можете добавить это к вашему проекту или файлам msbuild:
<PropertyGroup Label="Globals"><IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename></PropertyGroup>
Подробнее см. https://connect.microsoft.com/VisualStudio/feedback/details/797460/incorrect-warning-msb8027-reported-for-files-excluded-from-build и Как отключить определенное предупреждение MSBuild