我在我的文件OverrideBuild.targets中重写了这样的Build目标:
<Target Name="OriginalBuild" DependsOnTargets="$(BuildDependsOn)">
<Message Text="Finished running target OriginalBuild" Importance="High" />
</Target>
<Target Name="Build" >
<CheckArtifacts ProjectGuid = "$(ProjectGuid)" SolutionPath = "$(SolutionPath)" >
<Output PropertyName = "ArtifactsHaveChanged" TaskParameter = "Result" />
</CheckArtifacts>
<Message Text="ArtifactsHaveChanged = $(ArtifactsHaveChanged)" Importance="high" />
<!-- if the artifacts.props file has not just been updated then we can run the original build target -->
<Message Condition="'$(ArtifactsHaveChanged)' == 'false'" Text="Running target OriginalBuild" Importance="High" />
<CallTarget Condition="'$(ArtifactsHaveChanged)' == 'false'" Targets="OriginalBuild" />
<!-- Otherwise we need to run a new msbuild to avoid using an out-of-date cached version of the artifacts.props file.
To force the msbuild process not to use the cached values from this process we must pass at least one property.
-->
<Message Condition="'$(ArtifactsHaveChanged)' == 'true'" Text="Running target OriginalBuild in nested msbuild" Importance="High" />
<MSBuild Condition="'$(ArtifactsHaveChanged)' == 'true'" Targets="OriginalBuild"
Projects="$(MSBuildProjectFullPath)" Properties="InNestedMsbuild=true" />
<!-- Visual Studio doesn't pick up on the modified artifacts.props file unless we force it to reload the solution -->
<Touch Condition="'$(ArtifactsHaveChanged)' == 'true' and '$(BuildingInsideVisualStudio)' == 'true'" Files = "$(SolutionPath)" />
<Message Text="Finished running build target override" Importance="High" />
</Target>
我的每个.vcxproj或.csproj文件都包含此文件:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\OverrideBuild.targets" />
</Project>
这就像我想要的C ++项目一样,但是C#项目失败了。通过msbuild构建C#项目时,它会失败,因为C#编译器的命令行缺少本地程序集的引用参数。例如,一个C#文件,在文件顶部有一行这样的行:
using My.Utils.Common;
失败,并显示以下错误消息:
error CS0234: The type or namespace name 'Common' does not exist in the namespace 'My.Utils' (are you missing an assembly reference?)
查看使用的编译器命令,它缺少这一行:
/reference:C:\Code\scratch\Build\My.Utils.Common\Bin\Release\My.Utils.Common.dll
当我注释掉我对构建目标的覆盖时,存在缺少的行。奇怪的是,即使我的Build覆盖到位,它也可以在Visual Studio中构建。它仅在从命令行使用msbuild进行构建时才会失败,并且仅适用于C#项目。
我认为我覆盖Build目标的方式是完全透明的,但显然不是。任何人都可以了解出了什么问题吗?
答案 0 :(得分:1)
似乎,当项目A依赖于具有项目引用的项目B时,B的Build目标的输出将用于推断构建A时应作为引用传递给编译器的内容。 ResolveAssemblyReferences
逻辑。
因此,要使替换的Build
目标正常工作,您需要使其输出与标准Build的输出匹配。
这是您可以实现的方法:
<Target
Name="Build"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="GetTargetPathWithTargetPlatformMoniker"
Returns="@(TargetPathWithTargetPlatformMoniker)" >
</Target>
SDK中的标准Returns="@(TargetPathWithTargetPlatformMoniker)"
的{{1}}是Returns
。但是项目数组Build
最初是空的,因此您需要先运行目标@(TargetPathWithTargetPlatformMoniker)
来填充它。
这些是构建系统的实现细节,因此它们可能因SDK版本而异,但是您始终可以检查GetTargetPathWithTargetPlatformMoniker
或等效语言中的逻辑。
请注意,这不能直接用于C ++项目,它们的默认目标C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.target
有点不同。您可能需要根据项目类型而有所不同以同时支持两者。目标上的条件不会阻止它覆盖现有的条件,只会停止执行它,因此,如果您需要不同的目标覆盖,则需要将替代方案放入文件中并有条件地将其导入。我不知道有什么更方便的方法,但这至少行得通。
答案 1 :(得分:0)
为什么在msbuild中覆盖Build目标对于C ++项目有效,但对于C#项目却失败?
测试完样本后,我发现错误并非来自overriden the Build target
,它应与您引用的项目类型有关。
因为我尝试在HelloWorld项目文件中注释导入行:
<Import Project="..\..\OverrideBuild.targets" />
然后,MSBuild命令行仍然会抛出该错误。
此外,我发现您引用的项目HelloWorldHelper
是一个控制台应用程序项目,其输出类型为 Class library 。
要解决此问题,我创建了一个新的 Class库,而不是Console应用程序,然后从MSBuild命令行对其进行构建,效果很好。
因此,请尝试将您引用的项目转换为Class library
。
希望这会有所帮助。