Пользовательская общая цель для построения решения

Я создал настраиваемую общую цель "RealClean", которая удаляет все файлы в каталоге вывода и "промежуточного вывода". Я поместил его в файл Microsoft.Common.targets. Когда я запускаю MsBuild на моем csproj, все в порядке. Но когда я запускаю MsBuild на моем sln (который просто ссылается на список csproj), у меня есть следующая ошибка

error MSB4057: The target "RealClean" does not exist in the project.

Ниже приведена командная строка для запуска MsBuild

C:\Windows\Microsoft .NET\Framework\v3.5\MsBuild.exe /p:Configuration="Release";OutputPath="..\..\MSBuild.Referentiel.net35";nowarn="1591,1573" /t:RealClean mySolution.sln

Любые подсказки?

Ответ 1

Чтобы работать с файлом решения, MSBuild создает временный файл проекта MSBuild, содержащий только некоторые объекты, такие как Сборка и Очистить. Таким образом, вы не можете вызвать свою настраиваемую цель в файле решения.

Ответ 2

У меня была такая же проблема, но я не хотел изменять вещи за пределами исходного дерева, чтобы заставить это работать. Добавление файлов в C:\Program Files... означает, что вы должны сделать это вручную на каждом dev-машине, чтобы получить такое же поведение.

Я сделал три вещи:

1) Создал файл пользовательских целей, который я импортирую в каждый проект С# и/или VB/F # в своем решении, добавив в каждый файл proj следующее:

<!-- Rest of project file -->

<PropertyGroup Condition="'$(SolutionDir)' == '' or '$(SolutionDir)' == '*undefined*'">
    <!-- Relative path to containing solution folder -->
    <SolutionDir>..\</SolutionDir>
</PropertyGroup>
<Import Project="$(SolutionDir)CommonSettings.targets" />

2) Добавлена ​​чистая цель, которая вызывается после реальной очистки (используя атрибут AfterTargets из MSBuild 4.0):

<Target Name="CleanCs" AfterTargets="Clean">
    <Message Text="Deep cleaning C# project..." />
    <CreateItem Include="$(OutDir)**\*.*; $(ProjectDir)\obj\**\*.*; $(IntermediateOutputPath)**\*.*"
                            Exclude="**\bin\**\*.vshost.exe; $(IntermediateOutputPath)**\*.log">
        <Output TaskParameter="Include" ItemName="AfterClean_FilesToDelete"/>
    </CreateItem>
    <Delete Files="@(AfterClean_FilesToDelete)" />
    <CreateItem Include="$(ProjectDir)\obj\" >
        <Output TaskParameter="Include" ItemName="AfterClean_DirectoriesToDelete" />
    </CreateItem>
    <CreateItem Include ="$(ProjectDir)\bin\" Condition="'$(TargetExt)' != '.exe'" >
        <Output TaskParameter="Include" ItemName="AfterClean_DirectoriesToDelete"/>
    </CreateItem>
    <RemoveDir ContinueOnError="true" Directories="@(AfterClean_DirectoriesToDelete)" />
</Target>

3) В моем проекте MSBuild с непрерывной интеграцией я проверяю и удостоверяюсь, что все файлы proj имеют # 1:

<ItemGroup>
    <!-- Exclude viewer acceptance tests as they must compile as x86 -->
    <CheckProjects_CsProjects Include="**\*.csproj" />
</ItemGroup>
<Target Name="CheckProjects">
    <!-- 
        Look for C# projects that don't import CommonSettingsCs.targets 
    -->
    <XmlRead XPath="//n:Project[count(n:Import[@Project[contains(string(), 'CommonSettingsCs.targets')]]) = 0]/n:PropertyGroup/n:AssemblyName/text() "
        XmlFileName="%(CheckProjects_CsProjects.Identity)"
        Namespace="http://schemas.microsoft.com/developer/msbuild/2003"
        Prefix="n" >
        <Output TaskParameter="Value" ItemName="CheckProjects_CsMissingImports"/>
    </XmlRead>
    <Error Text="Project missing CommonSettingsCs.targets: %(CheckProjects_CsMissingImports.Identity)"
                 Condition="'%(CheckProjects_CsMissingImports.Identity)' != ''" />
</Target>

Это не позволяет разработчикам забыть добавить # 1. Вы можете создать свой собственный шаблон проекта, чтобы убедиться, что все новые проекты имеют это по умолчанию.

Преимущество такого подхода заключается в том, что для создания нового набора исходного дерева не требуется ничего, кроме получения текущего исходного дерева. Недостатком является то, что вы должны редактировать файлы проекта один раз при их создании.

Ответ 3

Madgnome, вероятно, прав. Но я хотел добавить, что вы не должны редактировать файлы Microsoft.common.targets. Если вы это сделаете, вы рискуете иметь другой процесс сборки на этой машине по сравнению с тем, что есть у всех остальных. В вашем случае вы могли бы создать новый файл MSBuild с помощью только цели RealClean и поместить его на C:\Program Files (x86)\MSBuild\v4.0\Custom.After.Microsoft.Common.targets или для 32 бит C:\Program Files\MSBuild\v4.0\Custom.After.Microsoft.Common.targets и, по сути, это будет то же самое, что вставить этот файл внутри Microsoft.Common.targets, за исключением того, что вам не нужно изменять этот файл.