Solution1.sln包含两个项目:
ProjectB有一个名为“Foo”的自定义目标。我想跑:
msbuild Solution1.sln / t:Foo
这将失败,因为ProjectA没有定义“Foo”目标。
有没有办法让解决方案忽略丢失的目标? (例如,如果特定项目不存在目标,则不执行任何操作)而不修改SLN或项目文件?
答案 0 :(得分:8)
如果您不想编辑解决方案或项目文件,可以使用两部分解决方案,并且您很高兴它可以从MSBuild命令行工作,但不能从Visual Studio工作。
首先,您运行时遇到的错误:
MSBuild Solution1.sln /t:Foo
不是ProjectA不包含Foo目标,而是解决方案本身不包含Foo目标。正如@Jaykul所建议的那样,设置MSBuildEmitSolution环境变量将揭示解决方案metaproj中包含的默认目标。
使用metaproj作为灵感,您可以在解决方案文件旁边引入一个新文件“before.Solution1.sln.targets”(文件名模式很重要),内容如下:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Foo">
<MSBuild Projects="@(ProjectReference)" Targets="Foo" BuildInParallel="True" Properties="CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)" />
</Target>
</Project>
MSBuild元素大多只是从解决方案metaproj的Publish目标中复制而来。调整目标名称和任何其他细节以适合您的方案。
使用此文件,您现在将收到ProjectA不包含Foo目标的错误。根据项目间的依赖性,ProjectB可能会也可能不会构建。
因此,其次,为了解决这个问题,我们需要为每个项目提供一个空的Foo目标,然后在实际已经包含一个项目的项目中覆盖它。
我们通过引入另一个文件来实现这一点,例如“EmptyFoo.targets”(名称并不重要),如下所示:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Foo" />
</Project>
然后我们通过运行带有额外属性的MSBuild来让每个项目自动导入此目标文件,例如:
MSBuild Solution1.sln /t:Foo /p:CustomBeforeMicrosoftCommonTargets=c:\full_path_to\EmptyFoo.targets
或者在第一个目标文件中的MSBuild元素的Properties属性中包含CustomerBeforeMicrosoftCommonTargets属性,您可以在其中选择性地指定相对于$(SolutionDir)属性的完整路径。
但是,如果您愿意将Foo与任何默认解决方案目标(即构建,重建,清理或发布)一起运行,您可以从MSBuild中的Web发布管道如何使用DeployOnBuild属性中获得一些灵感。在包含不支持发布的其他项目类型的解决方案中调用Web项目的发布目标。
有关before.Solution1.sln.targets文件的更多信息: http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx
答案 1 :(得分:2)
您可以按项目名称定位,例如/ t:project:target(可能需要引号,我无法记住)。
您可以通过设置环境变量MSBuildEmitSolution = 1
找到所有生成的目标...这会导致msbuild将为其解决方案生成的临时.metaproj文件保存到磁盘。该文件中包含了所有定义的目标,只需将其打开并查看;)
答案 2 :(得分:1)
也许不是最好的答案,而是合理的黑客攻击。
msbuild ProjectA.csproj
msbuild ProjectB.csproj /t:Foo
答案 3 :(得分:1)
当msbuild构建解决方案时 - msbuild只将有限的一组目标发送到它的.metaproj文件中,而afaik - 你无法通过构建sln文件来构建自定义目标,你必须使用原始的project1.csproj或自定义构建脚本。 / p>
答案 4 :(得分:0)
仅供参考:
使用MSBuildTask时使用ContinueOnError
或使用-p:ContinueOnError=ErrorAndContinue
时使用(dotnet) msbuild
在有限的情况下可能会有所帮助:例如,您有一个.csproj文件列表,并且只想将元数据附加到特定的项目文件项,那么您可以编写如下内容:
<Target Name="UniqueTargetName" Condition="'$(PackAsExecutable)' == 'Package' Or '$(PackAsExecutable)' == 'Publish'" Outputs="@(_Hello)">
<ItemGroup>
<_Hello Include="$(MSBuildProjectFullPath)" />
</ItemGroup>
</Target>
<Target Name="BuildEachTargetFramework" DependsOnTargets="_GetTargetFrameworksOutput;AssignProjectConfiguration;_SplitProjectReferencesByFileExistence"
Condition="$(ExecutableProjectFullPath) != ''">
<Message Text="[$(MSBuildThisFilename)] Target BuildEachTargetFramework %(_MSBuildProjectReferenceExistent.Identity)" Importance="high" />
<MSBuild
Projects="%(ProjectReferenceWithConfiguration.Identity)"
Targets="UniqueTargetName"
ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="_Hallo2" />
</MSBuild>
<Message Text="[$(MSBuildThisFilename)] ########### HELLO %(_Hallo2.Identity)" Importance="high" />
</Target>