Solution1.sln包含两个项目:
- ProjectA.csproj
- ProjectB.csproj
ProjectB有一个名为“Foo”的自定义目标。我想运行:
msbuild Solution1.sln /t:Foo
这将失败,因为ProjectA没有定义“Foo”目标。
有没有办法使解决方案忽略缺少的目标?(例如,如果特定项目不存在该目标,则不执行任何操作)而不修改SLN或项目文件?
Solution1.sln包含两个项目:
ProjectB有一个名为“Foo”的自定义目标。我想运行:
msbuild Solution1.sln /t:Foo
这将失败,因为ProjectA没有定义“Foo”目标。
有没有办法使解决方案忽略缺少的目标?(例如,如果特定项目不存在该目标,则不执行任何操作)而不修改SLN或项目文件?
如果您不想编辑解决方案或项目文件,并且希望它能够从MSBuild命令行而不是从Visual Studio中工作,则有两部分的解决方案。
首先,运行以下命令时出现的错误:
MSBuild Solution1.sln /t:Foo
<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元素大部分只是从解决方案元项目的发布目标中复制而来。根据您的情况调整目标名称和其他细节。
有了这个文件,现在会出现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
在这里可以了解有关 before.Solution1.sln.targets 文件的更多信息: http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx
您可以通过项目名称来定位它们,例如/t:project:target(可能需要引号,我记不清了)。
您可以通过设置环境变量MSBuildEmitSolution = 1
来查找所有生成的目标...这会导致msbuild将生成的临时.metaproj文件保存到磁盘上,该文件中定义了所有这些目标,请打开它并查看 ;)
msbuild ProjectA.csproj
msbuild ProjectB.csproj /t:Foo
仅供参考:
在使用MSBuildTask时,请使用ContinueOnError
,或在使用(dotnet) msbuild
时使用-p:ContinueOnError=ErrorAndContinue
这可能在有限的情况下有所帮助:例如,如果您有一组.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>