MSBuild何时设置$(ProjectName)属性?

16

我对MSBuild比较陌生,我在一个WPF项目文件上进行了一些自定义操作,该项目文件会在Visual Studio 2010和TFS 2010中生成。我已按如下方式自定义了输出路径:

<OutputPath Condition=" '$(TeamBuildOutDir)' == '' ">$(SolutionDir)build\binaries\$(ProjectName)\$(Configuration)\$(Platform)</OutputPath>
<OutputPath Condition=" '$(TeamBuildOutDir)' != '' ">$(TeamBuildOutDir)binaries\$(ProjectName)\$(Configuration)\$(Platform)</OutputPath>

这使得我可以在桌面上构建到一个集中的二进制文件目录,并且在CI构建运行时,TFS可以找到这些二进制文件。

然而,在两种情况下,$(ProjectDir) 属性在构建时评估为空字符串,这会导致奇怪的结果。经过一些调试,看起来 $(ProjectName) 在 BeforeBuild 执行时已设置,但是我的 OutputPath 属性在此之前进行了评估。

<ProjectNameUsedTooEarly Condition=" '$(ProjectName)' == '' ">true</ProjectNameUsedTooEarly>

在同一属性组中,前面的属性与我的OutputPath属性相同。在BeforeBuild目标中,$(ProjectNameUsedTooEarly)会评估为true,但$(ProjectName)到那个时候会像正常一样评估为项目名称。

我应该怎么做才能确保我使用$(ProjectName)时它已经有一个值了呢?

我刚刚使用了Attrice的MSBuild Sidekick来调试我的构建文件,在第一个可用于断点的目标(_CheckForInvalidConfigurationAndPlatform)中,所有属性似乎都已经设置好了。ProjectName已经正确设置,但是我的OutputPath属性已经使用ProjectName的空值进行了设置。

1个回答

30

哦,有点混淆了,我会尝试澄清一下:

  1. 不要使用$(ProjectDir),使用$(MSBuildProjectDir) - 它是您在源代码树中的csproj位置,并由MSBuild.exe设置为保留属性。我认为在导入Microsoft.Common.Targets(这是由Microsoft.Csharp.targets执行的)之前,$(ProjectDir)是不可用的。属性评估总是在文件内部“原地”进行,而不是在所有导入完成后才进行。这可能解释了为什么您在SideKick工具中看到该属性有效。

  2. 同样,使用$(MSBuildProjectName)(我认为这将解决您的问题)

  3. 我不确定VS2010和TFS2010(因为它使用MSBuild 4.0和新的TeamBuild)如何处理,在.csproj中很难确定您的生成是从命令行/ IDE构建还是从TeamBuild中调用的。我的意思是,我不认为$(TeamBuildOutDir)在您的csproj中可用。我通常测试$(TeamBuildConstants)属性,因为当teambuild调用您的proj文件时,该属性会被传递下来。因为我还没有使用过2010,所以结果可能有所不同。


是的,你说得对——ProjectDir已经设置好了(实际上是直接从MSBuildProjectDir中设置),这是在Microsoft.Common.Targets中完成的。在我的调查中,我找到了这点。我想我的困惑可能源于我还不理解common.targets、csharp.targets、相关的csproj文件等的顺序。
  1. 我从项目属性页面的预构建宏页面中获取了ProjectName,我需要调查一下是否可以在团队构建中使用MSBuildProjectName。MSBuildProjectName来自哪里?有没有任何想法它是如何提供的?
- bwerks
1
显然,备受诟病且无效的IsDesktopBuild已被$(BuildingInsideVisualStudio)所取代,但我只是在构建日志中看到了该属性,才做出这样的假设。至于TeamBuildOutDir,你是对的——它在普通的VS构建中没有设置,因此你只能根据其存在来做出反应。我实际上是从http://blogs.msdn.com/aaronhallberg/archive/2007/06/07/preserving-output-directory-structures-in-orcas-team-build.aspx得到的这个想法。 - bwerks
3
我刚刚花了整个下午纠结于 $(ProjectName) 还没被设置,这会教训我要先去查 Stack Overflow... - James McNellis
这种解决方法对我来说可以避免一些非常丑陋的MSBuild标记。 - Reinderien
有没有不使用MSBuildXXX的时间?我刚刚尝试了它用于预构建和后构建批处理命令,但是得到了空字符串。我在这里提出了一个相关问题:https://dev59.com/etfvs4cB2Jgan1zntMbW。 - DuckMaestro
当我将一个.NET项目移植到SDK项目风格时,我遇到了类似的问题,其中我使用$(ProjectName)变量来调用外部脚本。正如已经解释的那样,问题在于Microsoft.Common.Targets在SDK风格项目的最后一行之后隐式包含。请参见https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk。显然,在老式的项目风格中,$(ProjectName)必须在属性替换之前的后期构建事件操作中的某个地方可用... - Ste

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接