定制共同目标以构建解决方案

时间:2010-08-03 14:25:15

标签: msbuild projects-and-solutions target

我创建了一个自定义公共目标“RealClean”,它删除了输出和“中间输出”目录中的每个文件。我把它放在Microsoft.Common.targets文件中。 当我在我的csproj上运行MsBuild时一切都很好。 但是当我在我的sln上运行MsBuild(它只是引用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

任何提示?

3 个答案:

答案 0 :(得分:16)

我有同样的问题,但不想修改源代码树之外的东西以使其工作。将文件添加到C:\ Program Files ...意味着您必须在每台开发机器上手动执行此操作才能获得相同的行为。

我做了三件事:

1)创建了一个自定义目标文件,我将其导入到我的解决方案中的每个C#和/或VB / F#项目中,方法是在每个项目文件中添加以下内容:

<!-- 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)添加了一个干净的目标,在真正的Clean之后调用(使用MSBuild 4.0的AfterTargets属性):

<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。您可以创建自己的项目模板,以确保默认情况下新项目具有此功能。

这种方法的优点是设置新的源树登记不仅仅涉及获取当前源树。缺点是您必须在创建项目文件时编辑一次。

答案 1 :(得分:5)

要处理解决方案文件,MSBuild会创建一个临时MSBuild项目文件,其中只包含一些目标,例如构建清除。因此,您无法在解决方案文件上调用自定义目标。

答案 2 :(得分:5)

Madgnome可能是对的。但我想补充一点,你不应该编辑Microsoft.common.targets文件。如果这样做,您可能会冒险在该计算机上执行不同的构建过程,而不是其他人拥有的构建过程。在您的情况下,您可以创建一个仅包含RealClean目标的新MSBuild文件并将其放置在 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中相同,除了您不必修改该文件。